Save The Tree implementation and acceptance work in progress
Preserve production code, regression fixtures, audio assets and provenance, test infrastructure, and the original-completion plan and progress ledger. Final game and Windows acceptance remain pending; excluded local artifacts and native experiments are not part of this snapshot.
This commit is contained in:
@@ -21,6 +21,7 @@ func _run() -> void:
|
||||
legacy_open["schema_version"] = 3
|
||||
legacy_open.erase("legacy_calendar_last_day")
|
||||
legacy_open.erase("legacy_history_last_day")
|
||||
legacy_open.erase("legacy_principal_profit_last_day")
|
||||
var legacy_restored := OperationsCoordinator.new()
|
||||
_expect(legacy_restored.restore_snapshot(legacy_open), "legacy save before its first close restores")
|
||||
legacy_restored.advance_to(1500)
|
||||
@@ -56,6 +57,10 @@ func _run() -> void:
|
||||
_expect(not unpaid.is_terminal() and unpaid.get_consecutive_insolvency_count() == 0, "profitable closes with arrears never count as losses")
|
||||
_expect(not unpaid.can_start_construction_or_investment()[&"allowed"], "unpaid wages still restrict new investment separately")
|
||||
_test_legacy()
|
||||
_test_principal_financing()
|
||||
_test_principal_repayment()
|
||||
_test_principal_command()
|
||||
_test_principal_profit_marker()
|
||||
print("%s: %d checks" % ["PASS" if _failures == 0 else "FAIL", _checks])
|
||||
quit(_failures)
|
||||
|
||||
@@ -96,3 +101,163 @@ func _expect(condition: bool, message: String) -> void:
|
||||
if not condition:
|
||||
_failures += 1
|
||||
push_error(message)
|
||||
|
||||
func _test_principal_financing() -> void:
|
||||
var runtime: Variant = load("res://autoload/simulation_runtime.gd").new()
|
||||
var clock: Variant = load("res://autoload/game_clock.gd").new()
|
||||
var state: Variant = load("res://autoload/game_state.gd").new()
|
||||
clock.reset(1,6,0);state.reset()
|
||||
_expect(runtime.initialize(clock,state,1131009)[&"valid"],"principal fixture Runtime initializes")
|
||||
clock.set_paused(true)
|
||||
var before: Dictionary = runtime.create_snapshot()
|
||||
_expect(runtime.restore_snapshot(before) and var_to_bytes(before)==var_to_bytes(runtime.create_snapshot()),"no-loan current snapshot retains exact whole representation")
|
||||
var coordinator := OperationsCoordinator.new({&"start_minute":360})
|
||||
var loan := &"LOAN_LIABILITY:principal.fixture"
|
||||
_expect(runtime.economy_service.register_account(loan,true),"explicit fixture liability account")
|
||||
_expect(runtime.economy_service.transfer(loan,&"PLAYER_CASH",1000,clock.absolute_minute,&"LOAN_PRINCIPAL_BORROWED",&"principal.fixture",&"principal.borrow").is_success(),"real principal borrowed")
|
||||
_expect(runtime.economy_service.transfer(&"PLAYER_CASH",loan,400,clock.absolute_minute,&"LOAN_PRINCIPAL_REPAID",&"principal.fixture",&"principal.repay").is_success(),"real principal repayment")
|
||||
var report: Dictionary = runtime.call("_build_operations_daily_financials",360,361,0,[])
|
||||
_expect(report.get(&"ok",false),"valid principal ledger produces daily report")
|
||||
if report.get(&"ok",false):
|
||||
var totals: Dictionary = report[&"category_totals"]
|
||||
_expect(totals[&"revenue"]==0 and totals[&"cost_of_goods"]==0,"principal never enters operating sales or costs")
|
||||
_expect(totals[&"financing_principal_inflows"]==1000 and totals[&"financing_principal_outflows"]==400,"gross principal cash flows separately classified")
|
||||
_expect(report[&"facility_profit_loss"].is_empty(),"principal never allocated to facility profit")
|
||||
var normal: Dictionary = coordinator.call("_normalize_categories",totals)
|
||||
_expect(normal.get(&"ok",false) and normal[&"categories"]==totals,"Operations and Runtime retain identical financing categories")
|
||||
_expect(coordinator.call("_net_profit",normal[&"categories"])==-400,"original debt repayment counts as daily expense while borrowing remains outside sales")
|
||||
var expected: Variant = runtime.call("_operations_expected_category_totals",runtime.economy_service,360,361,0)
|
||||
_expect(expected==totals,"restore recomputes same full category totals")
|
||||
coordinator.configure_callbacks(func(payload: Dictionary, phase: StringName, token: Variant) -> Dictionary:
|
||||
if phase != &"apply":return {&"ok":true,&"token":token}
|
||||
var close: Dictionary = runtime.call("_build_operations_daily_financials",int(payload[&"period_start_minute"]),int(payload[&"period_end_minute_exclusive"]),0,[])
|
||||
close[&"settlement"]={&"arrears_total":0}
|
||||
return close)
|
||||
_expect(coordinator.advance_to(4320).is_success(),"three calendar days close with actual principal ledger")
|
||||
_expect(coordinator.get_day_summaries().size()==3,"three actual daily financing reports retained")
|
||||
var first: Dictionary = coordinator.get_day_summary(1)
|
||||
_expect(first[&"category_totals"][&"financing_principal_inflows"]==1000 and first[&"category_totals"][&"financing_principal_outflows"]==400 and first[&"net_profit"]==-400,"actual repayment reduces daily profit at the real day boundary")
|
||||
_expect(not coordinator.get_day_summary(2)[&"category_totals"].has(&"financing_principal_inflows") and coordinator.get_day_summary(2)[&"net_profit"]==0,"no-loan following day preserves old shape and profit")
|
||||
var days: Dictionary = coordinator.create_snapshot()
|
||||
var restored_days := OperationsCoordinator.new()
|
||||
_expect(restored_days.restore_snapshot(days) and var_to_bytes(restored_days.create_snapshot())==var_to_bytes(days),"whole three-day financing history restores byte-exact")
|
||||
var saved: Dictionary = runtime.create_snapshot()
|
||||
_expect(runtime.restore_snapshot(saved) and var_to_bytes(saved)==var_to_bytes(runtime.create_snapshot()),"whole principal snapshot restores exactly")
|
||||
var duplicate: CommandResult = runtime.economy_service.transfer(loan,&"PLAYER_CASH",1000,clock.absolute_minute,&"LOAN_PRINCIPAL_BORROWED",&"principal.fixture",&"principal.borrow")
|
||||
_expect(not duplicate.is_success() and var_to_bytes(saved)==var_to_bytes(runtime.create_snapshot()),"principal duplicate after restore remains whole state noop")
|
||||
var old_categories := {&"revenue":0,&"refunds":0,&"cost_of_goods":0,&"wages":0,&"maintenance":0,&"utilities":0,&"taxes_and_interest":0,&"fines":0,&"construction_cash_flow":0}
|
||||
var legacy: Dictionary = coordinator.call("_normalize_categories",old_categories)
|
||||
_expect(legacy[&"ok"] and var_to_bytes(legacy[&"categories"])==var_to_bytes(old_categories),"old categories retain exact shape without invented financing zeros")
|
||||
var bad := old_categories.duplicate(true);bad[&"mystery_financing"]=1
|
||||
_expect(not coordinator.call("_normalize_categories",bad)[&"ok"],"unclassified finance categories still reject")
|
||||
for value: Variant in [-1,"1000",OperationsCoordinator.MAX_FINANCIAL_AMOUNT+1]:
|
||||
bad=old_categories.duplicate(true);bad[&"financing_principal_inflows"]=value
|
||||
_expect(not coordinator.call("_normalize_categories",bad)[&"ok"],"invalid principal total rejects")
|
||||
var corrupt := EconomyService.new()
|
||||
_expect(corrupt.restore_snapshot(runtime.economy_service.create_snapshot()),"corruption fixture actual full economy")
|
||||
_expect(corrupt.transfer(loan,&"PLAYER_CASH",1,clock.absolute_minute,&"TRANSFER",&"principal.fixture",&"principal.unattested").is_success(),"explicit unattributed liability movement fixture")
|
||||
var altered := saved.duplicate(true)
|
||||
altered[&"systems"][&"runtime"][&"economy"]=corrupt.create_snapshot()
|
||||
altered[&"game_state"][&"resources"][&"gold"]=5601
|
||||
_expect(not runtime.restore_snapshot(altered) and var_to_bytes(saved)==var_to_bytes(runtime.create_snapshot()),"unattested liability movement rejects whole Runtime restore atomically")
|
||||
_expect(runtime.economy_service.get_balance(&"PLAYER_CASH")==5600 and runtime.economy_service.get_balance(loan)==-600,"exact remaining principal and cash")
|
||||
runtime.free();clock.free();state.free()
|
||||
|
||||
func _test_principal_repayment() -> void:
|
||||
var runtime: Variant = load("res://autoload/simulation_runtime.gd").new()
|
||||
var clock: Variant = load("res://autoload/game_clock.gd").new()
|
||||
var state: Variant = load("res://autoload/game_state.gd").new()
|
||||
clock.reset(1,6,0);state.reset()
|
||||
_expect(runtime.initialize(clock,state,1161009)[&"valid"],"repayment Runtime initializes")
|
||||
clock.set_paused(true)
|
||||
runtime.configure_save_policy({&"enabled":false,&"daily_checkpoint_enabled":false})
|
||||
var loan := &"LOAN_LIABILITY:repayment.fixture"
|
||||
_expect(runtime.economy_service.register_account(loan,true),"explicit existing fixture liability")
|
||||
_expect(runtime.economy_service.transfer(loan,&"PLAYER_CASH",1000,clock.absolute_minute,&"LOAN_PRINCIPAL_BORROWED",&"repayment.fixture",&"repayment.borrow").is_success(),"fixture principal borrowed in real ledger")
|
||||
var receipts: Array[Dictionary]=[]
|
||||
runtime.economy_service.transaction_posted.connect(func(id: StringName,_entries: Array) -> void:
|
||||
receipts.append({&"id":id,&"cash":runtime.economy_service.get_balance(&"PLAYER_CASH"),&"gold":state.get_resource(&"gold")}))
|
||||
for amount: Variant in [0,-1,1.5,"400",1001,OperationsCoordinator.MAX_FINANCIAL_AMOUNT+1]:
|
||||
var before: Dictionary=runtime.create_snapshot()
|
||||
_expect(not runtime.repay_loan_principal(&"repayment.fixture",amount,StringName("bad."+str(_checks))).is_success(),"invalid or excessive principal payment rejects")
|
||||
_expect(var_to_bytes(before)==var_to_bytes(runtime.create_snapshot()) and receipts.is_empty(),"rejected principal preserves whole state and notifications")
|
||||
var result: CommandResult=runtime.repay_loan_principal(&"repayment.fixture",400,&"repayment.first")
|
||||
_expect(result.is_success() and result.details[&"paid_principal"]==400 and result.details[&"outstanding_principal"]==600,"public partial repayment reports exact remaining principal")
|
||||
_expect(receipts.size()==1 and receipts[0][&"cash"]==5600 and receipts[0][&"gold"]==5600,"receipt sees committed principal and synchronized Gold")
|
||||
var saved: Dictionary=runtime.create_snapshot()
|
||||
_expect(not runtime.repay_loan_principal(&"repayment.fixture",400,&"repayment.first").is_success() and var_to_bytes(saved)==var_to_bytes(runtime.create_snapshot()) and receipts.size()==1,"principal replay is whole-state and receipt noop")
|
||||
_expect(runtime.restore_snapshot(saved) and var_to_bytes(saved)==var_to_bytes(runtime.create_snapshot()),"whole paid principal snapshot restores exact")
|
||||
_expect(not runtime.repay_loan_principal(&"repayment.fixture",400,&"repayment.first").is_success() and var_to_bytes(saved)==var_to_bytes(runtime.create_snapshot()),"restored payment key cannot charge twice")
|
||||
runtime.economy_service.begin_notification_scope()
|
||||
_expect(runtime.repay_loan_principal(&"repayment.fixture",600,&"repayment.final").is_success() and state.get_resource(&"gold")==5000,"nested final payment commits whole principal and Gold before receipt")
|
||||
runtime.economy_service.end_notification_scope()
|
||||
_expect(runtime.economy_service.get_balance(&"PLAYER_CASH")==5000 and runtime.economy_service.get_balance(loan)==0,"public final repayment extinguishes only the actual principal")
|
||||
var completed: Dictionary=runtime.create_snapshot()
|
||||
_expect(not runtime.repay_loan_principal(&"repayment.fixture",1,&"repayment.extra").is_success() and var_to_bytes(completed)==var_to_bytes(runtime.create_snapshot()),"extinguished principal cannot be overpaid")
|
||||
var report: Dictionary=runtime.call("_build_operations_daily_financials",360,361,0,[])
|
||||
_expect(report[&"ok"] and report[&"category_totals"][&"financing_principal_inflows"]==1000 and report[&"category_totals"][&"financing_principal_outflows"]==1000 and report[&"category_totals"][&"revenue"]==0 and report[&"category_totals"][&"cost_of_goods"]==0,"public repayment stays financing in actual daily report")
|
||||
runtime.free();clock.free();state.free()
|
||||
|
||||
func _test_principal_command() -> void:
|
||||
var runtime: Variant=load("res://autoload/simulation_runtime.gd").new()
|
||||
var clock: Variant=load("res://autoload/game_clock.gd").new()
|
||||
var state: Variant=load("res://autoload/game_state.gd").new()
|
||||
clock.reset(1,6,0);state.reset()
|
||||
_expect(runtime.initialize(clock,state,1191009)[&"valid"],"principal command Runtime initializes")
|
||||
clock.set_paused(true);runtime.configure_save_policy({&"enabled":false,&"daily_checkpoint_enabled":false})
|
||||
var id:=&"principal.command.fixture";var account:=&"LOAN_LIABILITY:principal.command.fixture"
|
||||
_expect(runtime.economy_service.register_account(account,true),"explicit command fixture liability")
|
||||
_expect(runtime.economy_service.transfer(account,&"PLAYER_CASH",1000,clock.absolute_minute,&"LOAN_PRINCIPAL_BORROWED",id,&"command.fixture.borrow").is_success(),"actual command fixture debt")
|
||||
var result: CommandResult=runtime.submit_command(&"repay_loan_principal",{&"loan_id":id,&"amount":400},&"player",id,0,-1,&"command.fixture.first")
|
||||
_expect(result.is_success() and result.command_id>0 and result.target_id==id and result.details[&"outstanding_principal"]==600,"ordinary paused command reports actual payment and target")
|
||||
_expect(runtime.economy_service.get_balance(&"PLAYER_CASH")==5600 and runtime.economy_service.get_balance(account)==-600 and state.get_resource(&"gold")==5600,"ordinary command commits exact principal and Gold")
|
||||
var bad_payloads: Array[Dictionary]=[{},{&"loan_id":123,&"amount":1},{&"loan_id":id,&"amount":1.5},{&"loan_id":id,&"amount":601},{&"loan_id":id,&"amount":1}]
|
||||
for i in range(bad_payloads.size()):
|
||||
var before: Dictionary=runtime.economy_service.create_snapshot();var gold: int=state.get_resource(&"gold")
|
||||
var key:=StringName("command.bad."+str(i)) if i<4 else &""
|
||||
result=runtime.submit_command(&"repay_loan_principal",bad_payloads[i],&"player",id,0,-1,key)
|
||||
_expect(not result.is_success(),"invalid principal command rejects without permissive conversion")
|
||||
_expect(var_to_bytes(before)==var_to_bytes(runtime.economy_service.create_snapshot()) and state.get_resource(&"gold")==gold,"failed command keeps exact financial state")
|
||||
var before: Dictionary=runtime.create_snapshot()
|
||||
_expect(runtime.submit_command(&"repay_loan_principal",{&"loan_id":id,&"amount":400},&"player",id,0,-1,&"command.fixture.first").code==CommandResult.Code.DUPLICATE_IDEMPOTENCY_KEY,"ordinary processed command key cannot repay twice")
|
||||
_expect(var_to_bytes(before)==var_to_bytes(runtime.create_snapshot()),"duplicate command preserves entire Runtime")
|
||||
var due: int=clock.absolute_minute+2
|
||||
_expect(runtime.submit_command(&"repay_loan_principal",{"loan_id":String(id),"amount":200},&"player",id,0,due,&"command.fixture.future").is_success(),"future principal command accepts serialized string payload")
|
||||
_expect(runtime.economy_service.get_balance(&"PLAYER_CASH")==5600,"future command has no early payment")
|
||||
var pending: Dictionary=runtime.create_snapshot();clock.advance_minutes(2)
|
||||
_expect(runtime.command_queue.get_result_by_idempotency_key(&"command.fixture.future").is_success() and runtime.economy_service.get_balance(account)==-400,"future command pays once through clock tick")
|
||||
var tx: StringName=runtime.economy_service.get_transaction_id_for_idempotency_key(&"command.fixture.future")
|
||||
var entries: Array=runtime.economy_service.get_transaction_entries(tx)
|
||||
_expect(entries.size()==1 and entries[0].absolute_minute==due,"principal ledger uses actual future execution minute")
|
||||
var continued: Dictionary=runtime.create_snapshot()
|
||||
_expect(runtime.restore_snapshot(pending) and var_to_bytes(pending)==var_to_bytes(runtime.create_snapshot()),"pending principal command restores exact")
|
||||
clock.advance_minutes(2)
|
||||
_expect(var_to_bytes(continued)==var_to_bytes(runtime.create_snapshot()),"pending principal command continuation equals original whole state")
|
||||
before=runtime.create_snapshot()
|
||||
_expect(runtime.submit_command(&"repay_loan_principal",{&"loan_id":id,&"amount":200},&"player",id,0,-1,&"command.fixture.future").code==CommandResult.Code.DUPLICATE_IDEMPOTENCY_KEY,"restored command key rejects repeat")
|
||||
_expect(var_to_bytes(before)==var_to_bytes(runtime.create_snapshot()),"restored duplicate preserves entire Runtime")
|
||||
_expect(runtime.submit_command(&"repay_loan_principal",{&"loan_id":id,&"amount":400},&"player",id,0,-1,&"command.fixture.final").is_success(),"queued remaining principal fully repays")
|
||||
_expect(runtime.economy_service.get_balance(&"PLAYER_CASH")==5000 and runtime.economy_service.get_balance(account)==0 and state.get_resource(&"gold")==5000,"queued final payment conserves exact initial cash")
|
||||
runtime.free();clock.free();state.free()
|
||||
|
||||
func _test_principal_profit_marker() -> void:
|
||||
var service := OperationsCoordinator.new()
|
||||
service.configure_callbacks(func(payload: Dictionary, phase: StringName, token: Variant) -> Dictionary:
|
||||
if phase != &"apply": return {&"ok": true, &"token": token}
|
||||
return {&"ok": true, &"category_totals": {&"financing_principal_outflows": 500}, &"facility_profit_loss": {}, &"anomalies": [], &"reconciliation_difference": 0, &"settlement": {&"arrears_total": 0}})
|
||||
_expect(service.advance_to(5000).is_success(), "principal expense closes through terminal boundary")
|
||||
_expect(service.current_minute == 4320 and service.is_terminal(), "three principal expenses stop at third midnight")
|
||||
for day in range(1, 4):
|
||||
var summary := service.get_day_summary(day)
|
||||
_expect(summary[&"net_profit"] == -500 and summary[&"consecutive_insolvency_count"] == day, "principal expense determines original daily profit and loss streak")
|
||||
var saved := service.create_snapshot()
|
||||
_expect(saved["schema_version"] == 5 and saved["legacy_principal_profit_last_day"] == 0, "new history uses explicit original profit basis")
|
||||
var restored := OperationsCoordinator.new()
|
||||
_expect(restored.restore_snapshot(saved) and restored.create_snapshot() == saved, "current original-profit terminal history restores exactly")
|
||||
for value: Variant in [-1, 4, 0.5, "0", null]:
|
||||
var bad := saved.duplicate(true)
|
||||
bad["legacy_principal_profit_last_day"] = value
|
||||
_expect(not restored.restore_snapshot(bad) and restored.create_snapshot() == saved, "invalid principal history marker rejects atomically")
|
||||
var missing := saved.duplicate(true)
|
||||
missing.erase("legacy_principal_profit_last_day")
|
||||
_expect(not restored.restore_snapshot(missing) and restored.create_snapshot() == saved, "missing current marker rejects atomically")
|
||||
|
||||
Reference in New Issue
Block a user