extends SceneTree var _checks := 0 var _failures := 0 var _clock: Variant var _state: Variant var _runtime: Variant func _initialize() -> void: call_deferred("_run") func _run() -> void: print("S4: runtime relationship and event integration") _test_threshold_foreground_acknowledgement_and_idempotency() _test_paid_choice_escrow_and_commit() _test_missing_actor_releases_reservation_and_lock() _test_waiting_choice_snapshot_exact_replay() _test_event_ledger_observer_boundaries() _test_paid_choice_attempt_lifecycle() _test_legacy_paid_choice_tokens() _test_paid_reservation_failure_boundaries() _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: int) -> 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(report[&"valid"], "runtime initializes S4 definitions") _expect(_runtime.event_service.get_definition(&"relationship.threshold") != null, "canonical relationship threshold Event is registered") 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_threshold_foreground_acknowledgement_and_idempotency() -> void: _reset_runtime(4_001) _expect(_spawn_guest(&"relation_guest", 150).is_success(), "relationship actor is created through Runtime Command") var created = _runtime.submit_command( &"create_relationship", { &"relationship_id": &"relationship.runtime.threshold", &"actor_a_id": &"player", &"actor_b_id": &"relation_guest", &"options": { &"trust": 35, &"respect": 40, &"affection": 45, &"fear": 5, &"dependence": 10, &"shield_max": 60, &"shield_current": 60, }, }, &"player", &"relation_guest", 80, -1, &"s4.relationship.create.threshold" ) _expect(created.is_success(), "Relationship is created through Runtime Command") var relationship = _runtime.relationship_service.get_relationship(&"relationship.runtime.threshold") _expect(relationship != null and relationship.actor_a_id == &"player" and relationship.actor_b_id == &"relation_guest", "Runtime preserves normalized relationship actors") var changed = _runtime.submit_command( &"change_relationship", { &"relationship_id": relationship.relationship_id, &"metric_id": &"affection", &"delta": 10, }, &"player", relationship.relationship_id, 80, -1, &"s4.relationship.affection.gate" ) _expect(changed.is_success() and changed.details[&"gated_threshold"] == 50, "Affection change reports the 50 threshold gate") _expect(relationship.get_metric(&"affection") == 49, "background calculation cannot cross 50 before Event acknowledgement") _expect(_runtime.relationship_service.get_threshold_candidates().size() == 1, "threshold crossing creates one deterministic relationship candidate") _expect(_runtime.event_service.get_queued_instances().size() == 1, "candidate is projected into EventService without immediate playback") _clock.set_paused(false) _clock.advance_one_minute() var foreground = _runtime.event_service.get_foreground_instance() _expect(foreground != null and foreground.source_event_id == &"relationship.threshold", "relationship candidate starts as the foreground Event") _expect(_clock.paused, "foreground Choice automatically pauses Simulation") _expect(_runtime.event_service.get_actor_locks().size() == 2, "foreground threshold Event locks both relationship actors") var instance_id: StringName = foreground.event_instance_id var choice_instance_id: StringName = foreground.choice_instance_id var acknowledged = _runtime.submit_command( &"submit_event_choice", { &"event_instance_id": instance_id, &"choice_instance_id": choice_instance_id, &"choice_id": &"acknowledge", }, &"player", instance_id, 100, -1, &"s4.threshold.acknowledge.first" ) _expect(acknowledged.is_success(), "foreground acknowledgement resolves through Runtime Command") _expect(relationship.get_metric(&"affection") == 50, "acknowledged threshold Event applies the gated Affection point") _expect(_runtime.relationship_service.get_threshold_candidates().is_empty(), "resolved Event consumes its relationship candidate") _expect(_runtime.event_service.get_actor_locks().is_empty() and _runtime.event_service.get_foreground_instance() == null, "resolved Event releases every Actor Lock") _expect(not _clock.paused, "Runtime resumes when no foreground Event remains") _clock.set_paused(true) var replayed = _runtime.submit_command( &"submit_event_choice", { &"event_instance_id": instance_id, &"choice_instance_id": choice_instance_id, &"choice_id": &"acknowledge", }, &"player", instance_id, 100, -1, &"s4.threshold.acknowledge.transport-retry" ) _expect(replayed.is_success() and replayed.is_replay, "same choice_instance_id returns EventService idempotent replay") _expect(relationship.get_metric(&"affection") == 50, "choice replay does not apply relationship Actions twice") _expect(_count_domain_events(&"EVENT_CHOICE_RESOLVED", instance_id) == 1, "choice replay emits no duplicate resolution Domain Event") _expect(_runtime.relationship_service.validate_invariants()[&"ok"], "threshold flow preserves Relationship invariants") _expect(_runtime.event_service.validate_invariants()[&"ok"], "threshold flow preserves Event and Actor Lock invariants") func _test_paid_choice_escrow_and_commit() -> void: _reset_runtime(4_002) var registered = _register_paid_event_definition(&"event.paid.commit", 125) _expect(registered.is_success(), "paid EventDefinition registers through Runtime Command") var enqueued = _runtime.submit_command( &"enqueue_event", { &"event_id": &"event.paid.commit", &"actor_ids": [&"player"], &"options": {&"event_instance_id": &"event_instance.paid.commit"}, }, &"player", &"event_instance.paid.commit", 60, -1, &"s4.event.paid.enqueue" ) _expect(enqueued.is_success(), "paid Event candidate enters Runtime queue") _start_next_foreground_minute() var foreground = _runtime.event_service.get_foreground_instance() _expect(foreground != null and foreground.event_instance_id == &"event_instance.paid.commit", "paid Event reaches foreground Choice") var cash_before: int = _runtime.economy_service.get_balance(&"PLAYER_CASH") var reserved = _runtime.submit_command( &"reserve_event_choice_cost", { &"event_instance_id": foreground.event_instance_id, &"choice_id": &"purchase", }, &"player", foreground.event_instance_id, 100, -1, &"s4.event.paid.reserve" ) var escrow_account := &"EVENT_ESCROW:event_instance.paid.commit" _expect(reserved.is_success(), "paid Choice reserves Cost through Runtime boundary") _expect(_runtime.economy_service.get_balance(&"PLAYER_CASH") == cash_before - 125, "Gold leaves PLAYER_CASH exactly once at reservation") _expect(_runtime.economy_service.get_balance(escrow_account) == 125, "reserved Gold is held in Event-specific escrow") _expect(_state.get_resource(&"gold") == cash_before - 125, "GameState Gold projection follows escrow transfer") var committed = _runtime.submit_command( &"submit_event_choice", { &"event_instance_id": foreground.event_instance_id, &"choice_instance_id": foreground.choice_instance_id, &"choice_id": &"purchase", }, &"player", foreground.event_instance_id, 100, -1, &"s4.event.paid.commit" ) _expect(committed.is_success(), "paid Choice commits after revalidation") _expect(_runtime.economy_service.get_balance(escrow_account) == 0, "committed Event leaves no Gold in escrow") _expect(_runtime.economy_service.get_balance(&"OPERATING_EXPENSE") == 125, "escrow Gold posts to the configured expense account") _expect(_runtime.economy_service.get_balance(&"PLAYER_CASH") == cash_before - 125, "Cost commit never charges PLAYER_CASH a second time") _expect(_runtime.event_service.has_flag(&"paid_choice_completed"), "paid Choice Action applies only after Cost reservation") _expect(_runtime.economy_service.validate_ledger()[&"ok"], "escrow reserve and commit remain double-entry balanced") _expect(_runtime.event_service.validate_invariants()[&"ok"], "paid Choice completion preserves Event invariants") func _test_missing_actor_releases_reservation_and_lock() -> void: _reset_runtime(4_003) var registered_staff = _runtime.submit_command( &"register_staff", { &"staff_id": &"temporary_actor", &"role_id": &"service", &"options": {}, }, &"player", &"temporary_actor", 80, -1, &"s4.actor.temporary.register" ) _expect(registered_staff.is_success(), "temporary foreground actor registers through Runtime") _expect(_register_paid_event_definition(&"event.actor.missing", 80).is_success(), "missing-actor fixture EventDefinition registers") var enqueued = _runtime.submit_command( &"enqueue_event", { &"event_id": &"event.actor.missing", &"actor_ids": [&"temporary_actor"], &"options": {&"event_instance_id": &"event_instance.actor.missing"}, }, &"player", &"event_instance.actor.missing", 60, -1, &"s4.actor.missing.enqueue" ) _expect(enqueued.is_success(), "missing-actor fixture enters Event queue") _start_next_foreground_minute() var foreground = _runtime.event_service.get_foreground_instance() _expect(foreground != null and _runtime.event_service.get_actor_locks().has(&"temporary_actor"), "foreground Event holds temporary actor lock") var cash_before: int = _runtime.economy_service.get_balance(&"PLAYER_CASH") var reserved = _runtime.submit_command( &"reserve_event_choice_cost", { &"event_instance_id": foreground.event_instance_id, &"choice_id": &"purchase", }, &"player", foreground.event_instance_id, 100, -1, &"s4.actor.missing.reserve" ) _expect(reserved.is_success() and _runtime.economy_service.get_balance(&"PLAYER_CASH") == cash_before - 80, "missing-actor fixture owns reserved Gold") _expect(_runtime.staff_service.remove_staff(&"temporary_actor", &"TEST_REMOVED", true, _clock.absolute_minute).is_success(), "actor disappears through StaffService lifecycle") _clock.set_paused(false) _clock.advance_one_minute() var instance = _runtime.event_service.get_instance(&"event_instance.actor.missing") _expect(instance != null and instance.state == EventInstance.State.CANCELLED, "Runtime audit cancels Event whose actor disappeared") _expect(_runtime.event_service.get_actor_locks().is_empty() and _runtime.event_service.get_foreground_instance() == null, "actor disappearance releases Lock and foreground ownership") _expect(_runtime.economy_service.get_balance(&"EVENT_ESCROW:event_instance.actor.missing") == 0, "actor disappearance empties Event escrow") _expect(_runtime.economy_service.get_balance(&"PLAYER_CASH") == cash_before and _state.get_resource(&"gold") == cash_before, "actor disappearance refunds reserved Gold exactly once") _expect(_runtime.economy_service.get_balance(&"OPERATING_EXPENSE") == 0, "cancelled missing-actor Event never commits Cost") _expect(_runtime.economy_service.validate_ledger()[&"ok"], "missing-actor refund preserves ledger invariants") _expect(_runtime.event_service.validate_invariants()[&"ok"], "missing-actor recovery preserves Event invariants") func _test_waiting_choice_snapshot_exact_replay() -> void: _reset_runtime(4_004) _expect(_spawn_guest(&"snapshot_relation_guest", 175).is_success(), "snapshot relationship actor is created") var relationship_id := &"relationship.runtime.snapshot" var created = _runtime.submit_command( &"create_relationship", { &"relationship_id": relationship_id, &"actor_a_id": &"player", &"actor_b_id": &"snapshot_relation_guest", &"options": {&"affection": 45, &"shield_max": 50, &"shield_current": 50}, }, &"player", relationship_id, 80, -1, &"s4.snapshot.relationship.create" ) _expect(created.is_success(), "snapshot Relationship registers") var gated = _runtime.submit_command( &"change_relationship", {&"relationship_id": relationship_id, &"metric_id": &"affection", &"delta": 10}, &"player", relationship_id, 80, -1, &"s4.snapshot.relationship.gate" ) _expect(gated.is_success(), "snapshot scenario creates threshold Event candidate") _start_next_foreground_minute() var foreground = _runtime.event_service.get_foreground_instance() _expect(foreground != null and _clock.paused, "snapshot is captured while foreground Choice is waiting") var instance_id: StringName = foreground.event_instance_id var choice_instance_id: StringName = foreground.choice_instance_id # Save capture occurs after tick completion, including the incremented Kernel # snapshot_version; this is the exact boundary replayed below. var waiting_snapshot: Dictionary = _runtime.create_snapshot() var waiting_digest: String = SimulationDigest.compute(waiting_snapshot) _expect(waiting_digest.length() == 64, "waiting-Choice snapshot produces a stable digest") var first_resolution = _runtime.submit_command( &"submit_event_choice", { &"event_instance_id": instance_id, &"choice_instance_id": choice_instance_id, &"choice_id": &"acknowledge", }, &"player", instance_id, 100, -1, &"s4.snapshot.choice.resolve" ) _expect(first_resolution.is_success(), "waiting Choice resolves before rewind") var final_digest: String = _runtime.latest_digest _expect(_runtime.relationship_service.get_relationship(relationship_id).get_metric(&"affection") == 50, "first timeline reaches acknowledged threshold") var restored_ok: bool = _runtime.restore_snapshot(waiting_snapshot) _expect(restored_ok, "Runtime restores a snapshot containing Choice token and Actor Locks") _expect(_runtime.latest_digest == waiting_digest, "waiting-Choice restore reproduces exact digest") var restored_foreground = _runtime.event_service.get_foreground_instance() _expect(restored_foreground != null and restored_foreground.event_instance_id == instance_id, "restored Runtime recovers the same foreground Event") _expect(restored_foreground.choice_instance_id == choice_instance_id and _runtime.event_service.get_actor_locks().size() == 2, "Choice token and Actor Locks restore exactly") _expect(_clock.paused and _runtime.relationship_service.get_relationship(relationship_id).get_metric(&"affection") == 49, "restore returns to pre-acknowledgement paused relationship state") var replay_resolution = _runtime.submit_command( &"submit_event_choice", { &"event_instance_id": instance_id, &"choice_instance_id": choice_instance_id, &"choice_id": &"acknowledge", }, &"player", instance_id, 100, -1, &"s4.snapshot.choice.resolve" ) _expect(replay_resolution.is_success(), "restored Choice accepts the same deterministic Command") _expect(_runtime.latest_digest == final_digest, "Choice replay after restore reproduces exact final digest") _expect(_runtime.relationship_service.get_relationship(relationship_id).get_metric(&"affection") == 50, "replayed timeline reaches threshold once") _expect(_runtime.relationship_service.validate_invariants()[&"ok"], "restored relationship state satisfies invariants") _expect(_runtime.event_service.validate_invariants()[&"ok"], "restored Event queue and Lock state satisfy invariants") _expect(_runtime.economy_service.validate_ledger()[&"ok"], "snapshot replay preserves economic invariants") func _spawn_guest(guest_id: StringName, gold: int) -> CommandResult: return _runtime.submit_command( &"spawn_guest", { &"guest_id": guest_id, &"guest_type_id": &"traveler", &"gold": gold, }, &"player", guest_id, 50, -1, StringName("s4.guest.spawn.%s" % guest_id) ) func _register_paid_event_definition(event_id: StringName, gold_cost: int) -> CommandResult: return _runtime.submit_command( &"register_event_definition", {&"definition": { &"event_id": event_id, &"category": &"RELATIONSHIP", &"priority": 70, &"foreground": true, &"transaction_policy": &"ROLLBACK_ALL", &"missing_actor_policy": &"CANCEL", &"content_rating": &"GENERAL", &"choices": [{ &"choice_id": &"purchase", &"text_key": StringName("event.%s.purchase" % event_id), &"cost": {&"gold": gold_cost}, &"actions": [{ &"action_id": &"paid_choice_flag", &"type": &"SET_FLAG", &"payload": {&"flag_id": &"paid_choice_completed"}, }], }], }}, &"player", event_id, 60, -1, StringName("s4.event.definition.%s" % event_id) ) func _start_next_foreground_minute() -> void: _clock.set_paused(false) _clock.advance_one_minute() func _count_domain_events(event_type: StringName, entity_id: StringName) -> int: var count := 0 for event in _runtime.domain_events.recent_events(): if event.event_type == event_type and ( entity_id in event.entity_ids or StringName(event.payload.get(&"event_instance_id", &"")) == entity_id ): count += 1 return count func _expect(condition: bool, label: String) -> void: _checks += 1 if condition: print(" ✓ %s" % label) return _failures += 1 push_error(" ✗ %s" % label) func _test_event_ledger_observer_boundaries() -> void: var cases: Array[Dictionary] = [ {&"name":&"success",&"policy":&"ROLLBACK_ALL",&"amount":1000,&"cash":3000,&"count":2,&"ok":true}, {&"name":&"rollback",&"policy":&"ROLLBACK_ALL",&"amount":3000,&"cash":5000,&"count":0,&"ok":false}, {&"name":&"skip",&"policy":&"SKIP_FAILED",&"amount":3000,&"cash":2000,&"count":1,&"ok":true}, {&"name":&"branch",&"policy":&"BRANCH_FAILURE",&"amount":3000,&"cash":4000,&"count":1,&"ok":true}, {&"name":&"auto_success",&"policy":&"ROLLBACK_ALL",&"amount":1000,&"cash":3000,&"count":2,&"ok":true,&"auto":true}, {&"name":&"auto_rollback",&"policy":&"ROLLBACK_ALL",&"amount":3000,&"cash":5000,&"count":0,&"ok":false,&"auto":true}, {&"name":&"cost_success",&"policy":&"ROLLBACK_ALL",&"amount":1000,&"cash":2900,&"count":4,&"ok":true,&"cost":100}, {&"name":&"cost_rollback",&"policy":&"ROLLBACK_ALL",&"amount":3000,&"cash":5000,&"count":2,&"ok":false,&"cost":1000}, ] for row: Dictionary in cases: _reset_runtime(981009) var name := String(row[&"name"]) var event_id := StringName("observer."+name) var actions: Array[Dictionary] = [] for id: StringName in [&"first", &"second"]: actions.append({&"action_id":id,&"type":&"ADD_LEDGER_ENTRY",&"payload":{&"from_account":&"PLAYER_CASH",&"to_account":_runtime.OPERATING_EXPENSE_ACCOUNT,&"amount":row[&"amount"]}}) var automatic: bool = row.get(&"auto",false) var definition := {&"event_id":event_id,&"category":&"FLAVOR",&"priority":70,&"foreground":not automatic,&"transaction_policy":row[&"policy"],&"failure_actions":[{&"action_id":&"branch",&"type":&"ADD_LEDGER_ENTRY",&"payload":{&"from_account":&"PLAYER_CASH",&"to_account":_runtime.OPERATING_EXPENSE_ACCOUNT,&"amount":1000}}]} if automatic: definition[&"automatic_actions"]=actions else: definition[&"choices"]=[{&"choice_id":&"choose",&"text_key":&"observer.choose",&"cost":{&"gold":row.get(&"cost",0)},&"actions":actions}] _expect(_runtime.submit_command(&"register_event_definition",{&"definition":definition}).is_success(),name+" public registration") _expect(_runtime.submit_command(&"enqueue_event",{&"event_id":event_id,&"actor_ids":[&"player"]}).is_success(),name+" public enqueue") var notifications: Array[Dictionary]=[] _runtime.economy_service.transaction_posted.connect(func(id: StringName, entries: Array) -> void: var copied: Array[Dictionary]=[] for entry: LedgerEntry in entries:copied.append(entry.to_dictionary()) notifications.append({&"id":id,&"entries":copied,&"cash":_runtime.economy_service.get_balance(&"PLAYER_CASH"),&"mirror":_state.get_resource(&"gold")})) _start_next_foreground_minute() var payload: Dictionary={} var result: CommandResult if not automatic: var foreground: EventInstance=_runtime.event_service.get_foreground_instance() _expect(foreground!=null,name+" real foreground choice") if foreground==null:continue payload={&"event_instance_id":foreground.event_instance_id,&"choice_instance_id":foreground.choice_instance_id,&"choice_id":&"choose"} result=_runtime.submit_command(&"submit_event_choice",payload) _expect(result.is_success()==bool(row[&"ok"]),name+" actual choice outcome") _expect(_runtime.economy_service.get_balance(&"PLAYER_CASH")==int(row[&"cash"])and _state.get_resource(&"gold")==int(row[&"cash"]),name+" final ledger/mirror exact") _expect(notifications.size()==int(row[&"count"]),name+" only surviving receipts notified once") var seen: Dictionary={} for notification: Dictionary in notifications: var id: StringName=notification[&"id"] var entries: Array[Dictionary]=[] for entry: LedgerEntry in _runtime.economy_service.get_transaction_entries(id):entries.append(entry.to_dictionary()) _expect(not seen.has(id)and var_to_bytes(entries)==var_to_bytes(notification[&"entries"]),name+" notified receipt exists exactly in final ledger") _expect(notification[&"cash"]==int(row[&"cash"])and notification[&"mirror"]==int(row[&"cash"]),name+" observer sees only final authoritative state") seen[id]=true _expect(_runtime.economy_service.notification_scope_depth()==0,name+" all nested scopes closed") if not automatic: _clock.set_paused(true) var economy_before: Dictionary=_runtime.economy_service.create_snapshot() var count_before: int=notifications.size() var replay: CommandResult=_runtime.submit_command(&"submit_event_choice",payload) _expect(replay.is_replay and replay.is_success()==bool(row[&"ok"]),name+" cached choice replays its original outcome") _expect(var_to_bytes(economy_before)==var_to_bytes(_runtime.economy_service.create_snapshot())and notifications.size()==count_before,name+" replay neither posts nor notifies twice") func _lifecycle_event(name: StringName, fail_a: bool) -> EventInstance: var actions: Array[Dictionary] = [] if fail_a: for id: StringName in [&"first", &"second"]: actions.append({&"action_id":id,&"type":&"ADD_LEDGER_ENTRY",&"payload":{&"from_account":&"PLAYER_CASH",&"to_account":_runtime.OPERATING_EXPENSE_ACCOUNT,&"amount":3000}}) var definition := {&"event_id":name,&"category":&"FLAVOR",&"priority":70,&"foreground":true,&"transaction_policy":&"ROLLBACK_ALL",&"choices":[{&"choice_id":&"a",&"text_key":&"lifecycle.a",&"cost":{&"gold":100},&"actions":actions},{&"choice_id":&"b",&"text_key":&"lifecycle.b",&"cost":{&"gold":200},&"actions":[]}]} _expect(_runtime.submit_command(&"register_event_definition",{&"definition":definition}).is_success(),"lifecycle definition registers") _expect(_runtime.submit_command(&"enqueue_event",{&"event_id":name,&"actor_ids":[&"player"],&"options":{&"event_instance_id":name}}).is_success(),"lifecycle event queues") _clock.advance_minutes(1) var event: EventInstance = _runtime.event_service.get_foreground_instance() _expect(event != null and event.event_instance_id == name,"lifecycle actual foreground") return event func _lifecycle_reserve(event: EventInstance, choice: StringName, key: StringName) -> CommandResult: return _runtime.submit_command(&"reserve_event_choice_cost",{&"event_instance_id":event.event_instance_id,&"choice_id":choice},&"player",&"",100,-1,key) func _lifecycle_choose(event: EventInstance, choice: StringName, key: StringName) -> CommandResult: return _runtime.submit_command(&"submit_event_choice",{&"event_instance_id":event.event_instance_id,&"choice_instance_id":event.choice_instance_id,&"choice_id":choice},&"player",&"",100,-1,key) func _test_paid_choice_attempt_lifecycle() -> void: _reset_runtime(4_107) var event := _lifecycle_event(&"multi_cost",false) _expect(_lifecycle_reserve(event,&"a",&"multi.a").is_success(),"first paid choice reserves") _expect(_lifecycle_reserve(event,&"b",&"multi.b").is_success(),"distinct affordable choice reserves independently") var a: Dictionary = event.reserved_costs[&"a"][&"token"] var b: Dictionary = event.reserved_costs[&"b"][&"token"] _expect(a[&"reservation_id"] != b[&"reservation_id"],"actual paid reservations have distinct persistent identities") _expect(_runtime.economy_service.get_balance(&"PLAYER_CASH") == 4700 and _runtime.economy_service.get_balance(&"EVENT_ESCROW:multi_cost") == 300,"both paid reservations in real ledger") var before: Dictionary = _runtime.economy_service.create_snapshot() _expect(_lifecycle_reserve(event,&"a",&"multi.a.again").is_success(),"existing reservation remains replayable") _expect(var_to_bytes(before) == var_to_bytes(_runtime.economy_service.create_snapshot()),"existing reservation never double debits") var saved: Dictionary = _runtime.create_snapshot() _reset_runtime(4_108) _expect(_runtime.restore_snapshot(saved) and var_to_bytes(_runtime.create_snapshot()) == var_to_bytes(saved),"entire multi-reservation snapshot restores exactly") event = _runtime.event_service.get_foreground_instance() _expect(_lifecycle_choose(event,&"b",&"multi.choose.b").is_success(),"restored B commits and unused A refunds") _expect(event.state == EventInstance.State.COMPLETED and event.reserved_costs.is_empty(),"restored paid event completes with no escrow tokens") _expect(_runtime.economy_service.get_balance(&"PLAYER_CASH") == 4800 and _runtime.economy_service.get_balance(&"EVENT_ESCROW:multi_cost") == 0,"selected200G only charged after refund100G") _expect(_runtime.id_generator.get_counter(&"event_cost") == 2,"persisted reservation ID counter restored") _reset_runtime(4_109) event = _lifecycle_event(&"retry_cost",true) var old_choice := event.choice_instance_id var failed := _lifecycle_choose(event,&"a",&"retry.a") _expect(not failed.is_success() and event.state == EventInstance.State.WAITING_CHOICE,"ordinary failed action remains waiting after rollback") _expect(event.choice_instance_id != old_choice,"fully rolled back attempt gets a fresh active choice token") _expect(_runtime.economy_service.get_balance(&"PLAYER_CASH") == 5000 and event.reserved_costs.is_empty(),"failed attempt returns actual funds") before = _runtime.create_snapshot() var replay: CommandResult = _runtime.event_service.submit_choice(event.event_instance_id,old_choice,&"a",_clock.absolute_minute) _expect(replay.is_replay and not replay.is_success() and var_to_bytes(before) == var_to_bytes(_runtime.create_snapshot()),"old failed attempt retains whole replay no-op") _expect(_lifecycle_reserve(event,&"a",&"retry.reserve").is_success(),"same affordable choice can reserve after a complete refund") _expect(_runtime.economy_service.get_balance(&"PLAYER_CASH") == 4900,"new retry reservation physically charges once") _expect(_lifecycle_choose(event,&"b",&"retry.choose.b").is_success(),"fresh different choice never replays previous failure") _expect(_runtime.economy_service.get_balance(&"PLAYER_CASH") == 4800 and event.state == EventInstance.State.COMPLETED,"retry B pays200G and refunds unused A") _expect(event.reserved_costs.is_empty() and _runtime.economy_service.get_balance(&"EVENT_ESCROW:retry_cost") == 0,"retry leaves no unpaid or unused reservations") _expect(_runtime.id_generator.get_counter(&"event_cost") == 3,"successful new reservations advance only their existing ID namespace") func _test_legacy_paid_choice_tokens() -> void: for mode: StringName in [&"commit", &"cancel"]: _reset_runtime(4_110) var name := StringName("legacy_cost_"+mode) var event := _lifecycle_event(name,false) # Reproduce the actual old three-field token and instance-level ledger key. _runtime.event_service.configure_callbacks( Callable(_runtime,"_event_actor_exists"),Callable(_runtime,"_execute_event_action_boundary"), func(cost: Dictionary, context: Dictionary) -> Dictionary: var id := StringName(context[&"event_instance_id"]) var escrow := StringName("EVENT_ESCROW:"+String(id)) _runtime.economy_service.register_account(escrow) var result: CommandResult = _runtime.economy_service.transfer(&"PLAYER_CASH",escrow,int(cost[&"gold"]),_clock.absolute_minute,&"EVENT_COST_RESERVED",id,StringName("event.cost.reserve."+String(id))) return {&"ok":result.is_success(),&"token":{&"event_instance_id":id,&"cost":cost.duplicate(true),&"escrow_account":escrow}}, Callable(_runtime,"_release_event_cost"),Callable(_runtime,"_commit_event_cost"),Callable(_runtime,"_event_entity_exists"),Callable(_runtime,"_event_path_exists") ) _expect(_lifecycle_reserve(event,&"a",&"legacy.reserve").is_success(),"actual legacy100G reservation") _expect(not event.reserved_costs[&"a"][&"token"].has(&"reservation_id"),"legacy token retains exactly old representation") var saved: Dictionary = _runtime.create_snapshot() _reset_runtime(4_111) _expect(_runtime.restore_snapshot(saved) and var_to_bytes(_runtime.create_snapshot()) == var_to_bytes(saved),"legacy cost token whole snapshot restores unchanged") event = _runtime.event_service.get_foreground_instance() if mode == &"commit": _expect(_lifecycle_choose(event,&"a",&"legacy.choose").is_success(),"restored legacy cost commits via old key") else: _expect(_runtime.event_service.cancel_event(event.event_instance_id).is_success(),"restored legacy cost cancels via old refund key") _expect(_runtime.economy_service.get_balance(&"PLAYER_CASH") == (4900 if mode == &"commit" else 5000),"legacy cash exact after commit or refund") _expect(_runtime.economy_service.get_balance(StringName("EVENT_ESCROW:"+String(name))) == 0 and event.reserved_costs.is_empty(),"legacy escrow and token cleared once") _expect(_runtime.id_generator.get_counter(&"event_cost") == 0,"legacy restore never invents a new reservation ID") func _test_paid_reservation_failure_boundaries() -> void: _reset_runtime(4_112) var event := _lifecycle_event(&"reserve_failure",false) var receipts: Array[Dictionary] = [] _runtime.economy_service.transaction_posted.connect(func(id: StringName, entries: Array) -> void: var copied: Array[Dictionary] = [] for entry: LedgerEntry in entries: copied.append(entry.to_dictionary()) receipts.append({&"id":id,&"entries":copied})) var choice: EventChoice = _runtime.event_service.get_definition(event.source_event_id).get_choice(&"a") choice.cost = {&"gold":6000} var ledger_before: Dictionary = _runtime.economy_service.create_snapshot() _expect(not _lifecycle_reserve(event,&"a",&"unfunded.gold").is_success(),"unaffordable gold reserve rejects") _expect(var_to_bytes(ledger_before) == var_to_bytes(_runtime.economy_service.create_snapshot()) and _state.get_resource(&"gold") == 5000,"gold reserve failure retains full ledger and mirror") _expect(_runtime.id_generator.get_counter(&"event_cost") == 0 and event.reserved_costs.is_empty(),"failed gold reserve consumes no cost identity or token") var mana_before: int = _state.get_resource(&"mana") choice.cost = {&"gold":100,&"mana":mana_before+1} _expect(not _lifecycle_reserve(event,&"a",&"unfunded.mixed").is_success(),"mixed resource reserve rejects after real gold transfer") _expect(var_to_bytes(ledger_before) == var_to_bytes(_runtime.economy_service.create_snapshot()),"mixed resource failure reverses the entire real ledger") _expect(_state.get_resource(&"gold") == 5000 and _state.get_resource(&"mana") == mana_before,"mixed cost failure retains all resources") _expect(receipts.is_empty(),"rolled-back public reserve never publishes a ghost receipt") _expect(_runtime.economy_service.notification_scope_depth() == 0 and _runtime.id_generator.get_counter(&"event_cost") == 0 and event.reserved_costs.is_empty(),"mixed reserve closes scopes and restores cost identity") _reset_runtime(4_113) event = _lifecycle_event(&"commit_retry",false) var old_choice := event.choice_instance_id _runtime.event_service._cost_committer = func(_token: Variant, _context: Dictionary) -> Dictionary: return {&"ok":false,&"error":"explicit commit refusal"} var result := _lifecycle_choose(event,&"a",&"commit.refused") _expect(not result.is_success() and event.state == EventInstance.State.WAITING_CHOICE,"recoverable commit failure remains waiting") _expect(event.choice_instance_id != old_choice and event.reserved_costs.is_empty(),"fully refunded commit failure advances attempt and clears token") _expect(_runtime.economy_service.get_balance(&"PLAYER_CASH") == 5000 and _state.get_resource(&"gold") == 5000,"commit refusal refunds real gold") var before: Dictionary = _runtime.create_snapshot() var replay: CommandResult = _runtime.event_service.submit_choice(event.event_instance_id,old_choice,&"a",_clock.absolute_minute) _expect(replay.is_replay and not replay.is_success() and var_to_bytes(before) == var_to_bytes(_runtime.create_snapshot()),"old commit failure remains exact replay noop") _runtime.event_service._cost_committer = Callable(_runtime,"_commit_event_cost") _expect(_lifecycle_choose(event,&"b",&"commit.alternative").is_success(),"alternative after refunded commit failure succeeds") _expect(event.state == EventInstance.State.COMPLETED and _runtime.economy_service.get_balance(&"PLAYER_CASH") == 4800,"commit retry finishes and charges B only") _expect(_runtime.economy_service.notification_scope_depth() == 0 and _runtime.id_generator.get_counter(&"event_cost") == 2,"commit retry closes scopes with persistent distinct identities")