4.4 KiB
Feature slice: saves, schema, migrations, and continuation
The local playable world and the regional proof use different persistence boundaries. Both are primitive-only, versioned, deterministic, and validated before mutation.
Local save boundary
SimulationStateRecord is currently schema v16. It contains the local
simulation seed/clock scope, village/NPC/animal/resource/storage/player/
combatant/faction records, ordered economic events, relationships, knowledge,
legacy opportunities, situations, journal entries, commitments, and bounded
semantic conversation acts. SimulationManager.create_state_record() creates
it; serialize_state() emits canonical JSON; restore_state() preflights and
then atomically restores dependent systems.
Top-level v16 adds non-empty world_id and location_id. Activity success and
blocked facts carry the same scope. A save recorded under another active adapter
is rejected before clock, economy, NPC, or event state is mutated. This closes
the context-reinterpretation hole where equal local coordinates could be
treated as the same world.
The record stores IDs, primitive values, event IDs, and semantic topic IDs. It
never stores scripts, nodes, NodePaths, callables, imported assets, dialogue
prose, or transient HUD/balloon state.
Migration policy
Nested records migrate at their own version; the top-level schema accepts an explicit historical range and normalizes old fields before cross-record validation. Current supported migrations include:
- legacy village/storage and event streams;
- directed relationships and causal knowledge provenance;
- opportunity history and its v2 lifecycle;
- animal routine/definition IDs;
- player citizen needs/health;
- combatants, factions, and enemy definition IDs;
- situations, journal entries, commitments, and conversation acts;
- world/location scope v16;
- explicitly marked legacy unstructured
task_blockedfacts.
Old definition values are not snapshotted. The current build supplies balance and handler definitions while mutable saved state is preserved. Unknown future schema versions fail closed until a migration exists.
Validation invariants
Restore checks include:
- unique IDs and next-ID cursors above restored history;
- valid definition/action/item/storage references;
- actor/target/cost/effect contracts for activity facts;
- animal reservations and feed event agreement;
- relationship causes pointing at valid known events;
- knowledge provenance and one-hop communication rules;
- situation/journal/commitment references and statuses;
- scope consistency for the event log and activity facts;
- no future event tick or forged actor/source/destination fields.
The test suite deliberately removes derived knowledge/opportunity state and tamper-tests facts, so validation does not rely on a secondary projection to catch corruption.
Local file safety
SaveSlotStore validates the complete JSON before replacement, restricts slot
names and size, preserves a previous file, and can recover a backup after an
interrupted replacement. F5/F9 use the current quicksave path in main.tscn.
The player transform and presentation-only scene state are intentionally not
saved.
Regional persistence boundary
RegionalChunkedPersistence and RegionalChunkedFileStore are the regional
counterpart. They serialize a RegionalCaravanService envelope into global,
location, mobile-group, scheduler, and event-segment chunks, with manifest and
per-file checksums. The file store uses immutable generations, a current
pointer, recovery scanning, and conservative pruning. Partial active-location
loads are metadata-only and cannot silently resurrect a removed location.
This regional codec is not yet the backend for local SaveSlotStore. Integrate
it only after the production regional facade, event retention, and lazy context
loading have one atomic manifest contract.
How to change state safely
- Add the field to the narrow nested record first.
- Define
SCHEMA_VERSION, validation, canonicalto_dictionary(), and an explicit migration from the prior version. - Update top-level construction/restore/checksum only after the nested record round-trips.
- Add malformed/tamper, old-save migration, save/load, and deterministic continuation tests.
- Update SIMULATION_STATE_SCHEMA.md and this guide with the actual version and compatibility range.
The full field-by-field history remains in Simulation State Schema.