clay-borg/workplans/CB-WP-0027-the-commentary-track.md
tegwick 5c6e322d5f
Some checks failed
ci / check (push) Failing after 4s
Sync hub state for CB-WP-0027
Workplan and task ids written back by fix-consistency C-06.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-06 10:19:16 +02:00

235 lines
9.8 KiB
Markdown

---
id: CB-WP-0027
kind: product
title: "The commentary track: the meta view beside the table, and what the player says while playing"
status: ready
state_hub_workstream_id: "e011da8d-de9e-48bf-a3f2-a9e715ef222f"
---
# Purpose
```
structural tier M (touches two canonical interfaces — ADR-0007 D5's
input contract, which currently admits only pointer
facts, and the recorded-session format, which is
`deny_unknown_fields`)
chaos d8 = 7 → no override
declared tier M
```
Declaration 10 of chaos window 2. Tier M: survey and decision merged into
one document; adversarial review optional.
## The maintainer's ask
> *"Extend the UI to provide the evaluation meta view to the game. Game
> interface to the left, meta and commentary to the right. As a test
> player I can provide comments about how I perceive the game or why I am
> playing a move — signal about unclear situations, frustration etc. —
> bound to the game state, reviewable for potential optimizations."*
## This is `GameDesign.md` §5's trial protocol, made ergonomic
**The protocol already exists and nobody would use it as written.** A
trial game is a `--record`ed session plus a sibling `trials/<date>.md`
written *afterwards*, from memory. The spec says it "must cost almost
nothing or it will not be done" — and then asks the player to reconstruct
their own reasoning after the fact.
A comment typed **while the position is on screen** is better in three
ways that matter to this project:
1. **It is contemporaneous.** *"Why am I playing this"* is available for
about ten seconds and then it is gone.
2. **It is bound to a position**, so it points at something replayable
rather than at a memory.
3. **It captures the class of signal nothing else here can.** Confusion,
frustration, and *"I don't understand what this does"* are invisible to
every gate in the project, and they are the observations that produce
design findings rather than engine findings.
## Why this is worth more than a comment box
**GameDesign §3.1 makes a note unreportable until it has a reproduction.**
Three findings are stuck there right now: F12 (GR-A13 wasted SOLVE), F14
(GR-E03/E04 never played) and F15 (the series question). Each is real and
none can go to `ground-game`.
**A comment bound to a recorded state, plus the recording, is the cheapest
reproduction a play-derived observation can have.** *"This felt pointless"*
attached to a replayable position is a different artifact from *"this felt
pointless"* in a file — the reader can go and look.
So the pass is not "add a text box". It is **closing the register's input
path for findings that come from playing rather than from building.**
## The failure this must not reproduce
**A pile of prose nobody reads is this project's signature defect.** The
message that sat unread for four days; the ten rulings that arrived and
were never collected. A commentary feature that stores comments and
surfaces them nowhere is that failure in a new medium, and it would be the
third instance.
> **Storage is not the deliverable. Surfacing is.**
T04 carries this and no task may be called done while comments are
write-only.
## Task: decide where comments live and what the page may send
```task
id: CB-WP-0027-T01
status: todo
priority: high
state_hub_task_id: "3586f3af-ad45-4bc6-bea2-b6eaedf05fbf"
```
`decisions/ADR-0014-*.md` (tier M merges survey and decision).
**Three questions, and the second is the one that bites.**
**(a) Where does a comment live?** Candidates: inside the recorded
`ScenarioFile`; in the `trials/<date>-<slug>.md` sibling `GameDesign.md`
§5 already specifies; or a third file keyed to the recording. Note
CB-WP-0026 added four fields to `ScenarioFile` and the schema is
`deny_unknown_fields` — **a scenario is a game record, and mixing a
player's prose into it may be the wrong shape.** Say which and why.
**(b) What may the page send?** ADR-0007 **Decision 5** currently binds
the browser to *raw pointer facts*`down on id`, `up on id` — and
forbids JavaScript from constructing commands. **A comment is not a
command**, so D5 is arguably untouched; but the transport widens from two
ids to arbitrary user text, and that must be *decided* rather than
assumed. State whether D5 is amended or merely scoped, and what stops the
new channel from becoming a command channel later.
**(c) What binds a comment to the game?** Round and step are readable but
weak. **The end-state hash is the strong binding** — it is what makes a
session comparable to its replay (`Summary::end_state_hash`), so a comment
keyed to a hash points at a position a reader can reach. Decide whether
the binding is the hash, the command index, or both, and what happens to a
comment whose position no longer replays.
**Also decide the retention question**, because it is a boundary this
project has not faced: these comments are **the maintainer's own words
about his own game**, and one of them will eventually be unflattering
about the design or about the engine. State whether they are private to
the repo, whether they travel to `ground-game`, and who decides.
## Task: the table on the left, the meta on the right
```task
id: CB-WP-0027-T02
status: todo
priority: high
state_hub_task_id: "0971185c-b72c-43ec-a356-c221ef6d8165"
```
Two columns: the game as it is today on the left, a meta panel on the
right. The log moves into the right column — it is commentary on the game,
not part of the table.
**What goes in the meta panel**, beyond the log and the comment box:
- the **session tally** (CB-WP-0024 T04), which currently only appears at
the end;
- the **register's open notes** for this game, if any — the point of the
panel is that the player can see what has already been observed;
- whatever CB-WP-0025's witness produces, **when it is wired** — it is not
yet, and this task does not wire it.
**Controls:**
- the layout must survive a narrow viewport — a two-column desktop layout
that unreadably overlaps on a laptop is a regression, and the existing
page is responsive by accident rather than by design, so this is the
moment it becomes deliberate;
- **every existing coverage probe must still pass.** `RENDERED` in
`lib.rs` asserts each view field appears in the *parsed* document; a
reflow that drops one fails the build, and that is the gate working;
- the game column must be usable with the meta column collapsed. A player
who does not want to write anything must not be worse off.
## Task: capture what the player says, bound to where they said it
```task
id: CB-WP-0027-T03
status: todo
priority: high
state_hub_task_id: "4a23ba0d-9b23-4381-b6b0-2b8959106270"
```
A comment box in the meta panel, posting to the existing guarded endpoint.
**The escaping is not incidental.** `esc()` exists and every interpolated
value goes through it, with a comment in the source saying *"cannot
currently carry a `<`" is how injection bugs are written*. This is the
first user-authored free text the page has ever handled, so it is the
first time that comment is load-bearing rather than precautionary.
**Controls:**
- **a comment containing `<script>` renders as text**, asserted on the
emitted document — the first real test of `esc()` against hostile input
rather than against suit names;
- a comment is bound to the position per T01's decision, and a test
asserts the binding **resolves**: a stored comment names a state that
the recording can reach;
- the empty comment is not stored — a blank note is noise in the register;
- **the game is playable with comments disabled**, and a test says so. The
commentary track must not become a dependency of playing.
## Task: surface them, or this pass has failed
```task
id: CB-WP-0027-T04
status: todo
priority: high
state_hub_task_id: "df8afbef-6ff7-4aa2-9ff7-b3fa05f676cc"
```
**The load-bearing task.** Comments must be readable *outside* the
session that produced them, by a command, without opening a file by hand.
- `make design` (or a sibling) reports comments **with their positions**,
because a comment without its position is prose again;
- a comment can be **promoted to a register note** — that is the input
path this pass exists to close, and it should cost one step;
- **age is reported.** GameDesign §3.1 expires notes at 30 days on the
existing `PROVISIONAL_WARN_DAYS` machinery; comments should not get a
private mechanism.
**Controls:**
- a comment written in a session is visible from a command in a *later*
session — the whole failure mode is signal that only exists while
someone is looking at it;
- **the reporting path is exercised by the self-test**, not only the
parsing. `design-baseline.py` had a self-test and a reporting path with
no CI, and the reporting path was where it rotted (ADR-0012 D8);
- promoting a comment to a note produces a register row that
`tools/design.py` accepts — if the register cannot express it, the shape
is wrong and that is a finding about ADR-0012, not a bug.
## Task: evidence
```task
id: CB-WP-0027-T05
status: todo
priority: medium
state_hub_task_id: "c0beb2d6-f998-4c36-aafa-c9ebd10c5086"
```
`evidence/CB-EV-0025-*.md`.
- **Whether a comment actually got written during play**, by the
maintainer, unprompted. The protocol's own test is whether it costs
little enough to use; anything else is a claim about a feature nobody
exercised.
- **Whether any stuck note moved.** F12, F14 and F15 are unreportable for
want of a reproduction; if the commentary path unblocks even one, that
is the pass's real result.
- **What the escaping test found**, since it is the first hostile input
this renderer has seen.
- **Whether the two-column layout cost any coverage probe**, and what that
says about how tightly the gate is coupled to the document's shape.
- **Quote CB-WP-0025's cost by re-running the instrument** — and note that
CB-EV-0019 §4's unbounded chain is still unbounded.