Files
TheTree_mock/tests/mvp/test_runtime_content_progression.gd

531 lines
28 KiB
GDScript

extends SceneTree
class DenyingOperationsCoordinator:
extends OperationsCoordinator
func can_start_construction_or_investment() -> Dictionary:
return {
&"allowed": false,
&"reason": &"ARREARS_REMAIN",
&"arrears_total": 25,
&"consecutive_insolvency_count": 1,
}
var _checks := 0
var _failures := 0
var _clock: Variant
var _state: Variant
var _runtime: Variant
var _direct_command_id := 900_000
func _initialize() -> void:
call_deferred("_run")
func _run() -> void:
print("MVP: Runtime content, hiring, and progression integration")
_test_catalog_bootstrap_and_queries()
_test_progression_resource_and_guest_facts()
_test_catalog_staff_hire_transaction()
_test_unique_runtime_protection()
_test_rank_two_three_and_atomic_failure()
_test_v3_migration_and_v4_tamper_guards()
_test_twenty_four_hour_replay()
_cleanup()
if _failures == 0:
print("PASS: %d checks" % _checks)
else:
push_error("FAIL: %d of %d checks failed" % [_failures, _checks])
quit(_failures)
func _reset_runtime(seed := 82_001) -> void:
_cleanup()
_clock = load("res://autoload/game_clock.gd").new()
_state = load("res://autoload/game_state.gd").new()
_runtime = load("res://autoload/simulation_runtime.gd").new()
_clock.reset(1, 6, 0)
_state.reset()
var report: Dictionary = _runtime.initialize(_clock, _state, seed)
_clock.set_paused(true)
_expect(bool(report.get(&"valid", false)), "Runtime initializes with validated content and Progression")
func _cleanup() -> void:
if _runtime != null:
_runtime.free()
if _clock != null:
_clock.free()
if _state != null:
_state.free()
_runtime = null
_clock = null
_state = null
func _test_catalog_bootstrap_and_queries() -> void:
_reset_runtime(82_001)
var report: Dictionary = _runtime.get_mvp_content_report()
_expect(bool(report[&"valid"]), "MVP catalog report is valid")
_expect(int(report[&"counts"]["guest_classes"]) == 8, "catalog exposes eight Guest classes")
_expect(int(report[&"counts"]["species"]) == 4, "catalog exposes four independent species")
_expect(int(report[&"counts"]["staff_candidates"]) == 21, "catalog exposes twenty-one fixed Staff candidates")
_expect(int(report[&"counts"]["unique_characters"]) == 2, "catalog exposes both unique characters")
var catalog_ids: Array[StringName] = _runtime.get_mvp_guest_definition_ids()
_expect(catalog_ids.size() == 32, "Runtime registers every class/species Guest definition")
_expect(_runtime.guest_service.get_definitions().size() == 35, "legacy three Guest definitions coexist with the 32 catalog definitions")
var sorted_ids := catalog_ids.duplicate()
sorted_ids.sort_custom(func(left: StringName, right: StringName) -> bool: return String(left) < String(right))
_expect(catalog_ids == sorted_ids, "Runtime catalog Guest IDs use stable canonical order")
var all_registered := true
for guest_type_id: StringName in catalog_ids:
if _runtime.guest_service.get_definition(guest_type_id) == null:
all_registered = false
break
_expect(all_registered, "all 32 catalog Guest definitions are queryable by stable ID")
report[&"counts"]["guest_classes"] = 0
_expect(int(_runtime.get_mvp_content_report()[&"counts"]["guest_classes"]) == 8, "content report query is a defensive copy")
var candidate: Dictionary = _runtime.get_mvp_staff_candidate_payload(&"staff_akane")
(candidate[&"options"][&"skills"] as Dictionary)[&"service"] = -1
_expect(
int(_runtime.get_mvp_staff_candidate_payload(&"staff_akane")[&"options"][&"skills"][&"service"]) == 68,
"Staff candidate payload query is a defensive copy"
)
var progression_report: Dictionary = _runtime.get_progression_report()
(progression_report[&"snapshot"][&"metrics"] as Dictionary)["asset_gold"] = 0
_expect(int(_runtime.progression_service.metrics[&"asset_gold"]) == 5_000, "Progression report query is a defensive copy")
func _test_progression_resource_and_guest_facts() -> void:
_reset_runtime(82_002)
var faith: CommandResult = _runtime.submit_command(
&"change_resources", {&"deltas": {&"faith": 40}},
&"player", &"", 50, -1, &"mvp.progression.faith"
)
_expect(faith.is_success(), "positive Faith resource change succeeds")
_expect(_state.get_resource(&"faith") == 40, "positive Faith changes live GameState")
_expect(int(_runtime.progression_service.metrics[&"faith_lifetime"]) == 40, "positive Faith increments lifetime progression atomically")
var spawned: CommandResult = _runtime.submit_command(
&"spawn_guest",
{
&"guest_id": &"catalog_guest_one",
&"guest_type_id": _runtime.get_mvp_guest_definition_ids()[0],
&"gold": 50,
&"options": {&"current_cell": Vector3i.ZERO},
},
&"world", &"catalog_guest_one", 40, -1, &"mvp.progression.guest_one"
)
_expect(spawned.is_success(), "catalog Guest can spawn through Runtime")
_expect(int(_runtime.progression_service.metrics[&"guest_lifetime"]) == 1, "successful Guest spawn increments lifetime Guest count once")
var duplicate: CommandResult = _runtime.submit_command(
&"spawn_guest",
{
&"guest_id": &"catalog_guest_one",
&"guest_type_id": _runtime.get_mvp_guest_definition_ids()[0],
&"options": {&"current_cell": Vector3i.ZERO},
},
&"world", &"catalog_guest_one", 40, -1, &"mvp.progression.guest_duplicate"
)
_expect(not duplicate.is_success(), "duplicate Guest spawn is rejected")
_expect(int(_runtime.progression_service.metrics[&"guest_lifetime"]) == 1, "failed Guest spawn cannot increment lifetime progression")
_expect(
_runtime.progression_service.update_metrics({&"faith_lifetime": ProgressionService.MAX_SAFE_INTEGER}),
"overflow rollback fixture reaches the maximum lifetime Faith"
)
var state_before: Dictionary = _state.create_snapshot()
var economy_before: Dictionary = _runtime.economy_service.create_snapshot()
var progression_before: Dictionary = _runtime.progression_service.create_snapshot()
var overflow: CommandResult = _runtime._execute_change_resources(_direct_command(
&"change_resources", {&"deltas": {&"faith": 1}}
))
_expect(not overflow.is_success(), "lifetime Faith overflow rejects the resource command")
_expect(_state.create_snapshot() == state_before, "failed lifetime update restores GameState exactly")
_expect(_runtime.economy_service.create_snapshot() == economy_before, "failed lifetime update restores Economy exactly")
_expect(_runtime.progression_service.create_snapshot() == progression_before, "failed lifetime update restores Progression exactly")
func _test_catalog_staff_hire_transaction() -> void:
_reset_runtime(82_003)
var bypass: CommandResult = _runtime.submit_command(
&"register_staff",
{
&"staff_id": &"staff_akane",
&"role_id": &"guard",
&"options": {&"current_cell": Vector3i.ZERO},
},
&"player", &"staff_akane", 80, -1, &"mvp.hire.bypass"
)
_expect(not bypass.is_success(), "generic Staff registration cannot bypass a reserved catalog candidate")
var cash_before: int = _runtime.economy_service.get_balance(_runtime.PLAYER_CASH_ACCOUNT)
var hired: CommandResult = _runtime.submit_command(
&"hire_staff_candidate",
{&"candidate_id": &"staff_akane", &"current_cell": Vector3i.ZERO},
&"player", &"staff_akane", 80, -1, &"mvp.hire.akane"
)
_expect(hired.is_success(), "validated Staff candidate hires atomically")
var staff: StaffRuntime = _runtime.staff_service.get_staff(&"staff_akane")
var shift: ShiftInstance = _runtime.staff_service.get_shift(StringName(hired.details[&"shift_id"]))
_expect(staff != null and staff.role_id == &"receptionist", "hire uses the catalog role as the sole source of truth")
_expect(staff != null and staff.daily_wage == 120, "FREE_HIRE retains its catalog daily wage")
_expect(staff != null and staff.get_employment_kind_name() == &"FREE_HIRE", "ordinary catalog hire records explicit FREE_HIRE employment")
_expect(staff != null and int(staff.skills[&"service"]) == 68, "hire copies catalog skills without caller inference")
_expect(staff != null and staff.permitted_task_tags == [&"reception", &"service"], "hire copies canonical permitted Task tags")
_expect(shift != null and shift.template_id == &"DAY", "hire creates the candidate's preferred Shift")
_expect(_runtime.staff_service.get_daily_payroll_total() == 120, "hired candidate participates in deterministic daily payroll")
_expect(
_runtime.economy_service.get_balance(_runtime.PLAYER_CASH_ACCOUNT) == cash_before - 180,
"signing cost is paid exactly once through the Gold ledger"
)
_expect(_state.get_resource(&"gold") == cash_before - 180, "ledger signing cost synchronizes GameState Gold")
_expect(_runtime.path_service.has_actor_projection(&"staff:staff_akane"), "hired Staff is projected into Path traffic")
_expect(_runtime.get_hired_staff_candidate_ids() == [&"staff_akane"], "Runtime records the candidate as permanently hired")
var saw_hire_event := false
for event: SimulationDomainEvent in _runtime.domain_events.recent_events():
if event.event_type == &"STAFF_CANDIDATE_HIRED" and &"staff_akane" in event.entity_ids:
saw_hire_event = true
_expect(saw_hire_event, "successful hire publishes a structured DomainEvent")
var replay_cash: int = _runtime.economy_service.get_balance(_runtime.PLAYER_CASH_ACCOUNT)
var replay: CommandResult = _runtime.submit_command(
&"hire_staff_candidate",
{&"candidate_id": &"staff_akane", &"current_cell": Vector3i.ZERO},
&"player", &"staff_akane", 80, -1, &"mvp.hire.akane"
)
_expect(not replay.is_success() and replay.code == CommandResult.Code.DUPLICATE_IDEMPOTENCY_KEY, "resent hire command is recognized by its idempotency key")
_expect(_runtime.economy_service.get_balance(_runtime.PLAYER_CASH_ACCOUNT) == replay_cash, "resent hire never charges the signing cost twice")
var duplicate: CommandResult = _runtime.submit_command(
&"hire_staff_candidate",
{&"candidate_id": &"staff_akane", &"current_cell": Vector3i.ZERO},
&"player", &"staff_akane", 80, -1, &"mvp.hire.akane.other"
)
_expect(not duplicate.is_success(), "same candidate cannot be hired under a different request")
_expect(_runtime.economy_service.get_balance(_runtime.PLAYER_CASH_ACCOUNT) == replay_cash, "duplicate-candidate rejection spends no Gold")
var original_coordinator: Variant = _runtime.operations_coordinator
var original_operations_enabled: bool = bool(_runtime._operations_enabled)
var staff_before_gate: Dictionary = _runtime.staff_service.create_snapshot()
var economy_before_gate: Dictionary = _runtime.economy_service.create_snapshot()
var hired_before_gate: Array[StringName] = _runtime.get_hired_staff_candidate_ids()
_runtime.operations_coordinator = DenyingOperationsCoordinator.new()
_runtime._operations_enabled = true
var gated: CommandResult = _runtime._execute_hire_staff_candidate(_direct_command(
&"hire_staff_candidate",
{&"candidate_id": &"staff_tessa", &"current_cell": Vector3i.ZERO}
))
_runtime.operations_coordinator = original_coordinator
_runtime._operations_enabled = original_operations_enabled
_expect(
not gated.is_success()
and StringName(gated.details.get(&"reason", &"")) == &"ARREARS_REMAIN",
"Operations arrears gate rejects a new wage-bearing Staff contract"
)
_expect(
_runtime.staff_service.create_snapshot() == staff_before_gate
and _runtime.economy_service.create_snapshot() == economy_before_gate
and _runtime.get_hired_staff_candidate_ids() == hired_before_gate,
"rejected Operations-gated hire spends nothing and mutates no Staff history"
)
var staff_before: Dictionary = _runtime.staff_service.create_snapshot()
var economy_before: Dictionary = _runtime.economy_service.create_snapshot()
var game_state_before: Dictionary = _state.create_snapshot()
var path_before: Dictionary = _runtime.path_service.create_snapshot()
var credits_before: Dictionary = _runtime._movement_credits.duplicate(true)
var events_before: Dictionary = _runtime.domain_events.create_snapshot()
var ids_before: Dictionary = _runtime.id_generator.create_snapshot()
var hired_ids_before: Array[StringName] = _runtime.get_hired_staff_candidate_ids()
var callback := Callable(_runtime, "_on_staff_registered")
_runtime.staff_service.staff_registered.disconnect(callback)
var forced_failure: CommandResult = _runtime._execute_hire_staff_candidate(_direct_command(
&"hire_staff_candidate",
{&"candidate_id": &"staff_bardo", &"current_cell": Vector3i.ZERO}
))
_runtime.staff_service.staff_registered.connect(callback)
_expect(not forced_failure.is_success(), "missing Path projection forces a post-payment hire failure")
_expect(_runtime.staff_service.create_snapshot() == staff_before, "failed hire restores Staff and Shift state exactly")
_expect(_runtime.economy_service.create_snapshot() == economy_before, "failed hire restores the ledger exactly")
_expect(_state.create_snapshot() == game_state_before, "failed hire restores GameState exactly")
_expect(_runtime.path_service.create_snapshot() == path_before, "failed hire restores Path exactly")
_expect(_runtime._movement_credits == credits_before, "failed hire restores movement credits exactly")
_expect(_runtime.domain_events.create_snapshot() == events_before, "failed hire restores DomainEvents exactly")
_expect(_runtime.id_generator.create_snapshot() == ids_before, "failed hire restores stable ID counters exactly")
_expect(_runtime.get_hired_staff_candidate_ids() == hired_ids_before, "failed hire leaves candidate history unchanged")
var canonical_save: Dictionary = _runtime.create_snapshot()
var wage_tamper: Dictionary = canonical_save.duplicate(true)
for raw_staff: Dictionary in wage_tamper[&"systems"][&"runtime"][&"staff"][&"staff"]:
if String(raw_staff[&"staff_id"]) == "staff_akane":
raw_staff[&"daily_wage"] = 0
break
var live_before: Dictionary = _runtime.create_snapshot()
_expect(not _runtime.restore_snapshot(wage_tamper), "v4 restore rejects a hired candidate whose catalog wage was altered")
_expect(_runtime.create_snapshot() == live_before, "catalog Staff crosslink rejection is atomic")
func _test_rank_two_three_and_atomic_failure() -> void:
_reset_runtime(82_004)
var rank_before: Dictionary = _runtime.progression_service.create_snapshot()
var world_before: Dictionary = _runtime.world_service.create_snapshot()
var unmet: CommandResult = _runtime._execute_set_world_tree_rank(_direct_command(
&"set_world_tree_rank", {&"rank": 2, &"request_id": &"rank_two_unmet"}
))
_expect(not unmet.is_success(), "Rank 2 rejects unmet reputation and asset requirements")
_expect(_runtime.progression_service.create_snapshot() == rank_before, "failed eligibility check leaves Progression exact")
_expect(_runtime.world_service.create_snapshot() == world_before, "failed eligibility check leaves World exact")
_expect(_runtime._execute_update_progression_metrics(_direct_command(
&"update_progression_metrics", {&"metrics": {&"reputation": 25}}
)).is_success(), "Rank 2 reputation fact updates")
_expect(_runtime._execute_change_resources(_direct_command(
&"change_resources", {&"deltas": {&"gold": 5_000}}
)).is_success(), "Rank 2 asset threshold is funded")
var promoted_two: CommandResult = _runtime._execute_set_world_tree_rank(_direct_command(
&"set_world_tree_rank", {&"rank": 2, &"request_id": &"rank_two"}
))
_expect(promoted_two.is_success(), "eligible Rank 2 promotion succeeds")
_expect(_runtime.progression_service.current_rank == 2 and _state.world_tree_rank == 2, "Progression and GameState commit Rank 2 together")
_expect(_runtime.world_service.get_bounds() == ProgressionService.RANK_BOUNDS[2], "Rank 2 commits canonical World bounds")
var replay_before: Dictionary = _runtime.create_snapshot()
var replay: CommandResult = _runtime._execute_set_world_tree_rank(_direct_command(
&"set_world_tree_rank", {&"rank": 2, &"request_id": &"rank_two"}
))
_expect(replay.is_success() and replay.is_replay, "same rank request ID replays the original success")
_expect(_runtime.create_snapshot() == replay_before, "rank request replay is completely read-only")
var skip: CommandResult = _runtime._execute_set_world_tree_rank(_direct_command(
&"set_world_tree_rank", {&"rank": 4, &"request_id": &"rank_four_skip"}
))
_expect(not skip.is_success() and _runtime.progression_service.current_rank == 2, "rank progression cannot skip Rank 3")
var rank_three_guests_ok := true
var rank_guest_definition: StringName = _runtime.get_mvp_guest_definition_ids()[0]
for index in range(300):
var guest_id := StringName("rank_three_guest_%03d" % index)
var spawned: CommandResult = _runtime._execute_spawn_guest(_direct_command(
&"spawn_guest",
{
&"guest_id": guest_id,
&"guest_type_id": rank_guest_definition,
&"gold": 0,
&"options": {
&"current_cell": Vector3i.ZERO,
&"planned_exit_at": 10_000,
},
}
))
rank_three_guests_ok = rank_three_guests_ok and spawned.is_success()
var lifetime_updated: CommandResult = _runtime._execute_update_progression_metrics(_direct_command(
&"update_progression_metrics",
{&"metrics": {&"faith_lifetime": 100}}
))
_expect(
rank_three_guests_ok and lifetime_updated.is_success() \
and int(_runtime.progression_service.metrics[&"guest_lifetime"]) == 300,
"Rank 3 lifetime facts derive from 300 authoritative Guest records"
)
var promoted_three: CommandResult = _runtime._execute_set_world_tree_rank(_direct_command(
&"set_world_tree_rank", {&"rank": 3, &"request_id": &"rank_three"}
))
_expect(promoted_three.is_success(), "eligible Rank 3 promotion succeeds")
_expect(_runtime.progression_service.current_rank == 3 and _state.world_tree_rank == 3, "Progression and GameState commit Rank 3 together")
var saw_rank_event := false
for event: SimulationDomainEvent in _runtime.domain_events.recent_events():
if event.event_type == &"WORLD_TREE_RANK_ADVANCED" and int(event.payload.get(&"rank", 0)) == 3:
saw_rank_event = true
_expect(saw_rank_event, "successful promotion publishes WORLD_TREE_RANK_ADVANCED")
_reset_runtime(82_005)
_runtime.progression_service.update_metrics({&"reputation": 25})
_runtime._execute_change_resources(_direct_command(&"change_resources", {&"deltas": {&"gold": 5_000}}))
_expect(_runtime._expand_world_to_rank(3), "rank apply-failure fixture expands World and Path coherently")
var atomic_before := {
&"progression": _runtime.progression_service.create_snapshot(),
&"world": _runtime.world_service.create_snapshot(),
&"path": _runtime.path_service.create_snapshot(),
&"state": _state.create_snapshot(),
&"credits": _runtime._movement_credits.duplicate(true),
&"events": _runtime.domain_events.create_snapshot(),
&"ids": _runtime.id_generator.create_snapshot(),
}
var apply_failure: CommandResult = _runtime._execute_set_world_tree_rank(_direct_command(
&"set_world_tree_rank", {&"rank": 2, &"request_id": &"rank_two_apply_failure"}
))
_expect(not apply_failure.is_success(), "World/Path apply failure rejects promotion")
_expect(_runtime.progression_service.create_snapshot() == atomic_before[&"progression"], "failed rank apply restores Progression exactly")
_expect(_runtime.world_service.create_snapshot() == atomic_before[&"world"], "failed rank apply restores World exactly")
_expect(_runtime.path_service.create_snapshot() == atomic_before[&"path"], "failed rank apply restores Path exactly")
_expect(_state.create_snapshot() == atomic_before[&"state"], "failed rank apply restores GameState exactly")
_expect(_runtime._movement_credits == atomic_before[&"credits"], "failed rank apply restores movement credits exactly")
_expect(_runtime.domain_events.create_snapshot() == atomic_before[&"events"], "failed rank apply restores DomainEvents exactly")
_expect(_runtime.id_generator.create_snapshot() == atomic_before[&"ids"], "failed rank apply restores stable IDs exactly")
func _test_v3_migration_and_v4_tamper_guards() -> void:
_reset_runtime(82_006)
_runtime._execute_change_resources(_direct_command(&"change_resources", {&"deltas": {&"faith": 12}}))
for index in range(2):
var guest_id := StringName("legacy_guest_%d" % index)
var spawned: CommandResult = _runtime._execute_spawn_guest(_direct_command(
&"spawn_guest",
{
&"guest_id": guest_id,
&"guest_type_id": _runtime.get_mvp_guest_definition_ids()[index],
&"gold": 0,
&"options": {&"current_cell": Vector3i.ZERO},
}
))
_expect(spawned.is_success(), "legacy migration fixture Guest %d spawns" % index)
_runtime.guest_service.despawn_guest(&"legacy_guest_1", _clock.absolute_minute)
var v3: Dictionary = _runtime.create_snapshot()
var v3_runtime: Dictionary = v3[&"systems"][&"runtime"]
v3_runtime[&"runtime_schema_version"] = 3
v3_runtime.erase(&"kitchen_production")
v3_runtime.erase(&"elevators")
v3_runtime.erase(&"legacy_stairs")
preload("res://tests/fixtures/pre_upkeep_runtime.gd").strip_empty_upkeep(v3_runtime)
v3_runtime[&"path"][&"schema_version"] = 3
v3_runtime[&"path"].erase(&"vertical_walk_blockers")
v3_runtime[&"path"].erase(&"vertical_walk_requires_connector")
v3_runtime[&"path"].erase(&"transit_actor_ids")
v3_runtime.erase(&"operations")
v3_runtime.erase(&"catalog_manifest")
v3_runtime.erase(&"progression")
v3_runtime.erase(&"hired_staff_candidate_ids")
for infrastructure_key: StringName in [
&"excavation", &"spatial_subslots", &"route_projection",
&"facility_infrastructure",
]:
v3_runtime.erase(infrastructure_key)
_expect(_runtime.restore_snapshot(v3), "Runtime v3 Rank 1 snapshot migrates without guessed promotion evidence")
_expect(_runtime.progression_service.current_rank == 1, "v3 migration creates fresh Rank 1 Progression")
_expect(int(_runtime.progression_service.metrics[&"asset_gold"]) == _runtime.economy_service.get_balance(_runtime.PLAYER_CASH_ACCOUNT), "v3 migration derives asset Gold from the authoritative ledger")
_expect(int(_runtime.progression_service.metrics[&"faith_lifetime"]) == 12, "v3 migration derives lifetime Faith from current Faith")
_expect(int(_runtime.progression_service.metrics[&"guest_lifetime"]) == 2, "v3 migration derives lifetime Guests from active plus persistent records")
_expect(_runtime.get_mvp_guest_definition_ids().size() == 32, "v3 migration registers the current 32 catalog definitions")
var migrated: Dictionary = _runtime.create_snapshot()
_expect(int(migrated[&"systems"][&"runtime"][&"runtime_schema_version"]) == 14, "v3 migration emits canonical Runtime schema v14")
var digest := SimulationDigest.compute(migrated)
_expect(_runtime.restore_snapshot(migrated), "canonical v9 snapshot restores")
_expect(SimulationDigest.compute(_runtime.create_snapshot()) == digest, "canonical v9 restore is exact")
var progressed_legacy: Dictionary = v3.duplicate(true)
progressed_legacy[&"game_state"][&"world_tree_rank"] = 2
var live_before: Dictionary = _runtime.create_snapshot()
_expect(not _runtime.restore_snapshot(progressed_legacy), "v3 Rank 2 snapshot is rejected because promotion evidence is absent")
_expect(_runtime.create_snapshot() == live_before, "rejected progressed v3 migration is atomic")
var corruptions: Array[Dictionary] = []
var manifest: Dictionary = migrated.duplicate(true)
manifest[&"systems"][&"runtime"][&"catalog_manifest"][&"guest_definition_ids"][0] = "tampered_guest"
corruptions.append({&"label": "catalog manifest", &"snapshot": manifest})
var definition: Dictionary = migrated.duplicate(true)
var catalog_id := String(_runtime.get_mvp_guest_definition_ids()[0])
for raw_definition: Dictionary in definition[&"systems"][&"runtime"][&"guests"][&"definitions"]:
if String(raw_definition[&"guest_type_id"]) == catalog_id:
raw_definition[&"wealth_min"] = int(raw_definition[&"wealth_min"]) + 1
break
corruptions.append({&"label": "catalog Guest definition", &"snapshot": definition})
var progression: Dictionary = migrated.duplicate(true)
progression[&"systems"][&"runtime"][&"progression"][&"current_rank"] = 2
corruptions.append({&"label": "Progression history", &"snapshot": progression})
var rank: Dictionary = migrated.duplicate(true)
rank[&"game_state"][&"world_tree_rank"] = 2
corruptions.append({&"label": "GameState rank", &"snapshot": rank})
var bounds: Dictionary = migrated.duplicate(true)
bounds[&"systems"][&"runtime"][&"world"][&"bounds"][&"max_x"] = 13
corruptions.append({&"label": "World rank bounds", &"snapshot": bounds})
var hired_manifest: Dictionary = migrated.duplicate(true)
hired_manifest[&"systems"][&"runtime"][&"hired_staff_candidate_ids"] = ["not_a_candidate"]
corruptions.append({&"label": "hired candidate manifest", &"snapshot": hired_manifest})
for corruption: Dictionary in corruptions:
live_before = _runtime.create_snapshot()
_expect(
not _runtime.restore_snapshot(corruption[&"snapshot"])
and _runtime.create_snapshot() == live_before,
"%s tamper is rejected atomically" % corruption[&"label"]
)
func _test_twenty_four_hour_replay() -> void:
_reset_runtime(82_007)
var spawn: CommandResult = _runtime._execute_spawn_guest(_direct_command(
&"spawn_guest",
{
&"guest_id": &"replay_guest",
&"guest_type_id": _runtime.get_mvp_guest_definition_ids()[0],
&"gold": 100,
&"options": {&"current_cell": Vector3i.ZERO, &"planned_exit_at": _clock.absolute_minute + 2_000},
}
))
var hire: CommandResult = _runtime._execute_hire_staff_candidate(_direct_command(
&"hire_staff_candidate", {&"candidate_id": &"staff_akane", &"current_cell": Vector3i.ZERO}
))
_expect(spawn.is_success() and hire.is_success(), "24-hour replay fixture creates catalog Guest and Staff")
var start: Dictionary = _runtime.create_snapshot()
var second_clock = load("res://autoload/game_clock.gd").new()
var second_state = load("res://autoload/game_state.gd").new()
var second_runtime = load("res://autoload/simulation_runtime.gd").new()
second_clock.reset(1, 6, 0)
second_state.reset()
second_runtime.initialize(second_clock, second_state, 82_007)
second_clock.set_paused(true)
_expect(second_runtime.restore_snapshot(start), "24-hour replay clone restores exact v4 start")
_clock.set_paused(false)
second_clock.set_paused(false)
_clock.advance_minutes(1_440)
second_clock.advance_minutes(1_440)
_expect(
SimulationDigest.compute(_runtime.create_snapshot()) \
== SimulationDigest.compute(second_runtime.create_snapshot()),
"catalog, Staff hire, Progression, and six-Need state replay exactly for 24 hours"
)
second_runtime.free()
second_clock.free()
second_state.free()
func _direct_command(command_type: StringName, payload: Dictionary) -> SimulationCommand:
_direct_command_id += 1
return SimulationCommand.new(
_direct_command_id,
_clock.absolute_minute,
_clock.absolute_minute,
100,
command_type,
&"test",
&"",
payload,
&""
)
func _expect(condition: bool, label: String) -> void:
_checks += 1
if condition:
print(" ✓ %s" % label)
return
_failures += 1
push_error(" ✗ %s" % label)
func _test_unique_runtime_protection() -> void:
_reset_runtime(82_017)
var staff_before: Dictionary = _runtime.staff_service.create_snapshot()
var economy_before: Dictionary = _runtime.economy_service.create_snapshot()
for id: StringName in _runtime.mvp_content_catalog.get_unique_character_ids():
var forged: CommandResult = _runtime.submit_command(&"register_staff", {
&"staff_id": id, &"role_id": &"receptionist", &"options": {&"employment_kind": &"FREE_HIRE"}})
_expect(not forged.is_success() and _runtime.staff_service.create_snapshot() == staff_before and _runtime.economy_service.create_snapshot() == economy_before, "reserved unique identity cannot bypass its protected recruitment contract")
# Generic legacy fixture checks UNIQUE behavior without inventing Anri's joining conditions.
var created: CommandResult = _runtime.submit_command(&"register_staff", {
&"staff_id": &"unique_runtime_fixture", &"role_id": &"receptionist",
&"options": {&"employment_kind": &"UNIQUE", &"daily_wage": 75, &"current_cell": Vector3i.ZERO}})
_expect(created.is_success() and _runtime.economy_service.create_snapshot() == economy_before, "unique runtime fixture registers without signing payment")
var report: Dictionary = _runtime.get_staff_management_report()
_expect(report[&"staff"].size() == 1 and report[&"staff"][0][&"daily_wage"] == 0, "normal staff panel report shows effective zero unique wage")
var before: Dictionary = _runtime.create_snapshot()
_expect(not _runtime.staff_service.retire_staff(&"unique_runtime_fixture").is_success() and _runtime.create_snapshot() == before, "unique retirement rejection preserves complete runtime including paths and ledger")
_expect(_runtime.restore_snapshot(before) and _runtime.create_snapshot() == before, "runtime unique snapshot restores exactly")
_expect(_runtime.get_staff_management_report()[&"staff"][0][&"daily_wage"] == 0 and _runtime.staff_service.get_daily_payroll_total() == 0, "restored runtime and UI both retain zero unique upkeep")