M10: the seam for media, and no media
CI / Backend tests (push) Canceled after 0s
CI / Frontend lint + build (push) Canceled after 0s
CI / Docker image builds (push) Canceled after 0s

The media extension contract asks for a scene snapshot a future image or video
provider could be handed: location, who is present, what they hold, what must
stay true, and where in the story it sits. Building one was the milestone's
obvious first task, and it was the wrong one. That snapshot has existed since
M5. `narrative_state["scene"]` holds the summary, the location, the cast and the
coordinate it was written at; a validated `set_scene` event writes it, every
position snapshots it, and every head move restores it. It survives Undo, Redo,
Retry, divergence, Save Point restore and a process restart because it is the
authoritative state rather than a copy of it.

So there is no scenes table here. A second scene store would have been a second
answer to "where is the story now", with its own lineage rules to get wrong —
and the lineage rules are the expensive part, which is the argument for reusing
the ones that already work rather than against it. The Scene Packet is derived
on read, and its identity is computed from the campaign and the position rather
than allocated: the same position yields the same id in another process, after a
restart, and after the packet is thrown away and rebuilt, with no row to keep in
step. That is the part of a future media_assets table that would be expensive to
retrofit, so it is fixed now even though the table is not built.

One table, then: visual_profiles, the only thing the contract's scene list asks
for that nothing already stored. Campaign-scoped and not per-position, because a
character does not change appearance when the story forks — a reader who
diverged would otherwise lose their cast, and the same descriptors would land in
every per-position snapshot, measured at 245 copies of 367 bytes in a 120-turn
campaign to say something that never varies. Keyed by the M5 entity key rather
than a new identity namespace, and one table for characters, locations and items
alike, because a location is an entity with a type and splitting them would
reintroduce the genre shape M5 spent a milestone removing.

What the packet leaves out is the more interesting half. Not the transcript, and
not imported knowledge — none of it, not merely the sources marked hidden. The
rule is what the story established at this position, not everything the narrator
was told, and drawing it by class is what makes it hold for a secret nobody
thought to mark. A hidden Canon source proves it, with a positive control
showing the narrator did receive the sentinel the packet does not carry. Once a
validated event puts the observer in the room, the observer is in the packet:
that is no longer narrator-only knowledge, and a packet that hid it would be
hiding the story from itself.

The providers are contracts and nothing else. Protocols for image, video, audio,
speech and transcription, an empty registry, no adapter, no dependency, no
socket, and no media setting to point anywhere — a setting that exists can be
pointed at a cloud by mistake. A future provider endpoint must be loopback,
stricter than narration's trusted-LAN allowance, because a picture of a scene
carries the scene with it. Transcription returns an editable draft with no
commit method, so STT structurally cannot bypass the authoritative path.

Nothing here can write the story. Not by convention: no module under media/
imports the code that writes state, no media event type exists in the state
vocabulary, and every test in the authority suite compares the authoritative
document byte for byte either side of a media operation — including one where a
provider insists Alice is in a red coat in a corridor, and the campaign goes on
disagreeing.

One defect, found by the milestone's own tests. M10 first added a migration
creating an index that create_all already builds from the column, so an upgraded
database ended up with two indexes and a fresh install with one. Comparing the
two schemas is what caught it; neither database examined alone would have. The
migration is gone rather than renamed, and the right number of migrations for a
new table whose indexes are declared on its columns is zero.

