Causal trace¶
Causal trace
| Kind | Engine infrastructure (not a system, not toggleable, not in the graph) |
| Project | NextIteration.Engine/Trace/ (TraceRecorder, TraceStore, TraceQueries) |
| Exposes | ITraceStore; Explain, History, WhyChanged, Events, Decisions, Intents, TickDigest |
| Consumes | applied/rejected intents, decisions, events, propagations, destroyed nodes, player actions |
| Consumed by | the viewer (Explain this, timelines), the InterestScorer, the narrator (Phase 5), the harness and milestone tests |
| Status | designed · Phase 1 (#31) |
| PLAN | §13.5, §13.3, §10.1, §4.2 |
| Player | Explain this |
The graph is the present; the trace is the past. A trace record cannot affect the next tick — delete the whole trace and every subsequent tick is identical — so it is derived data, kept outside the graph, read by no system, never copied with a snapshot, not in the save file, and it outlives destroyed nodes. An NPC's memory of an event is a fact in the graph (and can be wrong); the trace is ground truth.
Records (per tick, in resolution order)¶
| Record | Fields |
|---|---|
| intent applied | tick, ordinal, intent (type, target, key, value/delta), Inputs if set, produced event ids, source |
| intent rejected / conflict | as above + reason, rival ordinal |
| decision | tick, actor, winning Option, top-3 runners-up, inputs, personality weights |
| event | id (tick << 20) \| ordinal, type, source, location, data, producing ordinal |
| propagation | source node, channel, per-hop (node, intensity) |
| node destroyed | kind, template, name, components at death |
| player action | player id, the action, the ordinals it became |
| rule fired (Phase 3) · oracle call (Phase 5) |
Full field lists on Trace records. Inputs on intents and options are what give a chain its next hop: FireSystem's ignition intent carrying smithy.temperature = 262, inn.ignition_point = 250 is why Explain can say because the smithy's heat crossed 250°.
Queries¶
Explain(eventId, depth = 6, breadth = 3) chain: event → intent → source → inputs → the intents that wrote them → … (max depth 20)
Explain(entityId) latest decision: winner, runners-up, inputs and each input's provenance
History(entityId, from, to) timeline: decisions, intents applied to it, events naming it, in world-time order
WhyChanged(nodeId, attribute, generation) the intent that wrote this value, and its source
Events(from, to, filter) Decisions(from, to, actor?, need?) Intents(tick, source?)
TickDigest(tick) stable hash over the tick's applied intents — the determinism signature
Endpoints: GET /worlds/{id}/explain/event/{eventId}, …/explain/entity/{nodeId}, …/history/{nodeId}?from&to, …/explain/change/{nodeId}/{attr}/{generation}.
What it does not answer: the state of the world at time T. "Was the inn on fire at 14:00" is a fold over the inn's history; "who was where" is a fold over containment changes. Full state at T is the ring buffer or a replay.
Storage tiers¶
| Tier | What | Phase |
|---|---|---|
| Hot | in-memory buffer, trace_buffer_ticks (default 2,000 = ten village days); the harness sizes it to its run; indexed by id, (node, attribute, generation), entity, source, time |
1 |
| Warm | append-only JSONL segments under saves/{universeId}/trace/, one per tick range, each with an index; Explain/History fall through; the hot buffer rebuilds from the newest segments on load; behind ITraceStore |
1 |
| Compaction | beyond trace_retention keep events and decision winners, drop intent detail and runners-up; aligned with LOD |
Scale |
| Cold | replay: seed + player-action log + oracle log regenerate any window from the nearest save | Scale |
Not a time-series database: every query is an id, entity or window lookup over an append-only log. Volume at village scale is a few hundred records a tick, tens of megabytes per ten days.
Four consumers¶
- Viewer —
Explainrendered as prose per record kind; the character card's timeline isHistory. - InterestScorer — chain depth and breadth of this tick's events, hot buffer only; replaces the fixed weight table.
- Narrator (Phase 5) — the chain is the RAG retrieval query.
- Milestone tests — "gathered at the campfire" is a fold over containment history; "fled" is a decision whose winning need is
safety; "the bucket race" is anintent_conflicton aVessel. If a story cannot be asserted from the trace, the trace is what needs fixing.
History¶
| Phase | Change |
|---|---|
| 1 | Introduced: records with ids and Inputs, the five queries and the digest, hot + warm storage, the "graph is the present" boundary. |
See also¶
From perception to Explain this · Trace records · Harness · Determinism