feat: add knowledge-gated pantry opportunities

This commit is contained in:
Rijad Zuzo
2026-07-13 00:46:56 +02:00
parent 9fcf6a0a58
commit c722e32a88
26 changed files with 2027 additions and 77 deletions
+13 -3
View File
@@ -17,6 +17,7 @@ SimulationClock
-> SimulationEventLog records completed facts
-> EventKnowledgeSystem records, ranks, transfers, and retains bounded knowledge
-> RelationshipSystem applies evidence-gated social consequences
-> FoodShortageOpportunitySystem projects one known unresolved need
-> WorldViewManager presents travel and NPC state
-> ActiveWorldAdapter supplies loaded-world positions/capacity
-> NpcVisual performs local navigation, animation, and transient reactions
@@ -38,6 +39,10 @@ would otherwise obscure that lifecycle:
retention/importance ranking;
- `simulation/relationships/RelationshipSystem.gd` owns directed relationship
queries, event-driven trust changes, and deterministic social tie-breaking;
- `simulation/opportunities/FoodShortageOpportunitySystem.gd` observes
immutable event references plus current pantry/NPC state, then owns the
bounded open/resolved pantry-restock lifecycle without changing resources or
assigning tasks;
- `simulation/persistence/` owns save-slot file safety;
- `simulation/state/` owns versioned serialized record contracts;
- `simulation/definitions/` owns stable IDs and immutable action/profession
@@ -58,6 +63,7 @@ hard to read.
| `simulation/events/` | Immutable event history and derived event queries |
| `simulation/knowledge/` | Per-NPC knowledge of objective event IDs |
| `simulation/relationships/` | Directed social consequences and relationship queries |
| `simulation/opportunities/` | Knowledge-gated unresolved-condition projections |
| `simulation/state/` | Versioned, serializable mutable records |
| `simulation/definitions/` | Stable IDs and immutable gameplay definitions |
| `simulation/persistence/` | Validated local save-file storage |
@@ -80,15 +86,19 @@ improving ownership.
ownership.
- Presentation may report facts and submit commands; it does not choose NPC
actions or own resource, storage, inventory, event, knowledge, relationship,
or reservation state.
opportunity, or reservation state.
- Inspector history is a read-only façade query over objective events and
retained knowledge. Relationship cues consume state-change signals and are
intentionally absent from saves and checksums.
retained knowledge. Opportunity presentation is likewise query-only.
Relationship cues consume state-change signals and are intentionally absent
from saves and checksums.
- Resource changes go through `ResourceStateRecord`, NPC inventory, and
`VillageEconomy`; `village.food` and `village.wood` are synchronized views.
- New mutable features define serialization and deterministic continuation at
the same time as their first gameplay use. Cross-record causes use stable
event IDs rather than object references or prose.
- Opportunity records reference stable NPC, storage, resource, trigger-event,
and resolution-event IDs. Their generator may observe authoritative state
and history, but it does not mutate the economy or command NPC behavior.
- Prefer one tested vertical behavior over a generic framework with no proven
consumers.
+8 -1
View File
@@ -705,10 +705,17 @@ Completed:
actions. A real evidence-caused trust gain produces one short amber blossom
above its observer, including in cinematic mode, without persistent or
simulation-owned animation state.
25. Knowledge-gated village need: a compact, cardless `Village need` line now
shows the real pantry target, food progress, and interested villager. That
person's inspector retains the open/resolved lifecycle and names the exact
NPC or player supply actor. The repeatable debug capture stages this from
live simulation state; world framing and the elevated follow camera remain
unchanged.
Next:
1. Implement one bounded Milestone 7 rumour/opportunity proof, as sequenced in
1. Prove the same opportunity lifecycle with one missing-wood `task_blocked`
condition before extracting shared generation rules, as sequenced in
`LEARNING_ROADMAP.md`.
Do not start with GIS data, a full city, a large asset pack, or more NPC
+37 -14
View File
@@ -37,22 +37,25 @@ transfer occurred.
## Persistence and determinism
`SimulationStateRecord` schema v7 stores the ordered event stream,
`SimulationStateRecord` schema v8 stores the ordered event stream,
`next_event_id`, directed relationships that may reference an exact event, and
per-NPC known-event references with first-acquisition provenance. Schema v1 and
v2 saves migrate to an empty stream beginning at ID zero. Parsing rejects
duplicate event IDs, invalid or duplicate knowledge references, impossible
communicator sources, relationship causes the observer does not know, and a
next ID that could collide with restored history.
per-NPC known-event references with first-acquisition provenance, plus
opportunity records that reference exact trigger/resolution events. Schema v1
and v2 saves migrate to an empty stream beginning at ID zero; world schemas
v1v7 migrate to an empty opportunity list. Parsing rejects duplicate event
IDs, invalid or duplicate knowledge/opportunity references, impossible
communicator sources, relationship causes the observer does not know, and next
IDs that could collide with restored history.
A successful food deposit can currently raise a hungry familiar NPC's directed
trust in its contributor only when that NPC knows the event. The actor and
living NPCs within the bounded witness radius receive a `KnownEventStateRecord`
at record time. Witness distance uses the event's captured position, never the
actor's later location. The relationship stores the same deposit event ID
rather than copied prose, so the inspector can resolve and display the real
completed fact. This is a first evidence-gated causal consumer of the event
stream, not general event sourcing.
Positive food deposits and positive NPC food withdrawals from
`village_pantry` into that actor's matching inventory are currently knowable.
The actor and living NPCs within the bounded witness radius receive a
`KnownEventStateRecord` at record time. Witness distance uses the event's
captured position, never the actor's later location. A successful food deposit
can raise a hungry familiar witness's directed trust; the relationship stores
that same deposit event ID rather than copied prose, so the inspector can
resolve and display the real completed fact. This is evidence-gated use of the
event stream, not general event sourcing.
Knowledge now records whether an NPC performed, witnessed, heard, or inherited
a fact from a legacy save. When an NPC arrives beside an already-working NPC at
@@ -72,6 +75,21 @@ evidence. Conversations prefer lasting direct facts, then the most recently
acquired direct fact. Communicated provenance snapshots how the speaker knew
the event, so a listener's memory stays valid after the speaker forgets.
`FoodShortageOpportunitySystem` is another read-only consumer of immutable
facts. A known positive NPC pantry withdrawal, combined with the pantry
currently being empty and a living critically hungry knower, can open one
`restock_empty_pantry` record. The opportunity does not perform a transaction,
assign an NPC, or append a quest-only event. It resolves only after the pantry
actually reaches its target through either:
- a later positive `storage_deposited` event from a real NPC inventory; or
- a later player `resource_extracted` event from an existing player-usable food
ResourceNode directly into `village_pantry`.
The exact trigger and resolution IDs remain in opportunity history. The active
trigger memory is protected until resolution, then returns to normal bounded
retention.
The food-loop regression verifies this chain:
```text
@@ -92,6 +110,9 @@ acquisition provenance, separately from three objective events the NPC
personally performed. A real trust-changing consequence emits one transient
amber blossom above its observer. The cue is presentation-only, remains visible
in cinematic mode, and is neither saved nor replayed after visual rebuild.
The village summary also shows one compact active need with its real food
progress and interested villager; only that villager's inspector retains its
open/resolved detail and names the exact supplier.
## Deliberate limits
@@ -104,3 +125,5 @@ hearing, personalized reinforcement/decay, multi-hop rumours, secrecy, false
beliefs, and multi-event causal graphs belong in later event/history slices.
They should extend this record family without making prose authoritative or
recomputing old evidence from current positions.
The current opportunity is likewise a single bounded projection, not a generic
quest, reward, acceptance, dialogue, or capable-helper framework.
+24 -3
View File
@@ -711,9 +711,30 @@ The compact history/reaction slice is complete:
slice.
This completes the first bounded Milestone 6 evidence-to-choice presentation
path without claiming full belief simulation. The practical next slice is one
bounded Milestone 7 rumour/opportunity proof without generalized distortion,
free-form dialogue, or a generic quest framework.
path without claiming full belief simulation.
The first bounded Milestone 7 opportunity proof is complete:
- a positive NPC food withdrawal from `village_pantry`, combined with the
pantry currently being empty, is the exact shortage evidence;
- the need opens only when a living critically hungry villager knows that
event through performance, witnessing, or the existing one-hop
communication contract;
- highest hunger and then lowest stable NPC ID select one interested villager,
with at most one open pantry need;
- schema-v8 opportunity records retain stable NPC, event, storage, resource,
and resolution IDs, and protect the trigger memory while the need is open;
- an exact later NPC food deposit or player resource extraction into the
pantry resolves the same record through the real economy/event history;
- generation neither mutates the economy nor commands NPC work, and it adds no
quest-only event, acceptance, reward, dialogue, multi-hop rumour, or generic
quest framework.
Milestone 7 is not complete. The practical next slice is a second bounded
unresolved-condition consumer: surface missing-wood `task_blocked` facts from
patrol or study as a cared-about woodpile-restock need, resolve it through real
NPC/player wood supply, define deterministic interested-party death/staleness
handling, and only then extract the lifecycle shared by two proven consumers.
Recently completed:
+46 -18
View File
@@ -2,7 +2,7 @@
> Agent-facing context for understanding the project quickly.
>
> Snapshot basis: repository state on July 11, 2026. Treat the code as the
> Snapshot basis: repository state on July 13, 2026. Treat the code as the
> source of truth when this document and the implementation differ.
See the [documentation map](README.md) for the authority and scope of each plan.
@@ -374,7 +374,10 @@ A small village panel displays:
decision reason, utility scores, directed familiarity/trust, and the exact
completed event that last changed trust;
- a compact selected-person history that separates up to four importance-ranked
retained memories from the NPC's three latest objective personal actions.
retained memories from the NPC's three latest objective personal actions;
- a cardless active `Village need` line sourced from the real pantry target,
food progress, and interested villager, with open/resolved detail only in
that person's inspector.
NPC name/profession labels, definition-driven colors and props, carried-food
visuals, compact task glyphs, and a brief amber blossom on real trust gains make
@@ -419,7 +422,10 @@ Focused `RefCounted` collaborators keep rule ownership visible:
one-hop communication, deterministic recent-memory retention, and stable
importance ranking for presentation/communication queries;
- `RelationshipSystem` owns directed relationship state, event-driven trust
consequences, and deterministic social queries.
consequences, and deterministic social queries;
- `FoodShortageOpportunitySystem` projects the first knowledge-gated unresolved
condition into a persisted open/resolved record without changing resources
or assigning work.
`SimulationManager` remains the scene-tree façade and signal boundary rather
than duplicating these responsibilities across additional manager nodes.
@@ -456,9 +462,10 @@ follow camera.
### `world/ui/ui.gd`
The UI subscribes to village, task, event, knowledge, and relationship changes.
It formats aggregate state and resolves known facts/relationship causes through
the event log without owning or recomputing simulation facts.
The UI subscribes to village, task, event, knowledge, relationship, and
opportunity changes. It formats aggregate state and resolves known facts,
relationship causes, and opportunity lifecycle details through manager queries
without owning or recomputing simulation facts.
## Current runtime flow
@@ -491,6 +498,7 @@ NpcVisual navigates through the active world
| -> SimulationEventLog appends completed facts
| -> EventKnowledgeSystem captures actor/nearby knowledge
| -> RelationshipSystem applies evidence-gated social consequences
| -> FoodShortageOpportunitySystem may open or resolve a real need
| |
| v
| village_changed signal updates the UI
@@ -527,6 +535,7 @@ NpcVisual navigates through the active world
│ ├── economy/ Inventory and storage transactions
│ ├── events/ Ordered event history and queries
│ ├── knowledge/ Per-NPC facts, provenance, transfer, and retention
│ ├── opportunities/ Knowledge-gated unresolved-condition projection
│ ├── persistence/ Validated local save-slot storage
│ ├── relationships/ Directed social consequences and queries
│ └── state/ Versioned simulation-state records
@@ -535,6 +544,7 @@ NpcVisual navigates through the active world
│ ├── communicated_knowledge_consequence_test.gd
│ ├── deterministic_simulation_test.gd
│ ├── food_storage_loop_test.gd
│ ├── food_shortage_opportunity_test.gd
│ ├── jajce_world_scaffold_test.gd
│ ├── knowledge_retention_consequence_test.gd
│ ├── jajce_runtime_integration_test.gd
@@ -543,6 +553,7 @@ NpcVisual navigates through the active world
│ ├── resource_node_player_parity_test.gd
│ ├── simulation_definitions_test.gd
│ ├── simulation_state_serialization_test.gd
│ ├── unit/test_food_shortage_opportunity_system.gd
│ └── witnessed_knowledge_consequence_test.gd
├── terrain/jajce/ Dedicated Terrain3D seed data and assets
├── tools/
@@ -575,9 +586,9 @@ These are expected prototype constraints, not necessarily isolated bugs:
gathering use `ResourceNode` instances with no fallback, food transfer uses
the typed pantry `StorageNode`, and patrol/study/rest use `ActivitySite`.
- Current NPC, village, resource, storage, event, knowledge, relationship,
clock, and RNG state serialize through world schema v7. F5/F9 provide one
validated local quicksave; a save menu, metadata, and player-transform
persistence remain deferred.
opportunity, clock, and RNG state serialize through world schema v8. F5/F9
provide one validated local quicksave; a save menu, metadata, and
player-transform persistence remain deferred.
- Simulation-owned resource records retain live amounts, reservations, and
usage definitions while ResourceNode scenes are unloaded.
- An explicit fixed-step clock converts frame delta into simulation ticks, but
@@ -590,11 +601,15 @@ These are expected prototype constraints, not necessarily isolated bugs:
located items.
- NPCs have home positions, schedule periods, carried food/wood, and directed
familiarity/trust. They retain direct or one-hop communicated knowledge of a
food deposit with first-acquisition provenance. Current trust causes are
lasting; other knowledge is capped and reviewed after one simulated day.
NPCs do not yet have wider social dimensions, goals, line-of-sight/hearing
evidence, personalized reinforcement/decay, false beliefs, or multi-hop
rumours.
food deposit or NPC pantry withdrawal with first-acquisition provenance.
Current trust causes and the trigger of an open opportunity are lasting;
other knowledge is capped and reviewed after one simulated day. NPCs do not
yet have wider social dimensions, goals, line-of-sight/hearing evidence,
personalized reinforcement/decay, false beliefs, or multi-hop rumours.
- One persisted `restock_empty_pantry` opportunity can emerge from a known
withdrawal plus current emptiness and critical hunger. It has exact NPC and
player supply resolutions, but no generic opportunity definitions, capable-
helper assignment, acceptance, rewards, free-form dialogue, or quest log.
- The reason inspector exposes current decisions, utility rejections, one exact
relationship cause, and a compact person-history view that distinguishes
importance-ranked retained memories from objective personal actions.
@@ -613,8 +628,8 @@ These are expected prototype constraints, not necessarily isolated bugs:
- Terrain3D and the bounded Jajce beauty baseline now run in the main game
scene; `Jajce Lookdev 01` and the runtime `Simulation Garden 01` are captured
as reproducible presentation baselines.
- Combat, companions, factions, politics, trade, rumours, quests, persistence,
and regional travel do not yet exist.
- Combat, companions, factions, politics, trade, generalized/multi-hop rumours,
a general quest framework, and regional travel do not yet exist.
- Stylized player/NPC silhouettes, water, foliage, and VFX support the current
build-in-public baseline, while blockout buildings and several work/resource
props remain visibly prototype-grade.
@@ -846,8 +861,21 @@ retention now keep current relationship causes lasting, cap other memories,
and forget routine facts at deterministic daily-sized reviews without deleting
the objective event. The selected-person inspector now shows lasting-first
retained memories beside objective personal history, and real trust changes
produce a short observer-only amber blossom without altering saved state. The
next systems slice is one bounded rumour/opportunity proof.
produce a short observer-only amber blossom without altering saved state.
The first bounded opportunity proof is complete. A positive NPC pantry
withdrawal plus current pantry emptiness opens one need only for a critically
hungry villager who knows that exact event. The schema-v8 record persists its
stable trigger, interested villager, pantry/food target, status, and later
resolution event; active evidence remains lasting. A real later NPC deposit or
player harvest into the pantry resolves it without quest-only history, economy
mutation by the generator, or AI assignment. The compact village/inspector UI
shows this lifecycle without changing the elevated follow camera.
Milestone 7 remains in progress. The next systems slice should prove the same
lifecycle with a missing-wood `task_blocked` condition and deterministic
interested-party death/staleness handling before extracting common opportunity
machinery.
The remaining simulation-garden target still aims for:
+12
View File
@@ -43,6 +43,18 @@ NPC generation chooses from the registry's stable IDs. NPC state stores and
restores those IDs as `StringName`, and rejects records that reference an
unknown profession or executable action.
## Opportunity vocabulary
`SimulationIds` also defines the first proven opportunity type,
`restock_empty_pantry`, and its `open`/`resolved` statuses. These are stable
serialized vocabulary, not editor-authored quest definitions. Dynamic trigger,
interested NPC, pantry/food goal, progress, and exact resolution-event identity
belong to `OpportunityStateRecord` and the focused opportunity system.
Do not extract a generic quest-definition registry until another real
unresolved-condition consumer proves which lifecycle fields and rules are
actually shared.
## Validation
The registry rejects:
+34 -4
View File
@@ -3,7 +3,7 @@
## Current contract
`SimulationStateRecord` is the versioned JSON boundary for the current
simulation. The current world schema is v7 and captures:
simulation. The current world schema is v8 and captures:
- simulation seed, tick interval, tick count, clock remainder, and elapsed
clock ticks;
@@ -19,14 +19,16 @@ simulation. The current world schema is v7 and captures:
ID that last changed trust;
- per-NPC known-event records that reference objective event history without
copying it, including first-acquisition method, acquisition tick, and
historical communicator provenance.
historical communicator provenance;
- opportunity records with stable type/status, interested NPC, trigger event,
target storage/resource/amount, and exact later resolution event identity.
The top-level identity is:
```json
{
"schema": "the_steward.simulation",
"schema_version": 7
"schema_version": 8
}
```
@@ -59,6 +61,8 @@ It also verifies clock remainder, resource amount/reservation/enabled
round-tripping, presentation unload/rebind, directed relationship/cause
round-tripping, divergent known-event state, communicated provenance, and
deterministic retention boundaries, and rejection of unsupported schemas.
Active and resolved opportunity round-tripping, contradictory target state,
invalid resource sources, and cross-record event references are covered too.
NPCStateRecord v2 adds the resolved travel destination and whether it is
active. Nested v1 NPC records migrate explicitly with no invented active
@@ -147,6 +151,30 @@ facts, and recent facts at least one simulated day old are removed at the next
deterministic daily-sized review. The objective event stream is never pruned by
this rule.
SimulationStateRecord v8 adds the top-level `opportunities` array and
`simulation.next_opportunity_id`. The first nested `OpportunityStateRecord`
schema stores `opportunity_id`, `opportunity_type`, `status`, `created_tick`,
`trigger_event_id`, `interested_npc_id`, `target_id`, `resource_id`,
`target_amount`, `resolution_event_id`, and `resolved_tick`. World schemas
v1v7 migrate explicitly to an empty opportunity list with next ID zero.
The bounded `restock_empty_pantry` contract accepts at most one open record.
Opportunity, trigger-event, and resolution-event IDs are unique and the next
ID must remain above restored history. The interested NPC, pantry, food
resource, and referenced events must exist. Its trigger is a positive NPC food
withdrawal from `village_pantry` to that actor's matching inventory; an open
record additionally requires the pantry to remain below its one-food target
and the interested NPC to have acquired that fact no later than creation.
Resolution references an exact later NPC inventory-to-pantry food deposit or a
player `resource_extracted` event from an existing player-usable food resource
into the pantry, with a matching resolved tick. Resolved history does not
require the pantry still to contain food because later consumption is valid.
While the need is open, its interested villager's trigger evidence is treated
as lasting during deterministic memory maintenance. Resolution releases that
fact back to the normal bounded-retention rules; it does not delete objective
event or opportunity history.
## Resource authority
`SimulationManager` owns `ResourceStateRecord` instances independently of the
@@ -183,11 +211,13 @@ This phase does not yet provide:
- a save-slot menu, metadata, thumbnails, autosaves, or multiple profiles;
- migrations from any historical world schema other than the explicitly
supported v1v6 layouts;
supported v1v7 layouts;
- player inventory or player relationship records;
- broader relationship dimensions, line-of-sight/hearing evidence,
continuous or personalized memory decay, reinforcement, false beliefs, or
multi-hop rumours;
- generalized opportunity/quest definitions, acceptance, rewards, assignment,
dialogue, or player-facing quest-log state;
- persistence for the player transform or presentation-only scene state.
Those features should build on this boundary rather than inventing parallel
+22 -5
View File
@@ -1,6 +1,6 @@
# Simulation Garden 01
Captured: 2026-07-12
Captured: 2026-07-13
## Files
@@ -29,10 +29,12 @@ $env:LOCALAPPDATA = 'C:\Users\Rijad\Documents\Simulation Game\logs\quality\godot
```
The script warms up `main.tscn`, verifies that the simulation and active NPC
visuals exist, stages a real food-deposit/trust consequence plus one wind gust,
captures the F10 debug presentation, then captures the cinematic presentation
with development labels and UI hidden. The trust blossom is restarted only for
the second framing so both captures show the same real consequence clearly.
visuals exist, stages a real food-deposit/trust consequence, a one-food pantry
shortage, the hungry interested villager's ordinary gather-food replan, and one
wind gust. It captures the F10 debug presentation, then the cinematic
presentation with development labels and UI hidden. The trust blossom is
restarted only for the second framing so both captures show the same real
consequence clearly.
## Review
@@ -109,3 +111,18 @@ consequence produces one brief amber halo-and-mote blossom above Tarik; it
remains visible when F10 removes the debug UI but does not become permanent
world clutter. Both refreshed images preserve the established elevated,
slightly staggered top-down camera.
## July 13 opportunity follow-up
The debug capture now leaves one real `restock_empty_pantry` need open. The
left summary puts the cardless need above routine recent events and names Tarik
as the critically hungry interested villager; his inspector shows the same
zero-of-one pantry target next to the exact withdrawal memory. Capture staging
then asks the existing utility selector to replan Tarik, producing `Gather
Food`, a real finite food target, and the honest reason `Critically hungry; must
find food` instead of a stale pre-shortage decision.
The inspector still fits the 1280×720 frame without adding another panel, and
the cinematic capture remains free of UI while preserving the task glyph,
trust blossom, and sparse calligraphic gust. Neither gameplay camera defaults
nor the established capture framing changed.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 418 KiB

After

Width:  |  Height:  |  Size: 419 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 446 KiB

After

Width:  |  Height:  |  Size: 457 KiB