# 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.