Views, snapshots and the ring buffer¶
ReadOnlyGraphView · SnapshotManager
| Kind | Engine core + infrastructure |
| Project | NextIteration.Core/Graph/ReadOnlyGraphView.cs, NextIteration.Engine/SnapshotManager.cs |
| Exposes | the per-phase view; /snapshots, /snapshots/{tick}, /rewind |
| Consumes | the live graph; the player-action log (for replay) |
| Consumed by | systems (view); the viewer's timeline; fork (Phase 3) |
| Status | designed · Phase 1 (#28, #32) |
| PLAN | §5.1, §18.6, §13.3 |
| Player | The timeline |
Two different things share the word "snapshot". Keeping them apart is the Phase 1 decision.
The per-phase view: a wrapper, not a copy¶
Systems in a phase must all read the same state and never each other's writes. Because the resolver applies the phase's batch only after the last system has returned, nothing writes to the live graph while systems run — so ReadOnlyGraphView is a read-only wrapper over the live graph, frozen by construction, with no mutation surface and zero copying. The Phase 0 spike deep-copied the graph three times a tick; that was an artefact of the earlier apply-per-system model. The host serialises ticks and API reads with a reader-writer lock so a GET never observes a half-applied batch.
The ring buffer: keyframes + replay¶
The last 200 ticks are reachable for rewind, step-back and "watch from here". SnapshotManager takes a full clone every keyframe_interval ticks (default 50) and reconstructs any buffered tick by loading the nearest keyframe and replaying forward with the player-action log. Deterministic replay is what makes this correct; the golden test (Determinism) is what guarantees it. Four keyframes instead of 200 clones; a scrub lands in tens of milliseconds at village scale.
POST /worlds/{id}/rewind { tick: 1180 } → load keyframe 1150, replay 30 ticks, enter Replaying
GET /worlds/{id}/snapshots → { from, to }
GET /worlds/{id}/snapshots/1180 → the reconstructed graph
In Replaying state the engine reproduces exactly what happened; leaving it and injecting a new action is what Phase 3 calls a fork.
The trace is the other half¶
State at tick N plus the causal trace from N onward determines any later state; the trace holds changes, the buffer holds states. A consumer that needs "the world at time T" uses the buffer or a replay, never the trace.
When to revisit¶
The harness reports tick duration p50/p95. Copy-on-write or structurally shared graphs are the Scale-phase answer if p95 ever exceeds 5 ms on the village.
History¶
| Phase | Change |
|---|---|
| 1 | Introduced: zero-copy view, keyframe ring buffer with replay. |