docs: mark resource authority phase complete

This commit is contained in:
2026-07-05 13:26:26 +02:00
parent 363620b731
commit 12f9ba616f
6 changed files with 61 additions and 45 deletions
+1 -1
View File
@@ -361,7 +361,7 @@ learning roadmap:
- deterministic clock and seeded randomness; ✅ - deterministic clock and seeded randomness; ✅
- fixed-seed headless scenarios and final-state checksum; ✅ - fixed-seed headless scenarios and final-state checksum; ✅
- versioned serializable NPC, village, resource, clock, and RNG records; ✅ - versioned serializable NPC, village, resource, clock, and RNG records; ✅
- resource amount and reservation authority outside scene nodes; - resource amount and reservation authority outside scene nodes;
- stable action/profession IDs and initial definitions; - stable action/profession IDs and initial definitions;
- separate action selection, execution, target resolution, and visual travel; - separate action selection, execution, target resolution, and visual travel;
- explicit active-position synchronization. - explicit active-position synchronization.
+18 -15
View File
@@ -54,7 +54,7 @@ The gate is complete when the same scenario produces the same checksum without
loading `main.tscn`, and loading or unloading a visual does not change loading `main.tscn`, and loading or unloading a visual does not change
authoritative NPC or resource state. authoritative NPC or resource state.
**Current progress:** the first two architecture slices are implemented: **Current progress:** the first three architecture slices are implemented:
- `SimulationClock` advances explicit fixed ticks while preserving remainder; - `SimulationClock` advances explicit fixed ticks while preserving remainder;
- NPC decisions and visual wander requests use controlled per-NPC random - NPC decisions and visual wander requests use controlled per-NPC random
@@ -65,10 +65,15 @@ authoritative NPC or resource state.
clock, and RNG state; clock, and RNG state;
- a save-at-tick-24 continuation test matches an uninterrupted 48-tick - a save-at-tick-24 continuation test matches an uninterrupted 48-tick
checksum and rejects unsupported schema versions. checksum and rejects unsupported schema versions.
- `SimulationManager` owns resource records and all amount/reservation
mutation; ResourceNode binds by stable ID as presentation and interaction
geometry;
- an unload/rebind regression proves resource state remains authoritative while
its scene node is absent.
The gate remains open. Scene-independent resource authority, stable The gate remains open. Stable definitions, responsibility separation, and NPC
definitions, responsibility separation, and visual load/unload invariance are visual load/unload invariance are still required. See
still required. See [the simulation state schema](SIMULATION_STATE_SCHEMA.md). [the simulation state schema](SIMULATION_STATE_SCHEMA.md).
## Three vertical slices ## Three vertical slices
@@ -615,23 +620,21 @@ Completed foundations:
The practical next sequence is: The practical next sequence is:
1. Move resource amount/reservation authority out of `ResourceNode` scenes and 1. Replace free-form task and profession strings with stable IDs and
make unloaded resources remain in state.
2. Replace free-form task and profession strings with stable IDs and
definitions. definitions.
3. Separate action selection, execution, target resolution, and visual travel; 2. Separate action selection, execution, target resolution, and visual travel;
remove decision mutation from `WorldViewManager`. remove decision mutation from `WorldViewManager`.
4. Define active-position synchronization and prove visual unload/reload. 3. Define active-position synchronization and prove visual unload/reload.
5. Pass the architecture gate's deterministic headless and unloaded-visual exit 4. Pass the architecture gate's deterministic headless and unloaded-visual exit
tests. tests.
6. Build location-based food storage, inventory, and transactions. 5. Build location-based food storage, inventory, and transactions.
7. Emit structured economic events while making one NPC visibly gather, carry, 6. Emit structured economic events while making one NPC visibly gather, carry,
store, retrieve, and eat food. store, retrieve, and eat food.
8. Add save-slot persistence and explicit schema migrations before schedules 7. Add save-slot persistence and explicit schema migrations before schedules
or social state expand. or social state expand.
9. Resume Terrain3D sculpting, runtime integration, and the simulation-garden 8. Resume Terrain3D sculpting, runtime integration, and the simulation-garden
beauty pass. beauty pass.
10. Add stylized character and profession readability plus the reason 9. Add stylized character and profession readability plus the reason
inspector. inspector.
This order strengthens the simulation while regularly producing visible This order strengthens the simulation while regularly producing visible
+10 -10
View File
@@ -434,7 +434,7 @@ NpcVisual navigates through the active world
| Later ticks complete work | Later ticks complete work
| | | |
| v | v
| ResourceNode.extract() -> village.apply_resource_delta() | ResourceStateRecord.extract() -> village.apply_resource_delta()
| | | |
| v | v
| village_changed signal updates the UI | village_changed signal updates the UI
@@ -498,10 +498,10 @@ These are expected prototype constraints, not necessarily isolated bugs:
- Task names and task-to-activity-marker mappings are duplicated strings. - Task names and task-to-activity-marker mappings are duplicated strings.
- Temporary activity markers remain for eating, rest, study, and patrol; NPC - Temporary activity markers remain for eating, rest, study, and patrol; NPC
and player food/wood gathering use `ResourceNode` instances with no fallback. and player food/wood gathering use `ResourceNode` instances with no fallback.
- Current NPC, village, loaded resource, clock, and RNG state serialize through - Current NPC, village, resource, clock, and RNG state serialize through schema
schema v1, but there is no save-slot/file UX or backward migration yet. v1, but there is no save-slot/file UX or top-level backward migration yet.
- Resource records currently mirror loaded ResourceNode state; the scene nodes - Simulation-owned resource records retain live amounts, reservations, and
still own live amounts and reservations. usage definitions while ResourceNode scenes are unloaded.
- An explicit fixed-step clock converts frame delta into simulation ticks, but - An explicit fixed-step clock converts frame delta into simulation ticks, but
orchestration still lives on the scene-tree `SimulationManager`. orchestration still lives on the scene-tree `SimulationManager`.
- Automated coverage includes deterministic same-seed and save/restore - Automated coverage includes deterministic same-seed and save/restore
@@ -716,21 +716,21 @@ Food and wood migration and the deliberately minimal `JajceWorld` scaffold,
greybox, navigation spike, and stable-ID placement proof are complete. Do not greybox, navigation spike, and stable-ID placement proof are complete. Do not
proceed directly from that proof into open-ended beauty production. proceed directly from that proof into open-ended beauty production.
The architecture gate is now the active milestone. Its first two slices are The architecture gate is now the active milestone. Its first three slices are
complete: complete:
- explicit fixed-step simulation clock; - explicit fixed-step simulation clock;
- seeded per-NPC decision and wander random streams; - seeded per-NPC decision and wander random streams;
- headless fixed-seed scenario with a final-state checksum; - headless fixed-seed scenario with a final-state checksum;
- versioned JSON records for NPC, village, loaded resource, clock, and RNG - versioned JSON records for NPC, village, resource, clock, and RNG state;
state; - deterministic save/restore continuation with exact 64-bit RNG preservation;
- deterministic save/restore continuation with exact 64-bit RNG preservation. - simulation-owned resource amount/reservation state with ResourceNode
presentation binding and unload/rebind coverage.
The remaining gate work is: The remaining gate work is:
- data-defined action and profession IDs; - data-defined action and profession IDs;
- separated action selection, execution, target resolution, and visual travel; - separated action selection, execution, target resolution, and visual travel;
- resource amount and reservation authority moved out of scene nodes;
- explicit synchronization of active NPC position. - explicit synchronization of active NPC position.
The coherent visual slice can then aim for: The coherent visual slice can then aim for:
+9 -4
View File
@@ -18,6 +18,9 @@
- **`navigation_failed` signal** (discovered during Phase 4): Added a separate signal pathway to distinguish genuine arrival from navigation failure. The original plan treated all "arrivals" uniformly. - **`navigation_failed` signal** (discovered during Phase 4): Added a separate signal pathway to distinguish genuine arrival from navigation failure. The original plan treated all "arrivals" uniformly.
- **Stale-path prevention** (discovered during Phase 4): Added `path_request_id` + `path_pending` to reject async path results that arrive after a new target was set or the NPC died. - **Stale-path prevention** (discovered during Phase 4): Added `path_request_id` + `path_pending` to reject async path results that arrive after a new target was set or the NPC died.
- **Duplicate node_id detection** (discovered during Phase 4): Added startup validation that disables nodes with duplicate IDs and pushes an error. - **Duplicate node_id detection** (discovered during Phase 4): Added startup validation that disables nodes with duplicate IDs and pushes an error.
- **Simulation-owned resource authority** (architecture gate): Resource amount,
reservation, and enabled state now live in `ResourceStateRecord`; ResourceNode
binds by stable ID and can unload without deleting authoritative state.
### Bugs found and fixed ### Bugs found and fixed
@@ -33,8 +36,8 @@
| 8 | `Variant as StringName`: invalid cast | Phase 2-3 | Check for `null` on Dictionary `.get()` instead of casting | | 8 | `Variant as StringName`: invalid cast | Phase 2-3 | Check for `null` on Dictionary `.get()` instead of casting |
| 9 | Empty-path re-entrancy: immediate arrival report caused re-entrant signal chain | Phase 4 | Defer to `stuck_counter`/`stuck_time` in `_physics_process` instead | | 9 | Empty-path re-entrancy: immediate arrival report caused re-entrant signal chain | Phase 4 | Defer to `stuck_counter`/`stuck_time` in `_physics_process` instead |
| 10 | Stale async path: `await physics_frame` result used after target or death changed | Phase 4 | `path_request_id`/`path_pending` guard | | 10 | Stale async path: `await physics_frame` result used after target or death changed | Phase 4 | `path_request_id`/`path_pending` guard |
| 11 | Stolen extraction: NPC extracted from node after reservation was lost | Phase 4 | Guard extraction with `node.reserved_by == npc.id` | | 11 | Stolen extraction: NPC extracted after reservation was lost | Phase 4 | Guard extraction with the authoritative resource record's reservation |
| 12 | Depleted target retained an NPC reservation after player harvesting | Phase 4 | `ResourceNode.extract()` now releases its reservation on depletion | | 12 | Depleted target retained an NPC reservation after player harvesting | Phase 4 | Authoritative extraction now releases its reservation on depletion |
## Decision ## Decision
@@ -451,7 +454,8 @@ for the initial gather-food scenario.
### ✅ Phase 4 — Wood and player parity *[complete]* ### ✅ Phase 4 — Wood and player parity *[complete]*
**Wood migration** ✅ complete: **Wood migration** ✅ complete:
- `gather_wood` uses `ResourceNode.find_available("gather_wood")` in WVM - `gather_wood` resolves loaded presentation candidates through
`SimulationManager.acquire_resource_target()`
- Tree_01 (15 wood, yield 3.0) and Tree_02 (12 wood, yield 3.0) placed - Tree_01 (15 wood, yield 3.0) and Tree_02 (12 wood, yield 3.0) placed
- Extraction follows same path as food (reserve → travel → work → extract → village resource delta) - Extraction follows same path as food (reserve → travel → work → extract → village resource delta)
- Zone fallback removed; NPC goes idle if no tree available - Zone fallback removed; NPC goes idle if no tree available
@@ -460,7 +464,8 @@ for the initial gather-food scenario.
- Player interaction resolves the nearest player-usable resource node by its - Player interaction resolves the nearest player-usable resource node by its
interaction point. interaction point.
- `SimulationManager.harvest_resource_node()` uses the same authoritative - `SimulationManager.harvest_resource_node()` uses the same authoritative
`ResourceNode.extract()` contract and applies exactly the returned amount. `ResourceStateRecord.extract()` contract and applies exactly the returned
amount.
- Player harvesting can contend with an NPC reservation; depletion releases - Player harvesting can contend with an NPC reservation; depletion releases
that reservation so the NPC can recover cleanly. that reservation so the NPC can recover cleanly.
- Depleted and disabled targets provide explicit feedback. - Depleted and disabled targets provide explicit feedback.
+20 -12
View File
@@ -11,7 +11,8 @@ simulation. Schema v1 captures:
starvation state, and decision RNG stream; starvation state, and decision RNG stream;
- village resource counters; - village resource counters;
- controlled per-NPC wander RNG streams; - controlled per-NPC wander RNG streams;
- loaded ResourceNode amount, reservation, and enabled state. - scene-independent resource state plus the definition facts needed while its
ResourceNode is unloaded.
The top-level identity is: The top-level identity is:
@@ -42,19 +43,26 @@ its future random sequence.
4. running the remaining 24 ticks; 4. running the remaining 24 ticks;
5. requiring the complete final-state checksums to match. 5. requiring the complete final-state checksums to match.
It also verifies clock remainder, ResourceNode amount/reservation/enabled It also verifies clock remainder, resource amount/reservation/enabled
round-tripping, and rejection of unsupported schemas. round-tripping, presentation unload/rebind, and rejection of unsupported
schemas.
## Transitional resource boundary ## Resource authority
Schema v1 can capture and restore loaded `ResourceNode` state, but the scene `SimulationManager` owns `ResourceStateRecord` instances independently of the
node still owns the live amount and reservation. That is transitional support, scene tree. Amount, reservation, enabled state, action/resource identity,
not the final authority model. yield, and usage permissions remain available and serializable while no
ResourceNode is loaded.
The next architecture-gate phase moves those values into scene-independent ResourceNode binds to a record by stable ID and provides presentation,
resource records. ResourceNode will then bind to a record by stable ID and act interaction transforms, and active-world discoverability. Unloading a node does
as presentation plus an active-world interaction surface. An unloaded resource not delete its record. Loading another node with the same stable ID rebinds to
must remain simulated and serializable. 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.
## Deliberately out of scope ## Deliberately out of scope
@@ -64,7 +72,7 @@ This phase does not yet provide:
- backward migrations beyond schema v1; - backward migrations beyond schema v1;
- inventory, relationship, schedule, or history records; - inventory, relationship, schedule, or history records;
- a player-facing load flow; - a player-facing load flow;
- scene-independent resource authority. - save-slot persistence for scene-independent resource state.
Those features should build on this boundary rather than inventing parallel Those features should build on this boundary rather than inventing parallel
serialization paths. serialization paths.
@@ -46,9 +46,9 @@ random streams, and no dependency on a loaded gameplay scene.
1. ✅ Add a deterministic clock, seeded random source, and scenario runner. 1. ✅ Add a deterministic clock, seeded random source, and scenario runner.
2. ✅ Introduce serializable village, NPC, and resource-state records. 2. ✅ Introduce serializable village, NPC, and resource-state records.
3. **Next:** Bind `ResourceNode` presentation to resource records instead of 3. Bind `ResourceNode` presentation to resource records instead of owning
owning authoritative amount and reservation. authoritative amount and reservation.
4. Move target choice and reservation coordination out of 4. **Next:** Move target choice and reservation coordination out of
`WorldViewManager` into an action/target system with an active-world query `WorldViewManager` into an action/target system with an active-world query
adapter. adapter.
5. Split action selection, execution, and presentation travel. 5. Split action selection, execution, and presentation travel.