# CB-EV-0014 — what the human check bought CB-WP-0016 T03. Measured 2026-08-02 at `4df2d0a`+. Pass kind `product`, tier **S** (chaos d4=3, no override). Declaration 11 of 12. Cost quotes **CB-WP-0015's** figure, per CB-EV-0012's rule and with the correction CB-EV-0013 §5 attached to it. See §5. --- ## 1. The check found a defect every test in the repo was blind to CB-EV-0012 §4 kept INTENT stage 1 open on one action the loop could not perform. The maintainer ran it. **The table reads. The drag did not work.** Diagnosed against the live server *before* any code changed, which is what made the rest cheap: ``` POST down=action-attack&up=seat-1 → ok (the game advanced) POST down=action-attack&up=action-attack → "not a legal move here" ``` Socket, token guard, `resolve` and dispatch: all correct. The defect was in the page, and it had a root cause worth more than the instance: > **Drop targets were `id`s, and an `id` must be unique.** So exactly one > element could ever be `seat-0`. The relationship-graph circle took it, > and the seat *card* — which every action card's own text points at, > *"drag Attack onto a seat…"* — silently had none. A seat is drawn twice and both drawings are the seat. The document model could not express that. ## 2. Why nothing caught it, stated precisely | control | why it was blind | |---|---| | `jsrun::gesture` | calls `__down(id)`, which synthesized `{target:{id}}`. It feeds element ids straight in and **never hit-tests** — it establishes *"the script posts the ids it was given"*, never *"there is an element there to give"* | | the 42-path coverage gate | asserts each view field is present in the **parsed document**. A `
` with no id satisfies that perfectly | | `resolve`'s unit tests | test the mapping from a fact to a command. The fact never arrives | | M-D1-MUT | its population is the AM-* acceptance rows. None of them is about the page | Every one was green. This is the shape CB-WP-0015 closed one layer in — a harness answering a narrower question than its name implies — recurring in the presentation layer. ## 3. The fix, and the check that is honestly insufficient **Drop keys are now `data-drop`, not `id`.** Any number of elements may carry the same key, so a seat is droppable on its card *and* on its graph node. Measured on the live page: `seat-0`, `seat-1`, `seat-2` each appear **twice**; `id` survives on exactly one element, `cb-status`, which is the only one the script looks up. Two checks, and the difference between them is the finding: | check | catches the reported defect? | |---|---| | **every offered affordance names a key that exists** — drives four real bot games through `Policy::choose`, renders at every real decision point | **NO.** `seat-0` *did* exist, on the graph circle | | **every seat card is a drop target, not only the graph node** | **yes** | The general check is worth having — it fails when a target is wholly absent, which is a real class — but **it would not have found the bug the maintainer found**, and saying otherwise would be the exact error this project keeps catching. An existence check over a whole document cannot tell you the element the user is being *pointed at* is the one that works. Hooking `Policy::choose` rather than re-driving the game by hand matters: those are the same decision points `cb-play --serve` renders at, with the same `legal` list. A hand-rolled walk would be a second implementation of the loop, free to agree with itself while disagreeing with what ships. ### Mutations, each red for its stated reason | mutation | result | |---|---| | the seat card loses its drop key — *the reported defect, reintroduced* | red, **and only the targeted test fired**; the general one stayed green | | the table stops being a drop target | red — *"whose DROP id `table` is not an element in the document"* | | the silent `return` comes back | red — *"a drop on nothing said `""`"* | ## 4. Silence was the second defect `SCRIPT` did `if (!down || !up) { down = null; return; }` — no POST, no status line, nothing at all. **That is why a human sitting in front of it could not tell a broken target from a working page.** The Rust side already held the right principle: `resolve` refuses rather than substituting a default, because *"a drag that means nothing must mean nothing, not the first legal move."* Refusing is right. Refusing **silently** is not, and the two had been conflated. The page now reports the raw fact — *"took action-attack, let go over nothing droppable"*. It names elements, not moves, so ADR-0007 control 5 is intact and the body-shape assertion still holds. ## 5. What the human check cost, and what it bought Stage 1 was held open on this check for **two passes** (CB-WP-0014, CB-WP-0015), against a standing temptation to close it on green tests — CB-EV-0012 §4 recorded that temptation explicitly and refused it. It bought a defect that made the stage's headline interaction **non-functional on its primary target**, plus a root cause in the document model, plus a control class that did not exist. Two passes of delay was the right price, and the reasoning that kept it open — *"no test in this repo can reach it"* — was exactly correct rather than merely cautious. **The stage does not close here either.** The fix is verified by tests, by mutation, and against a live server; it is **not** verified by a human dragging. That is the same standard that found this, and the same one that would have missed it. | pass | kind | responses | cost | $/response | |---|---|---|---|---| | **CB-WP-0015** | product | ~~136~~ **166** | ~~$15.14~~ **$22.70** | ~~0.111~~ **0.137** | | CB-WP-0016 | product | *provisional — not quoted* | | | **CORRECTED 2026-08-02 (CB-EV-0015 §6).** This file originally reported CB-WP-0015 at **$15.14 / 136** and claimed that figure was *"the first this project has quoted at a boundary that had actually settled."* **The claim was false and the number was wrong.** $15.14/136 was read from `make status` during CB-WP-0015 itself and carried forward — it was that pass's own in-flight figure, which is precisely what CB-EV-0012's rule exists to forbid. Measured after CB-WP-0017's declaration closed the window: **$22.70 / 166**, higher by 50%. So the defect is not only the boundary CB-EV-0013 §5 identified. It is that a figure gets *read once and quoted later*, and a number read earlier in a session is an in-flight number no matter which pass's name is on it. ## 6. Open - **INTENT stage 1: still one human verification**, now of a fix rather than of an unknown. `cb-play --serve 0`, drag an action onto a seat *card*. - **The self-quoting rule still names the wrong boundary** — quote two passes back. Owed since CB-EV-0013 §5. - **AM-4b's scope defect (408,237 uncounted lines)** and its unmeasured proc-macro share. - **`python3` as a toolchain dependency was never argued.** - **AM-4a cannot survive stage 2** — 1,741,979 against 161,000. - **ADR-0007 D3's acquisition rule** remains unratified after deciding two dependency questions. - **Chaos: 11 of 12 declarations, 1 override.** The calibration window closes on the next declaration and owes an evaluation.