extends GutTest const MANAGER_SCRIPT := preload("res://simulation/SimulationManager.gd") var manager: Node func before_each() -> void: manager = MANAGER_SCRIPT.new() add_child_autofree(manager) func test_world_v14_migrates_to_empty_emergent_collections() -> void: var previous: Dictionary = manager.create_state_record().to_dictionary() previous["schema_version"] = SimulationStateRecord.PRE_EMERGENT_SCHEMA_VERSION for field in ["situations", "quest_journal", "commitments", "conversation_history"]: previous.erase(field) for field in [ "next_situation_id", "next_journal_entry_id", "next_commitment_id", "next_conversation_act_id", ]: previous["simulation"].erase(field) var migrated: SimulationStateRecord = SimulationStateRecord.from_dictionary(previous) assert_not_null(migrated) assert_true(migrated.situations.is_empty()) assert_true(migrated.quest_journal.is_empty()) assert_true(migrated.commitments.is_empty()) assert_true(migrated.conversation_history.is_empty()) assert_eq(int(migrated.simulation["next_situation_id"]), 0) assert_eq(int(migrated.simulation["next_conversation_act_id"]), 0) func test_orphan_journal_and_situation_evidence_are_rejected() -> void: var orphan_journal: Dictionary = manager.create_state_record().to_dictionary() orphan_journal["quest_journal"] = [ ( QuestJournalEntryStateRecord . create(0, 42, SituationSystem.DEFINITION_PANTRY_SHORTAGE, 0) . to_dictionary() ) ] orphan_journal["simulation"]["next_journal_entry_id"] = 1 assert_null(SimulationStateRecord.from_dictionary(orphan_journal)) var missing_evidence: Dictionary = manager.create_state_record().to_dictionary() missing_evidence["situations"] = [ ( SituationStateRecord . create( 0, SituationSystem.DEFINITION_PANTRY_SHORTAGE, "missing-evidence", 0, 999, {"interested_npc_id": "0"} ) . to_dictionary() ) ] missing_evidence["simulation"]["next_situation_id"] = 1 assert_null(SimulationStateRecord.from_dictionary(missing_evidence)) func test_conversation_history_requires_valid_actors_and_monotonic_id() -> void: var state: Dictionary = manager.create_state_record().to_dictionary() var npc_ref := WorldEntityRef.create(WorldEventRecord.ENTITY_TYPE_NPC, &"0") var player_ref := WorldEntityRef.create(WorldEventRecord.ENTITY_TYPE_PLAYER, &"-1") state["conversation_history"] = [ ( ConversationActStateRecord . create( 0, 0, npc_ref, player_ref, ConversationIntentIds.GREET, [&"topic_pantry_shortage"] ) . to_dictionary() ) ] assert_null( SimulationStateRecord.from_dictionary(state), "The next stable act ID cannot collide with retained history" ) state["simulation"]["next_conversation_act_id"] = 1 assert_not_null(SimulationStateRecord.from_dictionary(state)) state["conversation_history"][0]["speaker"]["entity_id"] = "missing_npc" assert_null(SimulationStateRecord.from_dictionary(state))