feat: integrate regional caravan persistence

This commit is contained in:
Rijad Zuzo
2026-08-23 17:20:41 +02:00
parent 49c5bda651
commit 52307f1306
24 changed files with 1939 additions and 92 deletions
+13 -12
View File
@@ -21,10 +21,11 @@ own persistent quantities, travel completion, or quest progress.
The long-term direction is one regional simulation containing settlements,
routes, caravans, named people, aggregate cohorts, and polities. The current
repository has the regional records, deterministic scheduler, one exact
caravan transfer service, chunked persistence, and a 20-caravan structural
benchmark. It does not yet run that regional service as the production
`SimulationManager` facade or provide a complete market, settlement-growth, or
kingdom gameplay loop. That distinction is important when extending the game.
caravan transfer service, a production facade for one inbound Jajce route, a
combined local/regional save manifest, chunked persistence, and a 20-caravan
structural benchmark. It does not yet provide a complete market,
settlement-growth, or kingdom gameplay loop. That distinction is important
when extending the game.
## Start here
@@ -53,9 +54,9 @@ kingdom gameplay loop. That distinction is important when extending the game.
| Situations/quests | Definition-driven bounded situations, derived progress, journal metadata, commitments and idempotent outcomes | The initial Jajce slice is bounded; it is not a universal objective scripting language |
| Dialogue | Deterministic semantic `ConversationService`, authored intent/template resources, Dialogue Manager v3 presenter | Dialogue Manager renders planned turns; it is not an authority or save format |
| Entities | Shared definition → instance/state → presentation contracts for resources, animals, enemies, items, storage | New behavior profiles and genuinely new mechanics still need typed code and tests |
| Regional kernel | Primitive records, due-job heap, keyed random, analytical updates, caravan proof, chunk/file store | Regional service and 20-caravan trade are currently integration fixtures, not the live Jajce loop |
| Regional kernel | Primitive records, due-job heap, keyed random, analytical updates, caravan service, production facade, chunk/file store | One authored inbound route is live; the 20-caravan economy remains a structural fixture, not the Jajce market |
| Presentation | Active-world adapters, context registries, relevance cap of 40, navigation budget of 2/frame, High/Balanced/Low profiles | Hardware frame-time/VRAM evidence is still pending; structural benchmarks are not rendered claims |
| Persistence | Local save schema v16 with migrations and scope preflight; regional chunk generations with recovery | No save menu/profile system; regional chunk store is not yet the local `SaveSlotStore` backend |
| Persistence | Combined manifest v1 containing unchanged local schema v16 plus the canonical regional facade; regional chunk generations with recovery | No save menu/profile system; regional chunk/history generations are not yet the `SaveSlotStore` backend |
## The authority pipeline
@@ -106,9 +107,10 @@ relationship, or reward that the event claims happened.
- `simulation/events/`, `knowledge/`, `relationships/`, `situations/`, and
`dialogue/` — causal history and emergent narrative layers.
- `simulation/state/` — versioned primitive records and validation.
- `simulation/persistence/`local quicksave safety.
- `simulation/regional/` — regional records, scheduler, caravan proof, chunk
codec, and file generations.
- `simulation/persistence/`combined quicksave manifest and atomic slot
replacement, plus regional chunk codecs and generations.
- `simulation/regional/` — production facade, regional records, scheduler,
caravan transaction, retention planning, and scale contracts.
### Loaded world and presentation
@@ -161,12 +163,11 @@ are used when an existing save is loaded.
The following are deliberately **not** claimed as complete:
- wire `RegionalCaravanService` into the production regional facade and local
save manifest;
- integrate event retention/rollups/chunked history into one atomic,
lazily loaded long-horizon save;
- run 20 real caravan trades across five settlement economies with atomic
cargo/stock ledgers;
- replace local unloaded travel freezes with authoritative route-time work;
- integrate event retention/rollups/chunked history into one long-horizon save;
- add settlement projects, cohort promotion/demotion, offices, diplomacy,
armies, campaigns, and aggregate conflict;
- add visual relevance streaming to the live world view rather than only the
@@ -2,9 +2,9 @@
The regional package is the scale foundation for one authority spanning
settlements, routes, caravans, named people, aggregate cohorts, and polities.
It is intentionally additive: the current Jajce `SimulationManager` remains
the playable local facade while the regional contracts prove deterministic
unloaded work and conservation in isolation.
The production `SimulationManager` now owns a bounded regional facade for one
inbound Jajce route, while the broader regional contracts continue to prove
deterministic unloaded work and conservation before wider integration.
## Regional record model
@@ -63,6 +63,12 @@ no partial mutation. `to_dictionary()`, `from_dictionary()`, and `checksum()`
provide deterministic save/restore. The test runs always-loaded, never-loaded,
and load/unload presentation modes through the same authoritative service.
`RegionalSimulationFacade` is the first production consumer. It owns one
authored Travnik-to-Jajce route, advances before each committed local tick, and
exposes one bounded delivery command. The cargo is a separate catalogued
`regional_trade_goods` item with no local storage tag, so this proof does not
shadow or duplicate the pantry and woodpile economy.
## Chunked persistence
`RegionalChunkedPersistence` captures the service into a manifest plus fixed
@@ -89,11 +95,20 @@ primitive-tree bounds.
## Current integration boundary
The regional package is not yet the production authority for `main.tscn`:
`main.tscn` now advances the regional facade and `SaveSlotStore` writes a
combined `SimulationSaveManifest` containing the unchanged local v16 record
and canonical regional envelope. Both checksums plus world, seed, location,
and tick alignment are validated before either authority is restored. Raw
local v16 slots remain compatible and create an idle regional facade;
explicit non-Jajce adapter scopes keep writing local v16 until they have a
matching regional facade. Those scopes cannot dispatch a Jajce delivery, and
local-only saving fails closed if regional state is no longer reconstructibly
idle.
- Jajce local saves still use `SaveSlotStore` and `SimulationStateRecord` v16;
- `RegionalCaravanService` is a complete isolated transfer proof, not the live
economy's 20-trade scheduler;
The remaining boundary is intentionally narrow:
- the facade has one callable inbound route, not the live economy's 20-trade
market scheduler;
- event retention/rollups and regional chunk files are not yet one integrated
long-horizon save transaction;
- loaded/unloaded local NPC travel still has the old active-visual boundary;
@@ -101,8 +116,8 @@ The regional package is not yet the production authority for `main.tscn`:
aggregate conflict remain planned.
Do not create one `SimulationManager` per settlement or caravan. The next
production step is an explicit regional facade that delegates to these records
and services, while the active adapter presents only a bounded relevant context.
production step is to publish retained raw events, daily rollups, and chunked
regional history as one atomic, lazily loaded transaction behind the facade.
## Scale evidence
+20 -8
View File
@@ -64,11 +64,22 @@ 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.
`SimulationSaveManifest` v1 combines the unchanged local v16 record and the
canonical `RegionalSimulationFacade` envelope. It stores an independent
checksum for each authority and cross-validates world, seed, active location,
and processed tick. A rejected manifest cannot partially replace local or
regional state.
`SaveSlotStore` validates the complete manifest before replacement, restricts
slot names and size, preserves a previous file, and can recover a backup after
an interrupted replacement. It also accepts existing raw local v16 files and
bootstraps an idle regional facade at the restored seed and tick. Explicit
non-Jajce adapter scopes continue writing raw local v16 records until a
matching regional facade is implemented. This fallback is permitted only while
the regional facade equals its deterministic idle bootstrap; a local-only save
fails closed rather than discarding live regional state. `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
@@ -79,9 +90,10 @@ 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.
This regional chunk codec is not yet the backend for `SaveSlotStore`. The
production facade and combined quicksave manifest are complete; retained raw
events, rollups, chunk generations, and lazy context loading still need one
atomic long-horizon publication contract.
## How to change state safely
+1 -1
View File
@@ -77,7 +77,7 @@ For a new system, add tests for:
## Current evidence and gaps
The current full suite passes 154/154 tests with 2,047 assertions. Baseline 03
The current full suite passes 180/180 tests with 2,258 assertions. Baseline 03
measures 600 full-fidelity data-only NPC/combatant records at about 90.6 ticks/s
on the reviewed development host. The regional baseline proves the target
record counts and scheduler parity. Neither measures a complete regional
+11 -4
View File
@@ -1,10 +1,11 @@
# The Steward — Learning and Reusable-Systems Roadmap
> **Current implementation checkpoint (2026-08-13):** The roadmap below is a
> **Current implementation checkpoint (2026-08-23):** The roadmap below is a
> chronological learning record. The current code has completed the authored
> content/catalog, shared target/command, event/social, situation/dialogue,
> entity-family, context-scoping, and first regional record/caravan/chunk
> slices. For a source-based status matrix and the remaining integration work,
> slices, including one production facade and combined save manifest. For a
> source-based status matrix and the remaining integration work,
> start with [`DEVELOPER_INDEX.md`](DEVELOPER_INDEX.md). Do not infer current
> behavior from an older milestone paragraph when the index or code disagrees.
@@ -43,8 +44,8 @@ becomes knowledge, generated semantic dialogue, a journal projection, and an
event-backed social commitment whose ordinary deposit outcome survives
save/load. Definition packs now cover reusable items, resources, storage,
enemies, and animals. Regional records, deterministic scheduled work, bounded
presentation relevance, and the first authoritative caravan transfer form the
next world-slice foundation. See
presentation relevance, and the first authoritative caravan transfer now feed
one production facade and combined local/regional save boundary. See
[ADR 0001](decisions/0001-simulation-authority-boundary.md),
[ADR 0002](decisions/0002-emergent-world-content-and-narrative.md), and the
[regional simulation contract](REGIONAL_SIMULATION.md).
@@ -1107,6 +1108,12 @@ resolution, and personal request accept/decline.
Recently completed:
- `Regional Jajce Facade 13`: `SimulationManager` now advances one authored
Travnik-to-Jajce caravan route through the regional service, and an atomic
combined manifest preserves both local v16 and regional authority. Separate
regional trade goods prevent duplicate pantry/woodpile ownership; tamper,
legacy-slot, rollback, conservation, and deterministic continuation
regressions define the boundary before broader markets or chunked history.
- `Jajce Villager Field Note 12`: a separate player-facing note selects the
nearest loaded living villager and shows live name, action, task state, exact
target, carried inventory, and a currently matching decision reason. It
+37 -16
View File
@@ -1,10 +1,11 @@
# Regional simulation contract
> **Implementation status (2026-08-13):** The record, scheduler, caravan,
> **Implementation status (2026-08-23):** The record, scheduler, caravan,
> chunk, file-generation, relevance, and navigation-budget contracts are
> implemented and tested. They are still an additive regional package; the
> playable Jajce `SimulationManager` and `SaveSlotStore` remain the local
> production authority until the integrations listed at the end land.
> implemented and tested. `SimulationManager` now owns a production regional
> facade for one inbound Jajce route, and `SaveSlotStore` persists local and
> regional authority in one checked manifest. The scale economy and chunked
> long-horizon history remain separate integrations.
The regional layer extends the Jajce simulation without multiplying scene-tree
managers. One authority owns every loaded and unloaded location, settlement,
@@ -38,12 +39,10 @@ validated transactionally before a replacement state is published. Canonical
serialization sorts record families and IDs, making checksums independent of
construction order.
The current local `SimulationStateRecord` remains the v16 Jajce save boundary.
Regional state is deliberately carried in its own versioned service envelope
until one playable route consumes it; this avoids placing speculative regional
fields in every local save. The merge into the production save manifest must
retain this canonical regional payload rather than copying its fields into
scene nodes.
The current local `SimulationStateRecord` remains the unchanged v16 Jajce
record. `SimulationSaveManifest` v1 combines that record with the canonical
`RegionalSimulationFacade` envelope and checksums both authorities. Regional
fields are not copied into local records or scene nodes.
## Deterministic work
@@ -92,6 +91,30 @@ never-loaded, and load/unload executions must preserve cargo, headcount, facts,
arrival tick, queue state, and checksum. Nearby visuals may interpolate route
progress; they do not report elapsed travel completion.
## Production facade and combined save
`RegionalSimulationFacade` is now owned by the production `SimulationManager`.
It bootstraps an authored Travnik-to-Jajce route and advances the same
`RegionalCaravanService` before each committed local tick. Its bounded public
command can depart one exact delivery; arrival remains scheduled simulation
work and does not depend on a loaded caravan visual.
The route transports `regional_trade_goods`, a catalogued item with no local
storage tag. Jajce starts with no regional stock and Travnik starts with four
units, so the facade cannot duplicate the playable pantry's food or the
woodpile's wood. Local and regional event-ID spaces remain deliberately
separate until an explicit cross-domain history contract exists.
`SimulationSaveManifest` stores exactly the local v16 record, its checksum, the
regional facade envelope, its checksum, and the manifest schema/version. It
rejects checksum tampering and mismatched world, seed, active location, or
tick. Combined restore is transactional across both authorities. Existing raw
local v16 quicksaves remain loadable and bootstrap an idle regional route at
the restored seed and tick. Explicit non-Jajce adapter scopes continue to use
their local v16 boundary until a matching regional facade exists. That fallback
is allowed only while the regional facade equals its deterministic idle
bootstrap; Jajce delivery commands are rejected outside the combined scope.
## Event retention and daily rollups
`WorldEventRetentionPlanner` is a pure, deterministic query over a complete
@@ -157,14 +180,12 @@ active-world and hardware captures.
Build in this order, keeping each step behind conservation and continuation
tests:
1. make the Jajce route proof callable from the production regional facade and
save manifest;
2. integrate the retention/rollup and chunk codecs as one atomic,
1. integrate the retention/rollup and chunk codecs as one atomic,
lazily loaded history transaction;
3. schedule 20 ordinary caravan trades across five settlement economies;
4. promote/demote presentation and population fidelity while pinning named and
2. schedule 20 ordinary caravan trades across five settlement economies;
3. promote/demote presentation and population fidelity while pinning named and
causally referenced people;
5. add data-defined settlement projects, tier promotion, offices, diplomacy,
4. add data-defined settlement projects, tier promotion, offices, diplomacy,
armies, campaigns, and aggregate conflict.
Context-owned world-target registries and the first shared player/NPC activity
+16 -8
View File
@@ -451,12 +451,20 @@ replayed after restore.
## Local quicksave boundary
`SaveSlotStore` writes the existing versioned local 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.
`SaveSlotStore` writes `SimulationSaveManifest` v1 to
`user://saves/quicksave.json`. The manifest contains the unchanged local v16
record and canonical regional facade envelope, with an independent checksum
for each. Restore also requires world, seed, active location, and tick to agree
across both authorities, and rolls both back if local restoration fails.
The store validates the complete serialized manifest before replacement,
limits file size, restricts slot names, preserves the previous file during
replacement, and can recover that backup if replacement is interrupted. Raw
local v16 quicksaves remain loadable; they bootstrap an idle regional facade
at the restored seed and tick. Explicit non-Jajce adapter scopes continue
writing local v16 records until a matching regional facade exists. Local-only
saving is allowed only while regional state equals its deterministic idle
bootstrap; otherwise it fails closed rather than discarding authority.
In `main.tscn`, F5 saves and F9 loads this slot. Restoration rebuilds active NPC
visuals from authoritative state.
@@ -476,8 +484,8 @@ This phase does not yet provide:
- persistence of a currently open dialogue UI/turn. Semantic conversation
history and commitment authority persist, while a balloon is regenerated
after restore;
- production integration of the regional chunked save manifest, lazy location
loading, or aggregate population promotion/persistence;
- production integration of regional retained/rolled-up chunk history, lazy
location loading, or aggregate population promotion/persistence;
- persistence for the player transform or presentation-only scene state.
Those features should build on this boundary rather than inventing parallel