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.
463 lines
34 KiB
GDScript
463 lines
34 KiB
GDScript
extends SceneTree
|
|
|
|
## Source-only candidate. UNKNOWN native result/UID. Public paid warehouse and
|
|
## normal command/UI paths; Mimi is a disclosed public registration fixture,
|
|
## OFF_DUTY with existing Staff defaults/porter role, not a natural join/catalog.
|
|
## Economy notification rejection below is an explicit subclass failure fixture.
|
|
const Quote = preload("res://scripts/supply/supply_purchase_quote_v2.gd")
|
|
const SupplyManagementPanel = preload("res://scripts/ui/supply_management_panel.gd")
|
|
class RejectingNotificationEconomy:
|
|
extends EconomyService
|
|
func commit_transaction_notification(_transaction: StringName) -> bool: return false
|
|
|
|
class PlacementRuntimeView:
|
|
extends RefCounted
|
|
var staff_service: StaffService
|
|
var facility_service: Variant
|
|
class MissingFacilityView:
|
|
extends RefCounted
|
|
func get_instance(_id: StringName) -> FacilityInstance: return null
|
|
|
|
var runtime: Variant
|
|
var clock: Variant
|
|
var state: Variant
|
|
var warehouse: StringName
|
|
var built: Dictionary
|
|
var with_mimi: Dictionary
|
|
var checks := 0
|
|
var failures := 0
|
|
var output := ""
|
|
var written_proofs: Array[String] = []
|
|
|
|
func _initialize() -> void: call_deferred("_run")
|
|
|
|
func _run() -> void:
|
|
output = "user://tests/mimi_purchase_quote_%d" % OS.get_process_id()
|
|
expect(DirAccess.make_dir_recursive_absolute(ProjectSettings.globalize_path(output)) == OK, "fresh PID proof namespace")
|
|
runtime = root.get_node("SimulationRuntime")
|
|
clock = root.get_node("GameClock")
|
|
state = root.get_node("GameState")
|
|
clock.set_process(false)
|
|
clock.reset(1, 6, 0)
|
|
state.reset() # production default5000; no free building, wages or price subsidy
|
|
expect(runtime.initialize(clock, state, 421705)[&"valid"], "normal default-funding Runtime initializes")
|
|
clock.set_paused(true)
|
|
runtime.configure_save_policy({&"enabled": false, &"daily_checkpoint_enabled": false})
|
|
expect(runtime.submit_command(&"build_facility", {&"definition_id": &"warehouse", &"origin": Vector3i(-8, 0, 1)}).is_success(), "ordinary paid warehouse construction")
|
|
clock.advance_minutes(180)
|
|
for facility: FacilityInstance in runtime.facility_service.get_instances():
|
|
if facility.definition_id == &"warehouse": warehouse = facility.instance_id
|
|
expect(not warehouse.is_empty(), "real complete warehouse ID")
|
|
if warehouse.is_empty(): finish(); return
|
|
built = runtime.create_snapshot()
|
|
codec_cases()
|
|
expect(runtime.preview_supply_purchase(warehouse, SupplyCatalog.RAW_FOOD, 5)[&"total_cost"] == 15, "ordinary current3G prototype branch unchanged before Mimi")
|
|
expect(built[&"systems"][&"runtime"][&"runtime_schema_version"] == 14, "v1-only capture stays exact14")
|
|
var mimi := StaffRuntime.new().configure(Quote.MIMI, &"porter", {&"employment_kind": StaffRuntime.EmploymentKind.UNIQUE})
|
|
expect(runtime.staff_service.register_staff(mimi).is_success(), "controlled public UNIQUE fixture registration; natural join unaccepted")
|
|
expect(not runtime.staff_service.register_staff(mimi).is_success(), "same UNIQUE ID cannot register twice")
|
|
with_mimi = runtime.create_snapshot()
|
|
expect(with_mimi[&"systems"][&"runtime"][&"runtime_schema_version"] == 14, "presence/read-only preview alone does not invent v2 history")
|
|
placement_cases()
|
|
with_mimi = runtime.create_snapshot()
|
|
var before: Dictionary = runtime.create_snapshot()
|
|
var preview: Dictionary = runtime.preview_supply_purchase(warehouse, SupplyCatalog.RAW_FOOD, 5)
|
|
expect(preview[&"total_cost"] == 12 and preview[&"purchase_quote"][&"base_total"] == 15, "8000bp applies once to total15G yielding12G")
|
|
expect(var_to_bytes(before) == var_to_bytes(runtime.create_snapshot()), "public preview preserves all Runtime fields/types/RNG/journals")
|
|
proof("preview-before", before)
|
|
proof("preview-after", runtime.create_snapshot())
|
|
await manual_ui_and_formal()
|
|
automatic_and_failures()
|
|
finish()
|
|
|
|
func placement_cases() -> void:
|
|
var unplaced: Dictionary = runtime.create_snapshot()
|
|
var ordinary: Dictionary = runtime.preview_supply_purchase(warehouse, SupplyCatalog.RAW_FOOD, 5)
|
|
expect(not Quote.eligible(runtime) and ordinary[&"total_cost"] == 15 and not ordinary.has(&"purchase_quote"), "registered unplaced UNIQUE stays original v1 quote15G")
|
|
expect(var_to_bytes(runtime.create_snapshot()) == var_to_bytes(unplaced), "unplaced preview/eligibility never repairs or mutates placement")
|
|
proof("registered-unplaced", unplaced)
|
|
v1_placement_boundary("unplaced")
|
|
var assigned: CommandResult = runtime.submit_command(&"set_staff_work_assignment", {&"staff_id": Quote.MIMI, &"facility_id": warehouse, &"template_id": &"NIGHT"})
|
|
expect(assigned.is_success(), "normal public NIGHT assignment validates real warehouse/role/cap/path")
|
|
var worker: StaffRuntime = runtime.staff_service.get_staff(Quote.MIMI)
|
|
expect(worker.state == StaffRuntime.State.OFF_DUTY and runtime.staff_service.get_work_assignment(Quote.MIMI)[&"template_id"] == "NIGHT" and Quote.eligible(runtime), "persistent NIGHT placement passive works OFF_DUTY without attendance multiplier")
|
|
var placed: Dictionary = runtime.create_snapshot()
|
|
expect(runtime.preview_supply_purchase(warehouse, SupplyCatalog.RAW_FOOD, 5)[&"total_cost"] == 12 and var_to_bytes(runtime.create_snapshot()) == var_to_bytes(placed), "placed public quote12G is read-only")
|
|
proof("night-placed", placed)
|
|
var view := PlacementRuntimeView.new()
|
|
view.staff_service = runtime.staff_service; view.facility_service = MissingFacilityView.new()
|
|
expect(not Quote.eligible(view), "controlled read-only missing facility view refuses a present plan reference")
|
|
expect(var_to_bytes(runtime.create_snapshot()) == var_to_bytes(placed), "missing-reference predicate does not repair real Runtime")
|
|
var legacy := StaffService.new()
|
|
var fallback := StaffRuntime.new().configure(Quote.MIMI, &"porter", {&"employment_kind": StaffRuntime.EmploymentKind.UNIQUE, &"assigned_facility_id": warehouse})
|
|
expect(legacy.register_staff(fallback).is_success(), "controlled public component legacy placement fixture")
|
|
view.staff_service = legacy; view.facility_service = runtime.facility_service
|
|
var legacy_before := legacy.create_snapshot()
|
|
expect(legacy.get_work_assignment(Quote.MIMI).is_empty() and Quote.eligible(view), "legacy assigned field applies only with no repeating plan")
|
|
expect(var_to_bytes(legacy.create_snapshot()) == var_to_bytes(legacy_before), "legacy eligibility leaves every staff field/type unchanged")
|
|
expect(legacy.set_work_assignment(Quote.MIMI, &"", &"NIGHT", clock.absolute_minute).is_success(), "controlled component explicit empty repeating plan")
|
|
var empty_before := legacy.create_snapshot()
|
|
expect(not Quote.eligible(view) and var_to_bytes(legacy.create_snapshot()) == var_to_bytes(empty_before), "present empty plan cannot fall back or mutate fields")
|
|
# A stale live field is a disclosed getter view, never injected into Runtime.
|
|
var explicit_view := ExplicitPlanStaffView.new()
|
|
explicit_view.worker = StaffRuntime.new().configure(Quote.MIMI, &"porter", {&"employment_kind": StaffRuntime.EmploymentKind.UNIQUE, &"assigned_facility_id": warehouse})
|
|
explicit_view.plan = {&"facility_id": ""}
|
|
var exact_view := FlexiblePlacementRuntimeView.new()
|
|
exact_view.staff_service = explicit_view; exact_view.facility_service = runtime.facility_service
|
|
var view_before := explicit_view.worker.create_snapshot()
|
|
expect(not Quote.eligible(exact_view) and var_to_bytes(explicit_view.worker.create_snapshot()) == var_to_bytes(view_before), "controlled getter empty plan overrides stale live assignment read-only")
|
|
explicit_view.plan = {&"facility_id": "missing.mimi.fixture"}
|
|
expect(not Quote.eligible(exact_view) and var_to_bytes(explicit_view.worker.create_snapshot()) == var_to_bytes(view_before), "controlled getter missing-reference plan never revives legacy assignment")
|
|
expect(runtime.submit_command(&"set_staff_work_assignment", {&"staff_id": Quote.MIMI, &"facility_id": &"", &"template_id": &"NIGHT"}).is_success(), "normal public explicit clear keeps original paid/assignment contract")
|
|
var cleared: Dictionary = runtime.create_snapshot()
|
|
ordinary = runtime.preview_supply_purchase(warehouse, SupplyCatalog.RAW_FOOD, 5)
|
|
expect(not Quote.eligible(runtime) and ordinary[&"total_cost"] == 15 and not ordinary.has(&"purchase_quote") and var_to_bytes(runtime.create_snapshot()) == var_to_bytes(cleared), "public clear yields unchanged read-only v1 quote15G")
|
|
proof("cleared-before-v2", cleared)
|
|
v1_placement_boundary("cleared")
|
|
expect(runtime.submit_command(&"set_staff_work_assignment", {&"staff_id": Quote.MIMI, &"facility_id": warehouse, &"template_id": &"NIGHT"}).is_success(), "public re-placement restores original downstream discounted fixture")
|
|
expect(runtime.staff_service.get_staff(Quote.MIMI).state == StaffRuntime.State.OFF_DUTY and Quote.eligible(runtime), "NIGHT re-placement remains nonattendance passive")
|
|
|
|
class ExplicitPlanStaffView:
|
|
extends RefCounted
|
|
var worker: StaffRuntime
|
|
var plan: Dictionary
|
|
func get_staff(_id: StringName) -> StaffRuntime: return worker
|
|
func get_work_assignment(_id: StringName) -> Dictionary: return plan.duplicate(true)
|
|
class FlexiblePlacementRuntimeView:
|
|
extends RefCounted
|
|
var staff_service: Variant
|
|
var facility_service: Variant
|
|
|
|
func v1_placement_boundary(label: String) -> void:
|
|
var before: Dictionary = runtime.create_snapshot()
|
|
var cash: int = runtime.economy_service.get_balance(&"PLAYER_CASH")
|
|
var quantity: int = stock()
|
|
var result: CommandResult = runtime.submit_command(&"purchase_supplies", {&"warehouse_id": warehouse, &"item_id": SupplyCatalog.RAW_FOOD, &"quantity": 1})
|
|
expect(result.is_success() and not result.details.has(&"purchase_quote") and stock() == quantity + 1 and runtime.economy_service.get_balance(&"PLAYER_CASH") == cash - 3, "actual unplaced/cleared v1 order pays original3G " + label)
|
|
expect(runtime.create_snapshot()[&"systems"][&"runtime"][&"runtime_schema_version"] == 14, "no v2 history/version from actual v1 purchase " + label)
|
|
proof("placement-v1-" + label + "-result", result.to_dictionary())
|
|
proof("placement-v1-" + label + "-live", runtime.create_snapshot())
|
|
expect(runtime.restore_snapshot(before) and var_to_bytes(runtime.create_snapshot()) == var_to_bytes(before), "controlled fulltyped branch reset keeps downstream original assertions " + label)
|
|
|
|
func frozen_after_clear(paid: Dictionary, label: String) -> void:
|
|
var before_inventory: Dictionary = runtime.inventory_service.create_snapshot()
|
|
var before_economy: Dictionary = runtime.economy_service.create_snapshot()
|
|
var before_plans: Dictionary = runtime.auto_purchase_plans.create_snapshot()
|
|
var processed: Array = (paid[&"systems"][&"runtime"][&"command_queue"]["processed"] as Array).duplicate(true)
|
|
expect(runtime.submit_command(&"set_staff_work_assignment", {&"staff_id": Quote.MIMI, &"facility_id": &"", &"template_id": &"NIGHT"}).is_success(), "public clear after actual frozen order " + label)
|
|
var cleared: Dictionary = runtime.create_snapshot()
|
|
var ordinary: Dictionary = runtime.preview_supply_purchase(warehouse, SupplyCatalog.RAW_FOOD, 5)
|
|
expect(not Quote.eligible(runtime) and ordinary[&"total_cost"] == 15 and not ordinary.has(&"purchase_quote"), "new order after clear is v1 without repricing prior v2 " + label)
|
|
for previous: Dictionary in processed:
|
|
var actual: CommandResult = runtime.command_queue.get_processed_result(int(previous["command_id"]))
|
|
expect(actual != null and var_to_bytes(actual.to_dictionary()) == var_to_bytes(previous), "all original processed frozen results unchanged after clear " + label)
|
|
expect(var_to_bytes(runtime.inventory_service.create_snapshot()) == var_to_bytes(before_inventory) and var_to_bytes(runtime.economy_service.create_snapshot()) == var_to_bytes(before_economy) and var_to_bytes(runtime.auto_purchase_plans.create_snapshot()) == var_to_bytes(before_plans), "clear preserves all inventory/economy/frozen plan fields " + label)
|
|
expect(cleared[&"systems"][&"runtime"][&"runtime_schema_version"] == 15 and runtime.restore_snapshot(cleared) and var_to_bytes(runtime.create_snapshot()) == var_to_bytes(cleared), "v2 history stays strict15 while current placement is empty " + label)
|
|
proof("frozen-clear-" + label + "-live", runtime.create_snapshot())
|
|
var cash: int = runtime.economy_service.get_balance(&"PLAYER_CASH")
|
|
var quantity: int = stock()
|
|
var ordinary_paid: CommandResult = runtime.submit_command(&"purchase_supplies", {&"warehouse_id": warehouse, &"item_id": SupplyCatalog.RAW_FOOD, &"quantity": 1})
|
|
expect(ordinary_paid.is_success() and not ordinary_paid.details.has(&"purchase_quote") and stock() == quantity + 1 and runtime.economy_service.get_balance(&"PLAYER_CASH") == cash - 3, "actual v1 order after clear coexists with immutable v2 history " + label)
|
|
expect(runtime.create_snapshot()[&"systems"][&"runtime"][&"runtime_schema_version"] == 15, "later v1 never downgrades retained prior v2 history " + label)
|
|
proof("frozen-clear-" + label + "-ordinary-result", ordinary_paid.to_dictionary())
|
|
proof("frozen-clear-" + label + "-ordinary-live", runtime.create_snapshot())
|
|
expect(runtime.restore_snapshot(paid) and var_to_bytes(runtime.create_snapshot()) == var_to_bytes(paid), "controlled fulltyped original paid branch reset " + label)
|
|
|
|
func codec_cases() -> void:
|
|
for row: Array in [[1, 2], [3, 7], [4, 10], [5, 12], [6, 14], [100, 240]]:
|
|
var quote: Dictionary = Quote.make(SupplyCatalog.RAW_FOOD, row[0], 3)
|
|
expect(quote[&"effective_total"] == row[1] and Quote.valid(quote), "existing total-order integer half-up rule quantity%d" % row[0])
|
|
expect(var_to_bytes(Quote.decode_receipt_memo(Quote.receipt_memo(quote))) == var_to_bytes(quote), "full typed frozen quote memo roundtrip%d" % row[0])
|
|
var original: Dictionary = Quote.make(SupplyCatalog.RAW_FOOD, 5, 3)
|
|
for field: StringName in Quote.KEYS:
|
|
var corrupt := original.duplicate(true)
|
|
corrupt.erase(field)
|
|
expect(not Quote.valid(corrupt), "missing quote field rejected: " + String(field))
|
|
for field: StringName in [&"quantity", &"base_unit_price", &"base_total", &"multiplier_bp", &"effective_total"]:
|
|
var corrupt := original.duplicate(true)
|
|
corrupt[field] = float(corrupt[field])
|
|
expect(not Quote.valid(corrupt), "float charge field cannot be normalized: " + String(field))
|
|
for patch: Dictionary in [{&"quantity": 4}, {&"base_total": 14}, {&"effective_total": 10}, {&"multiplier_bp": 7999}, {&"applied_unique_id": "heroine_anri"}]:
|
|
var corrupt := original.duplicate(true)
|
|
corrupt.merge(patch, true)
|
|
expect(not Quote.valid(corrupt), "inconsistent/corrupt frozen quote rejected")
|
|
expect(Quote.make(SupplyCatalog.RAW_FOOD, 2, 9223372036854775807).is_empty(), "signed64 product/multiplier overflow refused before multiplication")
|
|
expect(Quote.affordable_quantity(12, 100, 3) == 5, "affordability uses total rounding, not a fake2G unit")
|
|
expect(SupplyAutoPurchasePlans.valid_charge(5, 3, 15) and not SupplyAutoPurchasePlans.valid_charge(5, 3, 12), "original v1 quantity-times-unit-price contract remains strict")
|
|
expect(SupplyAutoPurchasePlans.decode_receipt_memo(Quote.receipt_memo(original)).is_empty(), "old v1 codec never reinterprets explicit v2")
|
|
|
|
func manual_ui_and_formal() -> void:
|
|
var panel := SupplyManagementPanel.new()
|
|
panel.configure(runtime)
|
|
root.add_child(panel)
|
|
await process_frame
|
|
panel.selected_warehouse_id = warehouse
|
|
panel.selected_item_id = SupplyCatalog.RAW_FOOD
|
|
panel.quantity_spin.set_value_no_signal(5)
|
|
panel.refresh()
|
|
expect(panel.purchase_quote_label.text.contains("基準合計 15G") and panel.purchase_quote_label.text.contains("合計 12G"), "ordinary Supply UI shows base total and discounted effective total")
|
|
var cash: int = runtime.economy_service.get_balance(&"PLAYER_CASH")
|
|
var command_count: int = runtime.command_queue.processed_count()
|
|
panel.purchase_button.pressed.emit()
|
|
await process_frame
|
|
expect(stock() == 5 and runtime.economy_service.get_balance(&"PLAYER_CASH") == cash - 12, "existing UI button/normal command pays12G and stocks actual5")
|
|
expect(runtime.command_queue.processed_count() == command_count + 1, "actual command result retained; no fake noop journal")
|
|
var paid: Dictionary = runtime.create_snapshot()
|
|
proof("manual-paid", paid)
|
|
frozen_after_clear(paid, "manual")
|
|
expect(paid[&"systems"][&"runtime"][&"runtime_schema_version"] == 15, "actual frozen v2 history selects15")
|
|
panel.queue_free()
|
|
await process_frame
|
|
expect(not is_instance_valid(panel), "standalone panel owned release; Main/audio application-close untested")
|
|
var path := output.path_join("formal2")
|
|
var written: Dictionary = SaveService.save_snapshot(path, paid)
|
|
expect(written[&"ok"] and int(written[&"manifest"][&"format_version"]) == 2 and written[&"manifest"][&"runtime_schema_version"] == 15, "public formal2 carries explicit typed Runtime15 duplicate")
|
|
var files_before := package_hashes(path)
|
|
var inspected: Dictionary = SaveService.inspect_snapshot(path)
|
|
expect(inspected[&"ok"] and inspected[&"read_only"] and var_to_bytes(inspected[&"snapshot"]) == var_to_bytes(paid), "read-only formal2 preserves every decoded Variant byte")
|
|
expect(package_hashes(path) == files_before, "all four actual formal files unchanged by inspection")
|
|
var loaded: Dictionary = SaveService.load_snapshot(path)
|
|
expect(loaded[&"ok"] and var_to_bytes(loaded[&"snapshot"]) == var_to_bytes(paid), "ordinary formal2 load retains complete raw snapshot")
|
|
expect(runtime.restore_snapshot(loaded[&"snapshot"]) and var_to_bytes(runtime.create_snapshot()) == var_to_bytes(paid), "Runtime15 whole typed restore equality")
|
|
proof("manual-restored", runtime.create_snapshot())
|
|
reserved_stringname_memo_cases(paid, path)
|
|
for change: String in ["effective", "factor", "quantity", "masked14", "missingquote", "planheader"]:
|
|
var bad := paid.duplicate(true)
|
|
var data: Dictionary = bad[&"systems"][&"runtime"]
|
|
var processed: Array = data[&"command_queue"]["processed"]
|
|
var found := false
|
|
for row: Dictionary in processed:
|
|
if not (row["details"] as Dictionary).has(&"purchase_quote"): continue
|
|
found = true
|
|
var quote: Dictionary = row["details"][&"purchase_quote"]
|
|
match change:
|
|
"effective": quote[&"effective_total"] += 1
|
|
"factor": quote[&"multiplier_bp"] = 12000
|
|
"quantity": quote[&"quantity"] += 1
|
|
"missingquote": quote.erase(&"base_total")
|
|
break
|
|
if change == "masked14": data[&"runtime_schema_version"] = 14
|
|
if change == "planheader": data[&"auto_purchase_plans"][&"version"] = 2
|
|
expect(found, "real processed payment exists for corruption fixture")
|
|
expect(not runtime.restore_snapshot(bad) and var_to_bytes(runtime.create_snapshot()) == var_to_bytes(paid), "corrupt15 crosslink refuses and preserves every live field: " + change)
|
|
var ordinary_path := output.path_join("formal1")
|
|
expect(SaveService.save_snapshot(ordinary_path, built)[&"ok"], "old actual14/v1-only still writes format1")
|
|
expect(int(SaveService.inspect_snapshot(ordinary_path)[&"manifest"]["format_version"]) == 1, "old formal1 not upgraded by current Mimi presence")
|
|
var generic := SimulationSnapshot.capture(clock, state)
|
|
var generic_path := output.path_join("generic1")
|
|
expect(SaveService.save_snapshot(generic_path, generic)[&"ok"] and var_to_bytes(SaveService.inspect_snapshot(generic_path)[&"snapshot"]) == var_to_bytes(generic), "generic envelope without Runtime stays full format1")
|
|
ordinary_format_boundary_cases(paid)
|
|
# Actual valid transaction artifacts are created using the normal writer;
|
|
# only this disposable package's physical header/manifest are then mutated.
|
|
expect(SaveService.save_snapshot(path, paid)[&"ok"], "normal repeat write creates exact .bak2")
|
|
expect(SaveService.save_snapshot(path + ".tmp", paid)[&"ok"], "normal writer supplies genuine interrupted candidate2")
|
|
var marker := FileAccess.open(path + SaveService.SAVE_TRANSACTION_SUFFIX, FileAccess.WRITE)
|
|
expect(marker != null, "disclosed transaction crash marker fixture opens")
|
|
if marker != null: marker.store_string(SaveService.SAVE_TRANSACTION_MARKER); marker = null
|
|
# Unknown3 is protected before .bak/.tmp/marker reconciliation even though
|
|
# the compressed bytes/checksum remain valid.
|
|
set_physical_format(path, 3)
|
|
files_before = package_hashes(path)
|
|
for method: String in ["inspect", "load", "save", "recovery", "replace", "migration"]:
|
|
var result: Dictionary
|
|
match method:
|
|
"inspect": result = SaveService.inspect_snapshot(path)
|
|
"load": result = SaveService.load_snapshot(path)
|
|
"save": result = SaveService.save_snapshot(path, paid)
|
|
"recovery": result = SaveService.inspect_recovery_candidates(path)
|
|
"replace": result = SaveService.replace_snapshot_with_backup(path, paid, paid)
|
|
"migration": result = SaveService.migrate_save(path, SaveMigrationRegistry.new())
|
|
expect(not result[&"ok"] and package_hashes(path) == files_before, "unknown3 %s refusal preserves all formal/artifact bytes" % method)
|
|
set_physical_format(path, 1)
|
|
files_before = package_hashes(path)
|
|
expect(not SaveService.load_snapshot(path)[&"ok"] and package_hashes(path) == files_before, "Runtime15 physically masked as1 refused without reconciliation")
|
|
set_physical_format(ordinary_path, 2)
|
|
files_before = package_hashes(ordinary_path)
|
|
expect(not SaveService.load_snapshot(ordinary_path)[&"ok"] and package_hashes(ordinary_path) == files_before, "known2 with actual14/missing duplicate/crosslinks refused intact")
|
|
|
|
|
|
## Direct SaveService checks are read-only with respect to live Runtime.
|
|
## The public Runtime pair separately retains the legitimate failed-save event.
|
|
func ordinary_format_boundary_cases(paid: Dictionary) -> void:
|
|
var before: Dictionary = runtime.create_snapshot()
|
|
var old_path := output.path_join("ordinary_format1")
|
|
var new_path := output.path_join("ordinary_format2")
|
|
expect(SaveService.save_snapshot(old_path, built)[&"ok"], "normal old14 creates real formal1 before format boundary")
|
|
expect(SaveService.save_snapshot(new_path, paid)[&"ok"], "normal new15 creates real newslot formal2 before format boundary")
|
|
format_refused_preserves(old_path, paid, "formal1-to2", 1, 2)
|
|
format_refused_preserves(new_path, built, "formal2-to1", 2, 1)
|
|
for row: Array in [[old_path, built, 1], [new_path, paid, 2]]:
|
|
var written: Dictionary = SaveService.save_snapshot(row[0], row[1])
|
|
var inspected: Dictionary = SaveService.inspect_snapshot(row[0])
|
|
expect(written[&"ok"] and int(written[&"manifest"][&"format_version"]) == row[2], "same physical format ordinary Save remains allowed%d" % row[2])
|
|
expect(inspected[&"ok"] and var_to_bytes(inspected[&"snapshot"]) == var_to_bytes(row[1]), "same-format full stored Variant exact%d" % row[2])
|
|
for suffix: String in [".tmp", ".bak"]:
|
|
var pending_path := output.path_join("held_format1_" + suffix.trim_prefix("."))
|
|
expect(SaveService.save_snapshot(pending_path + suffix, built)[&"ok"], "genuine old-format pending recovery source " + suffix)
|
|
format_refused_preserves(pending_path, paid, "missing-formal" + suffix, 1, 2)
|
|
var recovered: Dictionary = SaveService.save_snapshot(pending_path, built)
|
|
expect(recovered[&"ok"] and recovered[&"interrupted_save_reconciled"], "same1 keeps normal pending recovery " + suffix)
|
|
expect(var_to_bytes(SaveService.inspect_snapshot(pending_path)[&"snapshot"]) == var_to_bytes(built), "same1 pending recovery stores every old Variant " + suffix)
|
|
var held2 := output.path_join("held_format2_tmp")
|
|
expect(SaveService.save_snapshot(held2 + ".tmp", paid)[&"ok"], "genuine known2 pending recovery source")
|
|
format_refused_preserves(held2, built, "missing-formal2.tmp", 2, 1)
|
|
var recovered2: Dictionary = SaveService.save_snapshot(held2, paid)
|
|
expect(recovered2[&"ok"] and recovered2[&"interrupted_save_reconciled"] and var_to_bytes(SaveService.inspect_snapshot(held2)[&"snapshot"]) == var_to_bytes(paid), "same2 keeps normal pending recovery with all frozen history")
|
|
for damage: String in ["manifest", "checksum"]:
|
|
var damaged := output.path_join("damaged_format1_" + damage)
|
|
expect(SaveService.save_snapshot(damaged, built)[&"ok"] and SaveService.save_snapshot(damaged + ".tmp", built)[&"ok"], "real formal1 and valid old pending candidate for " + damage)
|
|
var marker := FileAccess.open(damaged + SaveService.SAVE_TRANSACTION_SUFFIX, FileAccess.WRITE)
|
|
expect(marker != null, "controlled genuine transaction marker for " + damage)
|
|
if marker != null:
|
|
marker.store_string(SaveService.SAVE_TRANSACTION_MARKER)
|
|
marker = null
|
|
var manifest: Dictionary = JSON.parse_string(FileAccess.get_file_as_string(damaged.path_join(SaveService.MANIFEST_FILE)))
|
|
var file := FileAccess.open(damaged.path_join(SaveService.MANIFEST_FILE), FileAccess.WRITE)
|
|
expect(file != null, "controlled old-format manifest damage fixture " + damage)
|
|
if file != null:
|
|
if damage == "manifest":
|
|
file.store_string("{invalid")
|
|
else:
|
|
manifest["checksum_world"] = "0".repeat(64)
|
|
file.store_string(JSON.stringify(manifest))
|
|
file = null
|
|
format_refused_preserves(damaged, paid, "damaged-formal1-" + damage, 1, 2)
|
|
var repaired: Dictionary = SaveService.save_snapshot(damaged, built)
|
|
expect(repaired[&"ok"] and repaired[&"interrupted_save_reconciled"] and var_to_bytes(SaveService.inspect_snapshot(damaged)[&"snapshot"]) == var_to_bytes(built), "same1 retains valid current-format crash recovery " + damage)
|
|
expect(var_to_bytes(runtime.create_snapshot()) == var_to_bytes(before), "direct file boundary checks preserve every live Runtime field/type/RNG/journal")
|
|
proof("ordinary-format-live-before", before)
|
|
proof("ordinary-format-live-after", runtime.create_snapshot())
|
|
|
|
func format_refused_preserves(path: String, snapshot: Dictionary, label: String, old_format: int, new_format: int) -> void:
|
|
var before_files := package_hashes(path)
|
|
var before: Dictionary = runtime.create_snapshot()
|
|
var result: Dictionary = SaveService.save_snapshot(path, snapshot)
|
|
expect(not result[&"ok"] and result[&"code"] == &"FORMAT_MIGRATION_REQUIRED" and result[&"existing_format_version"] == old_format and result[&"requested_format_version"] == new_format and result[&"formal_and_artifacts_preserved"], "read-only different-format rejection " + label)
|
|
expect(var_to_bytes(package_hashes(path)) == var_to_bytes(before_files), "all formal/tmp/bak/marker files and directories exact on rejection " + label)
|
|
expect(var_to_bytes(runtime.create_snapshot()) == var_to_bytes(before), "direct rejection keeps all live types/IDs/RNG/journals " + label)
|
|
proof("format-refusal-" + label + "-files", before_files)
|
|
proof("format-refusal-" + label + "-result", result)
|
|
|
|
|
|
func reserved_stringname_memo_cases(paid: Dictionary, path: String) -> void:
|
|
# Actual v2 payment is the source of both negatives. Only disclosed quote
|
|
# authorities are removed to isolate the reserved memo TYPE_STRING_NAME gap;
|
|
# no amount/account/transaction/ID/balance is altered or normalized.
|
|
var masked := paid.duplicate(true)
|
|
var data: Dictionary = masked[&"systems"][&"runtime"]
|
|
var reserved_count := 0
|
|
for row: Dictionary in data[&"economy"][&"entries"]:
|
|
if String(row[&"memo_key"]).begins_with(Quote.PREFIX):
|
|
row[&"memo_key"] = StringName(row[&"memo_key"]); reserved_count += 1
|
|
for row: Dictionary in data[&"command_queue"]["processed"]:
|
|
(row["details"] as Dictionary).erase(&"purchase_quote")
|
|
for row: Dictionary in data[&"domain_events"]["recent_events"]:
|
|
if row["event_type"] in ["COMMAND_COMPLETED", "COMMAND_FAILED"] and row["payload"].get("details") is Dictionary:
|
|
(row["payload"]["details"] as Dictionary).erase(&"purchase_quote")
|
|
expect(reserved_count == 1 and data[&"auto_purchase_plans"][&"version"] == 1, "actual paid single double-entry ledger row reserved memo isolated without any v2 plan row")
|
|
expect(Quote.has_history(data), "reserved StringName memo still identifies invalid new-history authority")
|
|
var files := package_hashes(path)
|
|
for version: int in [14, 15]:
|
|
data[&"runtime_schema_version"] = version
|
|
proof("reserved-stringname-memo-%d-input" % version, masked)
|
|
expect(not runtime.restore_snapshot(masked) and var_to_bytes(runtime.create_snapshot()) == var_to_bytes(paid), "reserved StringName memo masked%d refuses with literal whole live state" % version)
|
|
expect(not SaveService.save_snapshot(path, masked)[&"ok"] and package_hashes(path) == files, "reserved StringName memo masked%d writer rejects before formal/artifact mutation" % version)
|
|
proof("reserved-stringname-memo-%d-live" % version, runtime.create_snapshot())
|
|
var unrelated := {&"economy": {&"entries": [{&"memo_key": &"legacy.unrelated.memo"}]}}
|
|
expect(not Quote.has_history(unrelated), "unrelated legacy StringName memo is not new history; old coercion parser remains literal")
|
|
|
|
func automatic_and_failures() -> void:
|
|
expect(runtime.restore_snapshot(with_mimi), "controlled pre-payment14 fixture resets literally")
|
|
expect(runtime.submit_command(&"set_supply_auto_purchase", {&"warehouse_id": warehouse, &"item_id": SupplyCatalog.RAW_FOOD, &"enabled": true, &"target_stock": 5}).is_success(), "ordinary public automatic intent5")
|
|
var cash: int = runtime.economy_service.get_balance(&"PLAYER_CASH")
|
|
clock.advance_minutes(1)
|
|
var plan: Dictionary = runtime.auto_purchase_plans.get_plan(warehouse, SupplyCatalog.RAW_FOOD)
|
|
expect(stock() == 5 and runtime.economy_service.get_balance(&"PLAYER_CASH") == cash - 12, "actual next tick auto order pays total12G")
|
|
expect(plan.has(&"last_quote") and not plan.has(&"last_unit_price") and plan[&"last_total_cost"] == 12, "explicit ten-field v2 row avoids a fabricated effective unit")
|
|
var auto_paid: Dictionary = runtime.create_snapshot()
|
|
proof("auto-paid", auto_paid)
|
|
frozen_after_clear(auto_paid, "auto")
|
|
expect(runtime.restore_snapshot(auto_paid) and var_to_bytes(runtime.create_snapshot()) == var_to_bytes(auto_paid), "whole typed auto15 restore with receipt crosslinks")
|
|
var frozen: Dictionary = Quote.receipt_from_ledger(runtime.economy_service, warehouse, SupplyCatalog.RAW_FOOD, plan[&"last_attempt_minute"], StringName(plan[&"last_transaction_id"]))
|
|
expect(var_to_bytes(frozen) == var_to_bytes(plan[&"last_quote"]), "unique auto ledger key resolves frozen full quote")
|
|
expect(runtime.supply_management.advance_auto_purchases(runtime, clock.absolute_minute).is_empty() and var_to_bytes(runtime.create_snapshot()) == var_to_bytes(auto_paid), "same-minute retry emits/stocks/pays nothing and keeps every journal")
|
|
# Failure injection is the same explicit contract used by existing core test.
|
|
expect(runtime.restore_snapshot(with_mimi), "separate notification-rejection fixture resets")
|
|
var rejecting := RejectingNotificationEconomy.new()
|
|
expect(rejecting.restore_snapshot(runtime.economy_service.create_snapshot()), "injected Economy starts from all actual fields")
|
|
runtime.economy_service = rejecting
|
|
runtime.call("_connect_economy_signals")
|
|
var before: Dictionary = runtime.create_snapshot()
|
|
var notifications: Array[StringName] = []
|
|
rejecting.transaction_posted.connect(func(id: StringName, _entries: Array) -> void: notifications.append(id))
|
|
var failed: CommandResult = runtime.submit_command(&"purchase_supplies", {&"warehouse_id": warehouse, &"item_id": SupplyCatalog.RAW_FOOD, &"quantity": 5})
|
|
var after: Dictionary = runtime.create_snapshot()
|
|
expect(not failed.is_success() and failed.details[&"reason"] == &"PAYMENT_FAILED", "real public command returns notification-failure result")
|
|
for field: StringName in [&"inventory", &"economy", &"auto_purchase_plans"]:
|
|
expect(var_to_bytes(before[&"systems"][&"runtime"][field]) == var_to_bytes(after[&"systems"][&"runtime"][field]), "rollback retains all original IDs/typed fields: " + String(field))
|
|
expect(notifications.is_empty(), "failed transaction posts no partial notification")
|
|
expect(var_to_bytes(before) != var_to_bytes(after) and runtime.command_queue.get_processed_result(failed.command_id) != null, "legitimate accepted/failed command and IDs remain; whole state is not falsely called noop")
|
|
proof("notification-failure-before", before)
|
|
proof("notification-failure-after", after)
|
|
proof("notification-failure-result", failed.to_dictionary())
|
|
|
|
func stock() -> int:
|
|
return runtime.inventory_service.total_quantity(runtime.facility_service.get_instance(warehouse).local_inventory_id, SupplyCatalog.RAW_FOOD)
|
|
|
|
func proof(label: String, value: Variant) -> void:
|
|
var path := output.path_join(label + ".var")
|
|
var file := FileAccess.open(path, FileAccess.WRITE)
|
|
expect(file != null, "proof file open: " + label)
|
|
if file == null: return
|
|
var bytes := var_to_bytes(value)
|
|
file.store_buffer(bytes)
|
|
file = null
|
|
expect(FileAccess.get_file_as_bytes(path) == bytes, "all original raw typed bytes persisted: " + label)
|
|
written_proofs.append(path)
|
|
|
|
func package_hashes(path: String) -> Dictionary:
|
|
var result: Dictionary = {}
|
|
var suffixes: Array[String] = ["", ".tmp", ".bak", ".migration.tmp", ".migration.original", ".pre_migration.bak", ".pre_migration.bak.tmp", ".pre_migration.bak.old", ".autosave.pending", ".autosave.pending.tmp", ".autosave.pending.bak", SaveService.SAVE_TRANSACTION_SUFFIX]
|
|
for generation: int in range(SaveService.MAX_AUTOSAVE_GENERATIONS):
|
|
var suffix := SaveService.AUTOSAVE_SUFFIX + str(generation)
|
|
suffixes.append(suffix)
|
|
suffixes.append(suffix + ".rotate_tmp")
|
|
for suffix: String in suffixes:
|
|
collect_owned_files(ProjectSettings.globalize_path(path + suffix), suffix, result)
|
|
return result
|
|
|
|
func collect_owned_files(path: String, relative: String, result: Dictionary) -> void:
|
|
if FileAccess.file_exists(path):
|
|
result[relative] = {&"sha256": FileAccess.get_sha256(path), &"bytes": FileAccess.get_file_as_bytes(path).size()}
|
|
return
|
|
if not DirAccess.dir_exists_absolute(path): return
|
|
result[relative + "/"] = &"DIRECTORY"
|
|
var names: PackedStringArray = DirAccess.get_directories_at(path)
|
|
names.append_array(DirAccess.get_files_at(path))
|
|
names.sort()
|
|
for name: String in names:
|
|
collect_owned_files(path.path_join(name), relative + "/" + name, result)
|
|
|
|
func set_physical_format(path: String, version: int) -> void:
|
|
var world := FileAccess.open(path.path_join(SaveService.WORLD_FILE), FileAccess.READ_WRITE)
|
|
expect(world != null, "controlled physical version fixture opens")
|
|
if world == null: return
|
|
world.seek(4)
|
|
world.store_32(version)
|
|
world = null
|
|
var manifest: Dictionary = JSON.parse_string(FileAccess.get_file_as_string(path.path_join(SaveService.MANIFEST_FILE)))
|
|
manifest["format_version"] = version
|
|
var file := FileAccess.open(path.path_join(SaveService.MANIFEST_FILE), FileAccess.WRITE)
|
|
expect(file != null, "controlled manifest version fixture opens")
|
|
if file != null: file.store_string(JSON.stringify(manifest)); file = null
|
|
|
|
func expect(ok: bool, label: String) -> void:
|
|
checks += 1
|
|
if not ok:
|
|
failures += 1
|
|
push_error("MIMI_PURCHASE: " + label)
|
|
|
|
func finish() -> void:
|
|
print("Mimi purchase quote: %d checks, %d failures" % [checks, failures])
|
|
quit(failures)
|