extends SceneTree var checks := 0 var failures := 0 func _initialize() -> void: call_deferred("_run") func expect(ok: bool, label: String) -> void: checks += 1 if not ok: failures += 1 push_error(label) func _run() -> void: var clock: Variant = load("res://autoload/game_clock.gd").new() var state: Variant = load("res://autoload/game_state.gd").new() var runtime: Variant = load("res://autoload/simulation_runtime.gd").new() clock.reset(1, 6, 0) state.reset() expect(runtime.initialize(clock, state, 424242)[&"valid"], "initialize") clock.set_paused(true) expect(runtime.enable_production_operations()[&"ok"], "enable") var definition: FacilityDefinition = runtime.definition_registry.get_facility(&"standard_room") var original_rate := definition.maintenance_gold definition.maintenance_gold = 24 expect(runtime.facility_service.create_instance({&"instance_id": &"upkeep-room", &"definition_id": &"standard_room"}).is_success(), "completed room") runtime.facility_service.set_operational_status(&"upkeep-room", {&"suspension_reason": &"DESTROYED"}, 360) clock.advance_minutes(60) expect(runtime.facility_upkeep.get_report()[&"pending_facility_units"].get("upkeep-room", 0) == 1440, "suspended room accrues one hour") runtime.facility_service.unregister_instance(&"upkeep-room") clock.advance_minutes(1019) var before: Dictionary = runtime.create_snapshot() expect(runtime.restore_snapshot(before), "23:59 save restores incurred upkeep after demolition") clock.advance_minutes(1) var summary: Dictionary = runtime.operations_coordinator.get_day_summary(1) expect(not summary.is_empty(), "midnight closes") if not summary.is_empty(): expect(summary[&"category_totals"][&"maintenance"] == 1, "one hour charged, post demolition no accrual") expect(summary[&"facility_profit_loss"].get(&"upkeep-room", {}).get(&"expenses", 0) == 1, "demolished facility expense retained") expect(runtime.economy_service.get_balance(FacilityUpkeepSettlement.EXPENSE) == 1, "expense ledger") var saved: Dictionary = runtime.create_snapshot() DirAccess.make_dir_recursive_absolute("res://artifacts/upkeep-2026-09-29") FileAccess.open("res://artifacts/upkeep-2026-09-29/preclose-snapshot.txt", FileAccess.WRITE).store_string(var_to_str(before)) FileAccess.open("res://artifacts/upkeep-2026-09-29/closed-snapshot.txt", FileAccess.WRITE).store_string(var_to_str(saved)) expect(runtime.restore_snapshot(saved), "closed upkeep save roundtrip") expect(runtime.create_snapshot() == saved, "closed snapshot exact") var panel := OperatingLedgerPanel.new() panel.setup(runtime, clock) expect(panel.get_report()[&"upkeep_cash_out"] == 1, "UI shows midnight maintenance payment") expect(panel.get_report()[&"upkeep_arrears"] == 0, "UI distinguishes unpaid balance") panel.free() var tampered := saved.duplicate(true) tampered[&"systems"][&"runtime"][&"facility_upkeep"][&"closed_periods"][0][&"facility_units"]["upkeep-room"] += 1 expect(not runtime.restore_snapshot(tampered) and runtime.create_snapshot() == saved, "receipt cannot diverge from accrued units") expect(runtime.restore_snapshot(before), "restore before unpaid close") var cash: int = runtime.economy_service.get_balance(&"PLAYER_CASH") expect(runtime.economy_service.transfer(&"PLAYER_CASH", &"CONSTRUCTION_EXPENSE", cash, 1439, &"CONSTRUCTION").is_success(), "spend cash before midnight") clock.advance_minutes(1) expect(runtime.upkeep_settlement.get_report()[&"arrears_total"] == 1, "insufficient funds retain full upkeep debt") expect(runtime.operations_coordinator.get_arrears_total() == 1, "coordinator includes upkeep debt") expect(runtime.operations_coordinator.get_day_summary(1)[&"category_totals"][&"maintenance"] == 1, "unpaid upkeep still reduces profit") var unpaid: Dictionary = runtime.create_snapshot() expect(runtime.restore_snapshot(unpaid), "unpaid close saves and restores") expect(runtime.create_snapshot() == unpaid, "unpaid close does not charge twice") # A controlled construction refund funds next-day repayment. This is a ledger # fixture, not evidence of natural sales or a normal-play balance result. expect(runtime.economy_service.transfer(&"CONSTRUCTION_EXPENSE", &"PLAYER_CASH", 2, 1440, &"CONSTRUCTION_REFUND").is_success(), "refund provides repayment funds") var funded: Dictionary = runtime.create_snapshot() expect(runtime.restore_snapshot(funded), "funded debt survives save restore") clock.advance_minutes(1439) expect(runtime.upkeep_settlement.get_arrears_total() == 1 and runtime.economy_service.get_balance(&"PLAYER_CASH") == 2, "debt awaits next midnight") var repayment_before: Dictionary = runtime.create_snapshot() expect(runtime.restore_snapshot(repayment_before), "next 23:59 restores outstanding debt") clock.advance_minutes(1) expect(not runtime.get_operations_report()[&"runtime_failure_latched"], "next-day repayment completes without failure") expect(runtime.upkeep_settlement.get_arrears_total() == 0 and runtime.operations_coordinator.get_arrears_total() == 0, "next midnight clears runtime and coordinator debt") expect(runtime.economy_service.get_balance(&"PLAYER_CASH") == 1, "old debt paid exactly once") expect(runtime.economy_service.get_balance(FacilityUpkeepSettlement.EXPENSE) == 1, "repayment does not recognize expense twice") var next_summary: Dictionary = runtime.operations_coordinator.get_day_summary(2) expect(not next_summary.is_empty() and next_summary[&"category_totals"][&"maintenance"] == 0, "next-day profit excludes prior expense repayment") var repaid: Dictionary = runtime.create_snapshot() expect(runtime.restore_snapshot(repaid) and runtime.create_snapshot() == repaid, "repaid snapshot roundtrip is exact") # Failure after posting upkeep must roll back receipts, ledger, cash and payroll. expect(runtime.restore_snapshot(before), "restore before failed close") expect(runtime.economy_service.transfer(&"PLAYER_CASH", &"CONSTRUCTION_EXPENSE", 1, 1439, &"UNKNOWN_TEST_CATEGORY").is_success(), "inject classification failure") var ledger_before: Dictionary = runtime.economy_service.create_snapshot() clock.advance_minutes(1) expect(runtime.get_operations_report()[&"runtime_failure_latched"], "failed close pauses runtime") expect(runtime.economy_service.create_snapshot() == ledger_before, "post-upkeep failure rolls ledger back exactly") expect(runtime.upkeep_settlement.get_report()[&"receipts"].is_empty(), "failed close leaves no settlement receipt") # Old saves start charging only from the restored minute. expect(runtime.restore_snapshot(before), "recover canonical preclose state") var legacy := before.duplicate(true) var data: Dictionary = legacy[&"systems"][&"runtime"] data[&"runtime_schema_version"] = 9 preload("res://tests/fixtures/pre_upkeep_runtime.gd").strip_empty_upkeep(data) expect(runtime.restore_snapshot(legacy), "genuine v9 migrates") expect(runtime.facility_upkeep.create_snapshot()[&"started_at"] == 1439, "migration starts at save minute without retroactive charge") clock.advance_minutes(1) expect(runtime.economy_service.get_balance(FacilityUpkeepSettlement.EXPENSE) == 0, "legacy save never bills pre-migration ownership") definition.maintenance_gold = original_rate runtime.free() clock.free() state.free() print("%s: %d checks" % ["PASS" if failures == 0 else "FAIL", checks]) quit(failures)