class_name FacilityCleaningPolicy extends RefCounted ## Approved trial values live in data, never in scheduler defaults. var last_error := "" var _values: Dictionary = {} func load_file(path: String = "res://data/environment/cleaning_policy.json") -> bool: var parsed: Variant = JSON.parse_string(FileAccess.get_file_as_string(path)) if not parsed is Dictionary: last_error = "Cleaning policy must be a JSON object" return false return configure(parsed) func configure(values: Dictionary) -> bool: var keys := ["schema_version", "initial_cleanliness", "maximum_cleanliness", "clean_at_or_below", "work_minutes", "recovery_per_completed_task"] if values.size() != keys.size(): last_error = "Unexpected cleaning policy fields" return false var candidate: Dictionary = {} for key: String in keys: var value: Variant = values.get(key) # JSON numbers arrive as floats; accept only finite exact small integers. if typeof(value) not in [TYPE_INT, TYPE_FLOAT] or not is_finite(float(value)) or float(value) != floor(float(value)) or float(value) < 0 or float(value) > 2147483647: last_error = "Invalid cleaning policy integer: " + key return false candidate[key] = int(value) if candidate["schema_version"] != 1 or candidate["maximum_cleanliness"] <= 0 or candidate["initial_cleanliness"] > candidate["maximum_cleanliness"] or candidate["clean_at_or_below"] >= candidate["maximum_cleanliness"] or candidate["work_minutes"] <= 0 or candidate["recovery_per_completed_task"] <= 0: last_error = "Invalid cleaning policy bounds" return false _values = candidate last_error = "" return true func create_snapshot() -> Dictionary: return _values.duplicate(true)