# CB-EV-0018 — four human checks, four sets of defects no test could reach CB-WP-0020 T06. Measured 2026-08-03 at `5e06a7d`+. Pass kind `product`, tier **S** (structural S; **chaos d8 = 8 → OVERRIDE, drawn S**). Declaration 3 of chaos window 2. --- ## 1. What the check found, and what the suite said about it Seven items. **Item 1 passed** — the resting affordance reads without touching anything. Every other one was a defect, and `make all` was green for all of them. | # | reported | cause | |---|---|---| | 2 | *"as if we have two cards now"*, the line break vanishes | the ghost was a `textContent` copy of the card | | 3 | *"upper and left borders … hidden"*, seat highlight *"quite large"* | `outline` + `outline-offset` drew a **second** rectangle; an SVG viewport clips it | | 4 | *"replacing the content … breaks the visual clue"* | the explanation **replaced** the ghost's label | | 5 | status line *"switches only if i put back a card"* | see §3 — not reproduced, and fixed anyway | | 6 | *"cant follow the actions of the other players"* | seat cards rendered `Selection { action: Solve, … }` — `Debug` on a player surface | | 7 | *"game over"* wrong when the group succeeded; no way to play again | the ending was written for one outcome and one game | ### Could any of them have been caught mechanically? Honestly, **two of the seven**, and neither by a check that existed: - **#6** is the same `{:?}`-on-a-player-surface defect the log fixed in CB-WP-0018, in a place that pass did not look. A grep for `{:?}` in emitted output would find it, and that check does not exist. **Worth building.** - **#7's headline** is a branch nobody wrote a case for; a test asserting the ending page differs on `group_success` would have caught it. **The other five cannot be caught here and saying otherwise would be the error this project keeps naming.** #2, #3 and #4 are about what a layout *looks like*; #5 is about which element a browser reports under a pointer. QuickJS has no layout engine and no hit-testing, and a stub that grew one would be asserting against my model of a browser rather than a browser. ## 2. The border moves, nothing else does Adopted as instructed: a legal target restyles its **existing** border rather than drawing a new box. ``` .dropok{border-style:dashed;border-color:#9cf;background:#1d2a33} .dropok circle,.dropok rect{stroke:#9cf;stroke-dasharray:5 3} ``` That is the whole fix for the missing top and left edges — an `outline` on an SVG `` is clipped by the viewport, and on a card it collided with the neighbour's margin. It also removes the oversized seat highlight, because the border was always the right size. **A border already in the layout cannot move the layout**, which is what *"more stable and less complicated"* was asking for. ## 3. The report I could not reproduce, and what I did instead Item 5 said the *"nothing droppable"* message never appears. The harness test for it passes, the page has real gaps to drop into, and I have no browser — so I could not reproduce it, and **the task said not to fix a message that already works.** The likeliest explanation is not the message but **which element the browser reports**: for touch and pen a browser implicitly captures the pointer to the `pointerdown` target, so `e.target` on `pointerup` is the element you *started* on wherever you release. That would make every drop look like a drop-on-itself — which is exactly the other half of the report, *"switches only if i put back a card, then showing `action-attack -> action-attack`"*. So the fix is to stop asking the event and ask the document: `document.elementFromPoint(clientX, clientY)`. **That is correct under both explanations** — with a mouse it returns the same element `e.target` would; with capture it returns the truth instead of the capture target. **Recorded as unreproduced, not as diagnosed.** If item 5 still misbehaves after this, the cause is something else and this note is the starting point. **And the refusal was written in element ids.** `action-attack -> action-attack is not a legal move here` is the vocabulary of the DOM on the one surface a player reads when something goes wrong. It now says *"Attack needs to be dropped on something"* or *"Attack on P2 is not a move you can make right now"*, and a test asserts no `action-` id leaks into it. ## 4. Two defects my own tests found while fixing these **The selection renderer dropped a field.** `selection_words` matched on `(target, problem)` and showed only the target when both were set. The 42-path coverage gate failed the build: *"claimed rendered, but absent from the emitted document: selections.\*.problem"*. The aggregate does not currently produce both — but a renderer that silently drops one is the omission class this crate exists to guard against, and the gate does not care whether the case is reachable today. **"Play again" moved the game to a new port.** The first version worked end to end and would have been useless: `run_game` bound a fresh listener per game, so dealing a second game left the player's tab pointing at a dead port — the CB-WP-0018 defect returning by a different route. The listener is now bound once per **session**. `play_again_deals_a_second_game` catches it, and it asserts the second game is a **different deal**, not merely that a second game happened — a seed that did not advance would have satisfied a naive count. ## 5. Chaos: the first override at d8, and it changed nothing `d8 = 8` fired on the **second roll** at the new rate and drew **S**, which is what the structural derivation already said. **That is one half of window 2's retirement condition** — *retire if an override changes nothing twice running*. **One.** If the next override also changes nothing, the mechanism goes. Worth stating plainly so it is not mistaken for evidence either way: an override firing on roll 2 of 12 at a 1-in-8 rate is unremarkable luck, and drawing the structural tier is a 1-in-3 outcome. Neither number says anything about whether d8 was the right rate. **The window needs its twelve.** ## 6. Cost | pass | kind | responses | cost | $/response | |---|---|---|---|---| | **CB-WP-0019** | meta | 117 | **$38.54** | 0.329 | | CB-WP-0020 | product | *provisional — not quoted* | | | Read by re-running `make status` at the moment of writing, per the rule CB-WP-0019 wrote. CB-WP-0019 was last reported at $34.80/107 and has settled at **$38.54/117** — **eight for eight**, and the first one under 20%, which is what re-running at quote time is supposed to do. **Meta budget: back under the line** — CB-WP-0020 is product work, which is what the 27% breach called for. ## 7. Open - **The human check is four for four.** Every run has found something the suite called green. Its cost is one maintainer session per pass; its yield so far is a broken drag, a lying affordance list, an invisible ending, and this set. **It should stay a gate on stage 1.** - **A `{:?}`-in-emitted-output check** would have caught item 6 and does not exist. Cheap; owed. - **The engine still has not imported the edition data**, now that GROUND-WP-0002 T01 has ruled it authoritative. That is the next product pass, and it is what makes the ending's `0` scores and `winners nobody` meaningful — ~~confirmed as the stand-in's doing, not a scoring bug~~. **CORRECTED 2026-08-03 (CB-WP-0021):** overstated. The `0` came from no Problem being claimed at all. The *threshold* gap is independent of the dataset — GR-S01 deals 2/3/4 of the five problems, so 4/6/9 points are in play against thresholds of 5/7/9, unreachable at 2p and 3–4p with either dataset. - **`ground-game` owes ten rulings** (U1–U10) and SOLVE's legality. - **Chaos: 3 of 12 in window 2, one override, changed nothing.**