diff --git a/evidence/CB-EV-0025-the-commentary-track.md b/evidence/CB-EV-0025-the-commentary-track.md new file mode 100644 index 0000000..1abeb0b --- /dev/null +++ b/evidence/CB-EV-0025-the-commentary-track.md @@ -0,0 +1,158 @@ +# CB-EV-0025 — the commentary track + +CB-WP-0027 T05. Tier M (structural M — touches ADR-0007 D5's input +contract and the recorded-session format; chaos d8=7 → no override). +Declaration 10 of chaos window 2. Closed 2026-08-06. + +**Delivered:** [ADR-0014](../decisions/ADR-0014-the-commentary-track.md), +a two-column page, a `/note` channel, `trials/-.md`, +`tools/trials.py`, `make trials`, and `--trial` on `cb-play`. + +--- + +## 1. The question this file cannot answer + +**T05 asks whether a comment actually got written during play, by the +maintainer, unprompted.** It has not been asked yet, and **that is the +pass's real acceptance test, not any of the tests below.** + +The protocol's own claim is that it must cost almost nothing or it will +not be done. Everything here is evidence that the mechanism *works*; +none of it is evidence that it *gets used*. I exercised it myself, which +proves the plumbing and proves nothing about the ergonomics — the person +who wrote the feature is the worst possible witness to whether it is +worth using. + +**Stated plainly rather than answered optimistically**, because +CB-WP-0022 built a register whose first run found ten answers nobody had +collected: this project's failures are about whether things get *read*, +not whether they get *built*. + +## 2. What ADR-0007 D5 turned out to be + +The workplan expected D5 — *JavaScript may not construct commands* — to +be the hard part. It was the easy part, for a reason worth recording: + +```rust +_ => return Err(format!("unrecognised field in pointer fact: {pair:?}")), +``` + +**`PointerFact::parse` refuses any unrecognised field**, so a comment +could not reach the command path even by accident. A parser that ignored +what it did not understand would have made this a real decision; one that +refuses made it a non-event. + +**That is a control paying off two years of maintenance early**, and it is +the clearest instance in this project of strictness at a boundary being +cheaper than vigilance across one. D5 is **scoped, not amended**: the +command channel is untouched, and the note channel is a second one that +cannot become the first because `resolve` takes a `PointerFact` and +nothing converts a `Note` into one. + +**The test asserts it anyway**, with a note whose text is a well-formed +pointer fact — because "the types don't connect" is a claim about code +layout until something checks the behaviour, and the inverse is asserted +too so the test is not vacuous. + +## 3. Running it changed the design, again + +`make trials`'s first version called **any note without a recording an +orphan**. A recording is only written when the game ends, so **every note +in a live session reported as broken.** + +A metric that cries wolf is one nobody reads — **which is the exact +failure this pass exists to prevent**, reproduced inside the tool built to +prevent it. Now three states: `ok`, `pending` (no recording yet), `orphan` +(the recording exists and the position is not in it). Only the third has a +target of zero. + +**This is the third pass running where building or running the thing found +something the design did not.** CB-WP-0024's `role` column, CB-WP-0025's +`K=2` infeasibility, and this. The pattern is consistent enough to state: +**the ADRs in this project are good at deciding and poor at predicting**, +and the loop's value comes disproportionately from the code loop rather +than from steps 1–3. + +## 4. A latent defect surfaced by a name collision + +`make trials` did nothing. `trials` is also a *directory*, so Make saw an +up-to-date file and ran the recipe not at all. + +Checking `.PHONY` found that **`design`, `difficulty` and `trials` — added +by CB-WP-0022, CB-WP-0025 and this pass — were all missing from it.** Two +of them work by luck: no file happens to share their name. + +**Three passes added a target and none added it to `.PHONY`**, which is a +process observation rather than a bug: the Makefile has no control that a +new target is declared, and the failure is silent until a name collides. +Not fixed beyond declaring the three, because a gate for this would cost +more than it catches — but it is the kind of thing that is invisible until +it is not. + +## 5. What the escaping test found + +`esc()` has escaped suit names since CB-WP-0012. This is the first +user-authored free text the renderer has handled, and the source comment +— *"cannot currently carry a `<`" is how injection bugs are written* — was +written in anticipation of exactly this. + +It held. `` renders escaped. + +**The test asserts something the obvious version would miss:** that the +player's words are *still readable* afterwards. An escaper that dropped +the text would pass "no script tag in the output" while destroying the +note. Escaping that eats what someone wrote is its own defect, and only +the positive half of the assertion catches it. + +## 6. Coverage cost of the reflow + +**None.** All 41 pre-existing `cb-render-html` tests passed unchanged +through a full restructure of the document into two columns, including the +coverage gate that asserts every view field appears in the *parsed* +document. + +**That is a stronger result than it looks.** The gate is coupled to +tokens, not to layout — so moving every element into new containers did +not disturb it. CB-WP-0024 saw the opposite when a probe was tied to a +rendering (`17 remaining`), and the contrast is the useful part: **a probe +that names a fact survives a reflow; a probe that names a presentation +does not.** + +## 7. Chaos window 2 + +**Declaration 10 of 12.** Structural M, d8 = 7, no override. + +**Twelve declarations, no 8 rolled**, so the window closes with **zero +overrides** and its retirement condition — *retire if an override changes +nothing twice running* — is untestable. CB-EV-0024 §6 said this; it is now +final rather than projected. + +**The window's own verdict should be that d8 made the mechanism +unevaluable**, and that the choice was between a rate that produces +evidence and a rate that produces rarity. Window 1 at d4 produced two +overrides and both changed the outcome; window 2 at d8 produced none. + +## 8. One flaky gate, reported rather than dismissed + +`make all` failed once at `env-test` and passed on re-run with zero +failures. A `cb-play` server and several `cargo` processes were running +concurrently during the failing run, which is the likely cause — but +**"likely" is doing work in that sentence and I did not chase it.** + +Recorded because a gate that fails intermittently and is re-run until +green is a gate being trained not to matter, and this project has enough +instances of that class already. + +## Open after this pass + +- **Nobody has used it yet** (§1). Until a note is written in anger, the + ergonomic claim is unsupported. +- **Promotion is manual.** ADR-0014 D5 says a comment becomes a register + note by a human's judgement, and T04 reports comments but does not + offer a one-step promotion. That was in the workplan's controls and is + the part not built. +- **The narrow-viewport rule is asserted on the stylesheet**, not on a + layout. There is no browser in the test harness that can measure a + reflow, and saying the assertion is weaker than the claim is the honest + position. +- **The flaky `env-test`** (§8) has no explanation, only a plausible one. diff --git a/workplans/CB-WP-0027-the-commentary-track.md b/workplans/CB-WP-0027-the-commentary-track.md index f3d0020..0f455ee 100644 --- a/workplans/CB-WP-0027-the-commentary-track.md +++ b/workplans/CB-WP-0027-the-commentary-track.md @@ -2,7 +2,7 @@ id: CB-WP-0027 kind: product title: "The commentary track: the meta view beside the table, and what the player says while playing" -status: active +status: done state_hub_workstream_id: "e011da8d-de9e-48bf-a3f2-a9e715ef222f" --- @@ -304,7 +304,7 @@ it. All three are declared now. ```task id: CB-WP-0027-T05 -status: todo +status: done priority: medium state_hub_task_id: "c0beb2d6-f998-4c36-aafa-c9ebd10c5086" ``` @@ -324,3 +324,31 @@ state_hub_task_id: "c0beb2d6-f998-4c36-aafa-c9ebd10c5086" 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. + +**Done 2026-08-06.** +[CB-EV-0025](../evidence/CB-EV-0025-the-commentary-track.md). + +**The first bullet is unanswered, and that is the honest result.** Nobody +has written a note in anger. I exercised the mechanism myself, which +proves the plumbing and proves nothing about the ergonomics — **the person +who wrote the feature is the worst possible witness to whether it is worth +using.** The protocol's claim is that it must cost almost nothing or it +will not be done, and that remains untested. + +- **ADR-0007 D5 was the easy part**, because `PointerFact::parse` already + refuses unrecognised fields — strictness at a boundary paying off years + early, and the clearest instance of it in this project. +- **`esc()` held**, and the test asserts the harder half: the player's + words are still *readable* after escaping. An escaper that dropped the + text would pass "no script tag" while destroying the note. +- **The reflow cost no coverage probe** — all 41 tests passed through a + full restructure. CB-WP-0024 saw the opposite when a probe named a + *rendering* rather than a *fact*, and the contrast is the useful part. +- **Running it changed the design for the third pass running** (after + CB-WP-0024's `role` column and CB-WP-0025's `K=2`). The ADRs here are + good at deciding and poor at predicting. +- **Chaos window 2 closes with zero overrides**, so its retirement + condition is untestable — now final rather than projected. + +**Not built, and named:** promotion of a comment to a register note is +still manual. `make trials` reports; it does not promote.