Backend 1,191 passed / 14 skipped / 0 failed, 89 of them M10's. Frontend 145
passed. Lint, production build and Docker build clean. No frontend file changed:
M10 adds no reader-facing surface, and ordinary play — turns, state, memory,
knowledge, Undo, Redo, Retry, Save Point restore, restart — runs with no media
configuration, no warning, no connection attempt and no media row written.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qyn3oRd4D6pi72nKBG725B
This commit is contained in:
JesseMarkowitz
2026-09-07 03:41:04 -04:00
co-authored by Claude Opus 5
parent 44edece67e
commit 1013c94eb1
27 changed files with 5235 additions and 23 deletions
+38 -19
View File
@@ -3,8 +3,8 @@
**This file is the index. Start here.**
**Current state:** Phase 0 complete; AI-DnD forked as the production base;
milestones **M1 through M8 implemented and accepted**, and **M9 implemented and
awaiting review**. M1-M6 were accepted on the dates below (M3 and M4: 2026-09-03;
milestones **M1 through M8 implemented and accepted**, and **M9 and M10
implemented and awaiting review**. M1-M6 were accepted on the dates below (M3 and M4: 2026-09-03;
M5: 2026-09-04; M6: 2026-09-06). M5 and M6 were each accepted only after an
independent review found a real defect and a corrective pass fixed it.
@@ -27,8 +27,16 @@ a reviewer: a set of claims with the measurements attached, not yet a record of
acceptance. M8's report has moved to `archive/milestone-reports/`, which is
where a milestone report goes once the next milestone's report replaces it.
**Next: M10 — Future Media Extension Hooks Only.** It has not been started, and
no brief for it exists.
**M10 — Future Media Extension Hooks Only — is implemented and awaiting
independent review** (2026-09-07). `reports/M10-IMPLEMENTATION-REPORT.md` is the
implementer's account. It built the seam and no media: one `visual_profiles`
table, a scene packet derived on read, provider contracts with an empty
registry, and no dependency added. Its central finding is that the scene
snapshot the media contract asks for **already existed**, built by M5.
**Next: M11 — v1 Security, Long-Run, and Release Validation.** It has not been
started, and no brief for it exists. It also owns the four post-M8 hands-on
playtest findings recorded in `BUILD-MILESTONES.md`.
**Package version:** see `VERSION.md`, which records what each revision changed
and why.
@@ -90,7 +98,7 @@ Two standing qualifications:
| Document | What it is for |
| --- | --- |
| `SPECIFICATION.md` | What the product must do. The top of the authority order. |
| `TECHNICAL-DESIGN.md` | The selected architecture, including what M1-M9 built, recorded as fact. |
| `TECHNICAL-DESIGN.md` | The selected architecture, including what M1-M10 built, recorded as fact. |
| `DATA-MODEL.md` | Entities, the stored head, branch disposition, and the v3 export contract. |
| `STORY-BRANCH-SEMANTICS.md` | Undo/Redo/Retry/branch/take behavior, including the M3 ratifications. |
| `CONTEXT-AND-MEMORY.md` | Prompt assembly, summarization, branch-safe memory. |
@@ -118,9 +126,10 @@ Two standing qualifications:
10. `BROWSER-UX-SPEC.md`
11. `V1-ACCEPTANCE-TESTS.md`
12. `DECISIONS/` — all of them; they are short.
13. `reports/M9-IMPLEMENTATION-REPORT.md`, for what the most recent milestone
actually left behind — reading it as a claim to check, not a record, until
it is reviewed. Nothing in `planning/archive/` unless sent there.
13. `reports/M10-IMPLEMENTATION-REPORT.md` and
`reports/M9-IMPLEMENTATION-REPORT.md`, for what the most recent milestones
actually left behind — read as claims to check, not records, until they are
reviewed. Nothing in `planning/archive/` unless sent there.
## Architectural decisions
@@ -151,14 +160,19 @@ work until Phase 0 closes — which Phase 0 satisfied on 2026-09-01. It is in
`reports/` holds the report for the milestone most recently completed, because
that is the one the next milestone's planning has to consult:
- `reports/M10-IMPLEMENTATION-REPORT.md` — the M10 implementation: the media
seam, everything it deliberately did not build, and the evidence for K01-K04.
Written by the implementer for an independent reviewer, so it is a set of
claims with the measurements attached and **not** a record of acceptance.
- `reports/M9-IMPLEMENTATION-REPORT.md` — the M9 implementation: the measured M8
portability baseline it started from, the final bundle contract, and the
evidence for every acceptance test it claims. Written by the implementer for
an independent reviewer, so it is a set of claims with the measurements
attached and **not** a record of acceptance. Its §W carries the M10-M11
handoff.
evidence for every acceptance test it claims. Its §W carries the M10-M11
handoff and its §Y holds the post-M8 playtest findings.
**It stays here until M10's report replaces it.**
**It stays here rather than moving to the archive**, against the usual
rotation, because M9 has not been accepted yet: a reviewer of either milestone
needs it, since M10 built on M9 and its baseline is M9's. It moves once M9 is
accepted.
Completed earlier milestones are in `archive/milestone-reports/`, which M8's
report joined when M9's was written: a milestone report is useful during the
@@ -293,20 +307,25 @@ Milestone M9 COMPLETE — awaiting review (2026-09-07)
migration hardening bundle format v3; SQLite online backup
|
v
Milestone M10 NEXT — not started
future media extension hooks see BUILD-MILESTONES.md
Milestone M10 COMPLETE — awaiting review (2026-09-07)
future media extension hooks reports/M10-IMPLEMENTATION-REPORT.md
scene packet derived, not stored; no media
|
v
Milestone M11 see BUILD-MILESTONES.md
Milestone M11 NEXT — not started
v1 security, long-run, release see BUILD-MILESTONES.md
validation also owns the post-M8 playtest findings
```
## Stop Rule
**One milestone at a time. Do not begin a milestone before its brief exists.**
**No M10 brief has been prepared**, and M9 is not accepted — it is implemented
and awaiting an independent review. Writing the M10 brief is the action after
that review closes, informed by the M9 report's §W.
**No M11 brief has been prepared**, and neither M9 nor M10 is accepted — both
are implemented and awaiting independent review. Writing the M11 brief is the
action after those reviews close, informed by the M9 report's §W, the M10
report's handoff, and the four post-M8 playtest findings in
`BUILD-MILESTONES.md`.
All three questions the M8 debt raised against M9 are settled and recorded:
the bundle carries historical context snapshots (`DATA-MODEL.md` §29); story