# The Steward — Simulation State Schema ## Current contract `SimulationStateRecord` is the versioned JSON boundary for the current simulation. The current world schema is v3 and captures: - simulation seed, tick interval, tick count, clock remainder, and elapsed clock ticks; - every NPC's identity, needs, attributes, task lifecycle, target, position, starvation state, and decision RNG stream; - village resource counters; - controlled per-NPC wander RNG streams; - scene-independent resource state plus the definition facts needed while its ResourceNode is unloaded. - pantry contents, carried NPC inventory, the ordered economic event stream, and its next stable event ID. The top-level identity is: ```json { "schema": "the_steward.simulation", "schema_version": 3 } ``` Unknown schema versions and structurally incomplete records are rejected. Add an explicit migration function before accepting a future version; never silently reinterpret old data as the newest layout. NPC action and profession references are serialized as stable strings and restored as `StringName`. Records referencing unknown executable actions or professions are rejected against the validated definition registry. See [the simulation definitions](SIMULATION_DEFINITIONS.md). ## Deterministic continuation RNG seeds and internal states are encoded as decimal strings. They are signed 64-bit values and cannot safely pass through every JSON number implementation without precision loss. Converting them to ordinary JSON numbers caused a restored simulation to retain the same visible state while silently changing its future random sequence. `tests/simulation_state_serialization_test.gd` protects this contract by: 1. running a fixed-seed scenario for 48 ticks without interruption; 2. running the same scenario for 24 ticks; 3. serializing and restoring into a fresh manager; 4. running the remaining 24 ticks; 5. requiring the complete final-state checksums to match. It also verifies clock remainder, resource amount/reservation/enabled round-tripping, presentation unload/rebind, and rejection of unsupported schemas. NPCStateRecord v2 adds the resolved travel destination and whether it is active. Nested v1 NPC records migrate explicitly with no invented active destination. This allows a reloaded visual to resume travel without changing target selection or deterministic RNG state. NPCStateRecord v3 adds carried inventory. SimulationStateRecord v2 adds StorageStateRecord entries; world-schema v1 migrates legacy village food into the stable `village_pantry` record. Parsed storage values are canonicalized so save/restore continuation retains byte-stable checksums. SimulationStateRecord v3 adds ordered `EconomicEventRecord` entries and `next_event_id`. World schemas v1 and v2 migrate explicitly to an empty event stream. Event records use stable source/destination/item IDs, reject invalid or duplicate IDs, and preserve deterministic ordering across save/restore. See [the economic event stream](ECONOMIC_EVENTS.md). ## Resource authority `SimulationManager` owns `ResourceStateRecord` instances independently of the scene tree. Amount, reservation, enabled state, action/resource identity, yield, and usage permissions remain available and serializable while no ResourceNode is loaded. ResourceNode binds to a record by stable ID and provides presentation, interaction transforms, and active-world discoverability. Unloading a node does not delete its record. Loading another node with the same stable ID rebinds to the existing record and cannot overwrite its amount or reservation with scene defaults. ResourceStateRecord v2 adds the definition facts needed while unloaded. Nested v1 resource records are migrated explicitly and hydrate their missing definition from a matching presentation node when one becomes available. ## Local quicksave boundary `SaveSlotStore` writes the existing versioned JSON record to `user://saves/quicksave.json`. It validates the serialized record before replacement, limits file size, restricts slot names, preserves the previous file during replacement, and can recover that backup if replacement is interrupted. Loading parses and validates the complete record before mutating the simulation. In `main.tscn`, F5 saves and F9 loads this slot. Restoration rebuilds active NPC visuals from authoritative state. ## Deliberately out of scope This phase does not yet provide: - a save-slot menu, metadata, thumbnails, autosaves, or multiple profiles; - migrations older than the explicitly supported world schemas v1 and v2; - player inventory, relationship, schedule, or social-memory records; - persistence for the player transform or presentation-only scene state. Those features should build on this boundary rather than inventing parallel serialization paths.