extends SceneTree var failures: Array[String] = [] var manager: Node func _initialize() -> void: call_deferred("_run") func _run() -> void: manager = load("res://simulation/SimulationManager.gd").new() root.add_child(manager) var speaker: SimNPC = manager.npcs[0] speaker.position = Vector3.ZERO speaker.hunger = 85.0 for npc in manager.npcs: if npc != speaker: npc.position = Vector3(100.0 + npc.id, 0.0, 0.0) _set_pantry_amount(1.0) _check(manager.get_quest_journal_entries().is_empty(), "Journal starts empty") _check( is_equal_approx( manager.economy.withdraw_to_inventory(speaker, SimulationIds.RESOURCE_FOOD, 1.0), 1.0 ), "A real last-food withdrawal creates the evidence" ) var situations: Array[SituationStateRecord] = manager.get_active_situations() _check(situations.size() == 1, "The exact shortage evidence opens one world situation") if situations.is_empty(): _finish() return var situation := situations[0] _check( manager.event_knowledge_system.knows_event(speaker.id, situation.get_trigger_event_id()), "The performing NPC knows the trigger fact" ) _check( not manager.event_knowledge_system.knows_event( SimulationIds.PLAYER_ACTOR_ID, situation.get_trigger_event_id() ), "The player does not know the situation before conversation" ) _check(manager.get_quest_journal_entries().is_empty(), "Unknown situations stay out of journal") manager.speed_index = 5 var conversation_id: StringName = manager.begin_player_conversation(speaker.id) _check(not conversation_id.is_empty(), "The informed NPC can begin generated dialogue") _check( manager.speed_index == 2 and manager.is_dialogue_active(), "Dialogue runs simulation at 1x" ) _check( manager.event_knowledge_system.knows_event( SimulationIds.PLAYER_ACTOR_ID, situation.get_trigger_event_id() ), "Speaking communicates the exact trigger fact to the player" ) _check(manager.get_quest_journal_entries().size() == 1, "Discovery projects into the journal") var turn: ConversationTurn = manager.conversation_service.get_turn(conversation_id) _check(turn != null and _has_intent(turn, ConversationIntentIds.OFFER_HELP), "Help is semantic") _check(_has_intent(turn, ConversationIntentIds.DECLINE), "Declining remains available") _check( _has_intent(turn, ConversationIntentIds.ASK_WHO_ELSE), "Alternative helpers can be asked" ) var offer := _option_for_intent(turn, ConversationIntentIds.OFFER_HELP) var offered: ConversationSelectionResult = manager.select_player_conversation_option( conversation_id, offer.get_option_id(), turn.get_revision() ) _check(offered.was_accepted(), "Offering help advances the deterministic conversation") _check(manager.get_active_commitments().size() == 1, "Offering help creates one commitment") turn = offered.get_turn() var accept := _option_for_intent(turn, ConversationIntentIds.ACCEPT) var accepted: ConversationSelectionResult = manager.select_player_conversation_option( conversation_id, accept.get_option_id(), turn.get_revision() ) _check(accepted.was_accepted(), "Accepting the offer records a semantic act") _check(manager.get_active_commitments().size() == 1, "NPC acknowledgement cannot duplicate it") _check( ( manager.get_quest_journal_entries()[0].get_selected_alternative_id() == SituationSystem.ALTERNATIVE_RESTOCK ), "Acceptance selects a real resolution alternative without copying progress" ) var saved: String = manager.serialize_state() var canonical_checksum: String = JSON.stringify(JSON.parse_string(saved)).sha256_text() manager.end_player_conversation(conversation_id) _check(manager.speed_index == 5, "Closing dialogue restores the prior speed") var restored: Node = load("res://simulation/SimulationManager.gd").new() root.add_child(restored) _check(restored.restore_state_from_json(saved), "Mid-commitment save reloads") var restored_serialized: String = restored.serialize_state() var restored_checksum: String = ( JSON.stringify(JSON.parse_string(restored_serialized)).sha256_text() ) if restored_checksum != canonical_checksum: var saved_data: Dictionary = JSON.parse_string(saved) var restored_data: Dictionary = JSON.parse_string(restored_serialized) print("[TEST] checksum mismatch sections: ", _different_keys(saved_data, restored_data)) _check(restored_checksum == canonical_checksum, "Mid-commitment continuation is deterministic") _check(restored.get_active_commitments().size() == 1, "The social commitment persists") restored.player_system.add_carried(SimulationIds.RESOURCE_FOOD, 1.0) _check( is_equal_approx(restored.deposit_player_inventory(SimulationIds.RESOURCE_FOOD), 1.0), "The player resolves the situation with an ordinary real deposit" ) var restored_situation: SituationStateRecord = restored.situation_system.get_by_id( situation.get_situation_id() ) var restored_commitment: CommitmentStateRecord = restored.commitment_system.get_all_sorted()[0] _check( restored_situation.get_status() == SituationStateRecord.STATUS_RESOLVED, "The exact deposit event resolves the world situation" ) _check( ( restored_commitment.get_status() == CommitmentStateRecord.STATUS_FULFILLED and ( restored_commitment.get_cause_event_id() == restored_situation.get_resolution_event_id() ) ), "That same event fulfills the commitment exactly once" ) _check( ( restored.get_quest_journal_entries()[0].get_status() == QuestJournalEntryStateRecord.STATUS_COMPLETED ), "The journal projects the closed world state" ) _check( restored.conversation_history.size() >= 3, "Semantic conversation acts and topics persist, never rendered prose" ) var fulfilled_fact: EconomicEventRecord = restored.commitment_lifecycle.get_fact( restored.event_log, CommitmentLifecycleService.EVENT_FULFILLED, restored_commitment.get_commitment_id() ) _check(fulfilled_fact != null, "Fulfillment records a durable social outcome fact") var player_relationship: RelationshipStateRecord = ( restored.relationship_system.get_relationship(speaker.id, SimulationIds.PLAYER_ACTOR_ID) ) _check( ( player_relationship != null and ( player_relationship.get_last_trust_cause_event_id() == int(fulfilled_fact.data["event_id"]) ) ), "The exact outcome fact causes the relationship consequence" ) _check( SimulationStateRecord.from_json(restored.serialize_state()) != null, "Fulfilled commitment facts and relationship causes remain schema-valid" ) var later_conversation: StringName = restored.begin_player_conversation(speaker.id) var later_turn: ConversationTurn = restored.conversation_service.get_turn(later_conversation) _check( later_turn != null and later_turn.get_act().get_intent_id() == ConversationIntentIds.THANK, "Later dialogue reflects the fulfilled commitment" ) _check( ( StringName("outcome_event_%d" % restored_situation.get_resolution_event_id()) in later_turn.get_reason_trace() ), "Later dialogue traces the exact real deposit event" ) restored.end_player_conversation(later_conversation) restored.free() manager.free() _finish() func _set_pantry_amount(amount: float) -> void: var pantry: StorageStateRecord = manager.get_pantry() pantry.withdraw(SimulationIds.RESOURCE_FOOD, pantry.get_amount(SimulationIds.RESOURCE_FOOD)) pantry.deposit(SimulationIds.RESOURCE_FOOD, amount) manager.economy.sync_resource(SimulationIds.RESOURCE_FOOD) func _option_for_intent(turn: ConversationTurn, intent_id: StringName) -> ConversationOption: for option in turn.get_options(): if option.get_intent_id() == intent_id: return option return null func _has_intent(turn: ConversationTurn, intent_id: StringName) -> bool: return _option_for_intent(turn, intent_id) != null func _check(condition: bool, message: String) -> void: if condition: return failures.append(message) push_error("[TEST] " + message) func _different_keys(left: Dictionary, right: Dictionary) -> Array[String]: var differences: Array[String] = [] for key in left: if not right.has(key) or JSON.stringify(left[key]) != JSON.stringify(right[key]): differences.append(String(key)) return differences func _finish() -> void: if failures.is_empty(): print("[TEST] Emergent Jajce slice passed") quit(0) else: quit(1)