extends SceneTree const Accrual = preload("res://scripts/economy/facility_upkeep_accrual.gd") const Settlement = preload("res://scripts/economy/facility_upkeep_settlement.gd") var checks := 0 var failures := 0 class RejectingEconomy: extends EconomyService func post(_entries: Array, _key: StringName = &"", _transaction: StringName = &"", _notify := true) -> CommandResult: return CommandResult.failed(CommandResult.Code.VALIDATION_FAILED, 0, "injected refusal") func _initialize() -> void: call_deferred("_run") func expect(value: bool, label: String) -> void: checks += 1 if not value: failures += 1 push_error(label) func _economy(cash: int) -> EconomyService: var economy := EconomyService.new({&"PLAYER_CASH": false}) if cash > 0: economy.initialize_account(&"PLAYER_CASH", cash) expect(Settlement.prepare_accounts(economy), "prepare designated expense/payable accounts") return economy func _period(start: int, units: Dictionary) -> Dictionary: return {&"period_start": start, &"period_end": (start / 1440 + 1) * 1440, &"facility_units": units} func _run() -> void: var economy := _economy(5) var service := Settlement.new() var period := _period(0, {"a": 10 * 1440, "b": 2 * 1440 + 10}) var first := service.settle(period, economy) expect(first.ok and not first.replayed, "first midnight settles") expect(economy.get_balance(Settlement.CASH) == 0, "cash cannot become negative") expect(economy.get_balance(Settlement.EXPENSE) == 12, "expense includes unpaid amount") expect(economy.get_balance(Settlement.PAYABLE) == -7, "seven gold remains payable") expect(service.get_report().arrears_by_facility == {"a": 5, "b": 2}, "insufficient funds allocate deterministically by facility ID") expect(service.get_report().fraction_units == {"b": 10}, "sub-gold expense is retained") expect(economy.has_pending_transaction_notification(first.transaction_id), "notification is deferred to outer transaction commit") expect(economy.commit_transaction_notification(first.transaction_id), "notification can be published after state commit") var guard := economy.create_snapshot() var snapshot := service.create_snapshot() var replay := service.settle(period, economy) expect(replay.ok and replay.replayed and replay.transaction_id == &"", "same settlement is idempotent and emits no notification") expect(economy.create_snapshot() == guard and service.create_snapshot() == snapshot, "replay changes neither balances nor receipts") var wrong := period.duplicate(true) wrong.facility_units.a += 1 expect(not service.settle(wrong, economy).ok and economy.create_snapshot() == guard, "changed request cannot reuse a closed period") expect(not service.settle(_period(2880, {}), economy).ok, "missing financial day rejected") # Facility a has been demolished; its debt must still be paid next midnight. economy.initialize_account(Settlement.CASH, 20, 1500, &"cash.for.next.day") var second := service.settle(_period(1440, {"b": 1430}), economy) expect(second.ok, "following day settles including prior arrears") expect(service.get_arrears_through(1439) == 0, "no historical debt before first settlement") expect(service.get_arrears_through(1440) == 7, "historical close retains its original debt after repayment") expect(service.get_arrears_through(2879) == 7, "interim query uses the last completed settlement") expect(service.get_arrears_through(2880) == 0, "repayment boundary clears current debt") expect(service.get_arrears_through(9999) == 0, "future query does not invent debt") expect(economy.get_balance(Settlement.EXPENSE) == 13, "prior debt repayment is not a new expense") expect(economy.get_balance(Settlement.CASH) == 12 and economy.get_balance(Settlement.PAYABLE) == 0, "eight gold pays debt and new fractional carry") expect(service.get_report().arrears_total == 0 and service.get_report().fraction_units.is_empty(), "debt and fractions cleared after payment") expect(service.validate_ledger(economy) and economy.validate_ledger().ok, "service and double-entry ledger reconcile") var expense_entries := 0 var payment_entries := 0 for entry: LedgerEntry in economy.get_entries(): if entry.category == &"MAINTENANCE_ACCRUAL": expense_entries += 1 expect(entry.absolute_minute in [1439, 2879], "expense belongs to the day being closed") if entry.category == &"MAINTENANCE_PAYMENT": payment_entries += 1 expect(entry.absolute_minute in [1440, 2880], "cash payment records actual midnight") expect(expense_entries == 3 and payment_entries == 3, "only positive recognized expenses and payments produce entries") var loaded_economy := EconomyService.new() expect(loaded_economy.restore_snapshot(economy.create_snapshot()), "ledger restores") var loaded := Settlement.new() expect(loaded.restore_snapshot(service.create_snapshot(), loaded_economy), "receipts restore with ledger crosschecks") expect(loaded.get_report() == service.get_report(), "derived debt/fractions rebuild exactly") var future := _period(2880, {"new": 3 * 1440}) expect(service.settle(future, economy).ok and loaded.settle(future, loaded_economy).ok, "both timelines advance") expect(service.create_snapshot() == loaded.create_snapshot() and economy.create_snapshot() == loaded_economy.create_snapshot(), "same future after reload") var valid := loaded.create_snapshot() var invalid := valid.duplicate(true) invalid.receipts[0].rows[0].new_expense += 1 expect(not loaded.restore_snapshot(invalid, loaded_economy) and loaded.create_snapshot() == valid, "forged expense rejected atomically") invalid = valid.duplicate(true) invalid.receipts[0].rows[0].paid = true expect(not loaded.restore_snapshot(invalid, loaded_economy), "boolean amount rejected") invalid = valid.duplicate(true) invalid.receipts[0].transaction_id = "missing" expect(not loaded.restore_snapshot(invalid, loaded_economy), "missing ledger transaction rejected") invalid = valid.duplicate(true) invalid.receipts[0].period.facility_units.a += 1 expect(not loaded.restore_snapshot(invalid, loaded_economy), "forged numerator and unchanged receipt rejected") invalid = valid.duplicate(true) invalid.receipts.pop_front() expect(not loaded.restore_snapshot(invalid, loaded_economy), "omitting settled debt history rejected by ledger ownership") invalid = valid.duplicate(true) invalid.version = 2 expect(not loaded.restore_snapshot(invalid, loaded_economy), "unknown save version rejected") var unrelated := _economy(100) expect(not loaded.restore_snapshot(valid, unrelated), "receipts cannot be restored onto unrelated money") var rejecting := RejectingEconomy.new({Settlement.CASH: false}) expect(Settlement.prepare_accounts(rejecting), "prepare rejecting ledger") var failed_service := Settlement.new() var before_service := failed_service.create_snapshot() var before_ledger := rejecting.create_snapshot() expect(not failed_service.settle(_period(0, {"room": 1440}), rejecting).ok, "ledger failure propagates") expect(failed_service.create_snapshot() == before_service and rejecting.create_snapshot() == before_ledger, "failed ledger post leaves all authoritative state unchanged") var empty := Settlement.new() var no_cash := _economy(0) expect(empty.settle(_period(0, {}), no_cash).ok, "empty day requires no zero-value ledger entry") var empty_loaded := Settlement.new() expect(empty_loaded.restore_snapshot(empty.create_snapshot(), no_cash), "empty settled day persists") # End-to-end cost math at completion/demolition boundaries with real ledger. var accrual := Accrual.new() accrual.start_at(360) accrual.advance_to(720, {}) accrual.advance_to(1080, {"built_at_noon": 24}) var closed: Dictionary = accrual.advance_to(1440, {}).closed_periods[0] var life := Settlement.new() var life_cash := _economy(100) expect(life.settle(closed, life_cash).ok and life_cash.get_balance(Settlement.EXPENSE) == 6, "six-hour completed ownership charges six gold after demolition") print("%s: %d checks" % ["PASS" if failures == 0 else "FAIL", checks]) quit(failures)