M5: genre-neutral authoritative narrative state, with review corrections
Replaces AI-DnD's RPG relative-delta world state with the genre-neutral typed
narrative state of ADR 010: explicit, absolute, allowlisted events proposed by
the model, validated by the application, applied to one authoritative document,
and snapshotted per position so restore stays a row read.
This commit includes the corrective pass that followed the independent review
in planning/reports/M5-IMPLEMENTATION-REPORT.md. The invariant it exists to
hold is:
visible active transcript position == stored head == authoritative state
Narrator editing (D10, STORY-BRANCH-SEMANTICS §§14-15)
A narrator edit no longer rewrites a row. It returns to the state before the
turn, takes the reader's exact text as the accepted narration, re-derives the
state that text implies, and becomes a new active continuation — while the
original narration keeps its words, its live flag and its whole future as
retained history. At the tip the correction is another take; with story below
it, it forks. No new history machinery: this is the existing fork/take/head
path with the reader's text in place of a generated reply. The §14A refusal
is therefore gone for narrator turns, and remains only for player input.
Pre-M5 positions
Migration 88 backfills the empty narrative document onto every action written
before M5, and a missing snapshot now restores the empty document instead of
leaving the previous position's state standing. Restoring to an old Save
Point no longer leaves a later position's entities and facts on screen.
Narrator context
Replayed history carries prose only; the machine-readable block is no longer
reconstructed into past turns, where it contradicted the authoritative state
in the same prompt. A fact withdrawn by a manual correction is now named as
no longer true, with the reader's reason, rather than silently dropped.
Also
- state_changes joins the action-list bulk read, removing one query per row.
- Extraction takes only the application's own protocol payload: an ordinary
```json or ```python block in a story survives, and a mangled proposal
still does not reach the reader.
Planning: ADR 013 records the authoritative document shape; §§14-15/14A, D10,
C04 and BUILD-MILESTONES are updated to describe what exists. Debt is recorded
against M8 (scenario editor UX) and M9 (export of the audit trail).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PWU4gTfLYY6Qq9U7aa9Qw2
This commit is contained in:
co-authored by
Claude Opus 5
parent
62a997f364
commit
b7005e6fdd
@@ -517,6 +517,31 @@ Mara never learned where the silver key was found.
|
||||
- correction is auditable,
|
||||
- old transcript is not silently rewritten unless explicitly edited.
|
||||
|
||||
### Result — PASS for the live campaign (M5 corrective pass, 2026-09-04)
|
||||
|
||||
The M5 review found the first condition failing: the state section dropped a
|
||||
withdrawn fact and the replayed history handed it straight back as an accepted
|
||||
event, in the protocol's own words, with nothing saying it had been corrected.
|
||||
Two changes fixed it, and both are pinned by
|
||||
`test_c04_a_withdrawn_fact_does_not_come_back_through_history`:
|
||||
|
||||
- replayed history is prose only — the machine-readable block is no longer
|
||||
reconstructed into past turns, so a turn's record of what was true *then*
|
||||
cannot contradict what is authoritative now;
|
||||
- a withdrawn fact is named in the state section under "No longer true — do not
|
||||
treat these as established", with the reader's reason, rather than silently
|
||||
omitted. Omitting it left the narration that first asserted it as the only
|
||||
account in the prompt.
|
||||
|
||||
The old transcript is not rewritten: an invalidated fact stays in the document
|
||||
with its status, its reason and its provenance.
|
||||
|
||||
**Carried debt, deferred to M9 (export/recovery):** a campaign's `state_events`
|
||||
and `state_proposals` are not carried in an export, so an imported copy keeps
|
||||
the correction's *effect* — the fact is still marked `manual_correction` — but
|
||||
reports zero audit events. The auditable condition therefore holds for a live
|
||||
campaign and not across a round trip.
|
||||
|
||||
---
|
||||
|
||||
## C05 — Canon Beats Reference
|
||||
@@ -721,25 +746,41 @@ Mara wears a green cloak.
|
||||
- downstream state is re-evaluated,
|
||||
- old version/future remains retained/disposable.
|
||||
|
||||
### Milestone ownership
|
||||
### Result — PASS (M5 corrective pass, 2026-09-04)
|
||||
|
||||
All three pass conditions stand for v1. They are delivered across three
|
||||
milestones, and this note records which is which rather than reducing the
|
||||
requirement:
|
||||
All three pass conditions are met, and each was demonstrated rather than
|
||||
inferred.
|
||||
|
||||
- **Edit becomes authoritative on the active path.** The reader's text is stored
|
||||
verbatim, with only the protocol block stripped, and no model is called
|
||||
(`test_the_corrected_text_is_used_verbatim_not_regenerated`).
|
||||
- **Downstream state is re-evaluated.** The state is derived from the snapshot on
|
||||
the node before the corrected turn and put through the normal validation path,
|
||||
and the campaign's live document then equals the document stored at the head
|
||||
(`test_editing_a_narrator_turn_with_visible_descendants_forks`, and the
|
||||
live-state/head-snapshot assertion carried by every test in that group).
|
||||
- **Old version/future remains retained/disposable.** Nothing on the departed
|
||||
line is written to: the original node keeps its words and its live flag, and
|
||||
every row played after it still exists
|
||||
(`test_the_old_narration_and_its_future_leave_the_active_transcript`,
|
||||
`test_editing_a_narrator_turn_with_an_undone_future_keeps_it`).
|
||||
|
||||
Verified in a real browser on the case the M5 review reproduced as broken:
|
||||
correcting the earliest narrator turn with four turns of story on screen, then
|
||||
checking the transcript, the retained rows, the state panel, the live document
|
||||
against the head snapshot, Undo/Redo, and the next turn's assembled prompt —
|
||||
16 of 16 checks.
|
||||
|
||||
The delivery history, kept because it explains the shape:
|
||||
|
||||
- **M3 — safe history behavior.** Replaying a narrator turn with different text
|
||||
forks, keeps the original take and its future, and starts the new continuation
|
||||
from the correct earlier state. In-place editing of a turn is **refused** while
|
||||
story descends from it off screen, so retained history cannot be made to
|
||||
contradict itself unseen (`STORY-BRANCH-SEMANTICS.md` §14A). Delivered.
|
||||
- **M5 — authoritative state re-evaluation.** The second pass condition. Making a
|
||||
hand-typed narrator correction authoritative and re-evaluating the state it
|
||||
implies requires the narrative-state extraction pass, so it is completed there,
|
||||
and the §14A refusal is replaced by it. Outstanding.
|
||||
- **Later browser UX work — the finished editing workflow.** How the user reaches
|
||||
and confirms the operation. Outstanding.
|
||||
|
||||
D10 is therefore **not** satisfied at the end of M3, and is not scored as such.
|
||||
forks and keeps the original take and its future. In-place editing was
|
||||
*refused* while story descended from a turn off screen.
|
||||
- **M5 — authoritative state re-evaluation**, and the refusal replaced. A
|
||||
narrator edit now forks rather than rewriting a row, so the off-screen case it
|
||||
refused is simply handled (`STORY-BRANCH-SEMANTICS.md` §§14-15).
|
||||
- **Later browser UX work.** How the reader reaches and confirms the operation
|
||||
is M8's; the operation itself is complete and reachable through the ✎ control.
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user