# CB-EV-0023 — the table you can watch CB-WP-0024 T05. Tier S (structural S — renders state the projection already carries; chaos d8=6 → no override). Declaration 7 of chaos window 2. Closed 2026-08-05. **Delivered:** the ending control says what it does and the page acts on it; draw and discard drawn as stacks; each seat's play drawn as a card; a session tally across games. Five remarks from play, four addressed (remarks 2 and 3 are CB-WP-0025). --- ## 1. How many of the five remarks were already implemented **Three of five were data the projection already carried, rendered as text.** That is the finding this pass is really about, and it was established by reading the code before writing the workplan rather than by building anything. | remark | what was actually missing | |---|---| | follow the other players | nothing in the model — `selections` project as `Shown` after Reveal and were already drawn, **as sentences** | | draw and discard stacks | nothing in the model — `solution_deck_len` and `solution_discard` were one line of text | | show the scores | nothing at all — `personal`, `mastery`, `winners`, `total`/`threshold` were already drawn | | the ending button | a real defect, two of them | | a cumulative score | genuinely absent | **So the table's problem was legibility, not content.** A renderer can show every field it is given and still be unreadable, and the coverage gate — which asserts every view field appears in the parsed document — passes either way. It is a completeness gate, and completeness was never the issue. **That is worth naming as a gap in the controls**, not as a criticism of them. `every_view_field_is_classified_in_the_emitted_document` proves nothing is silently omitted. Nothing proves it is *readable*, and nothing could, cheaply. The maintainer playing the game is the instrument, which is what makes remarks like these worth more than their length suggests. ## 2. The defect that mattered was untestable, and that is why it survived The ending control was labelled *"close — I have read this"* while `hotseat.rs` read it as **stop the server**, and acknowledging it changed nothing: the tab kept a full table and a `play again` pointing at a closed port. The label was a wording bug. **The second half survived for a structural reason:** > `jsrun`'s `fetch` stub returned `{then: function () { return this; }}`, > which never invoked its callbacks. **Every line of the script that > reacts to what the server said was unreachable from every test in this > project.** The `ok` → reload branch, the status text, and the branch that did not yet exist were all equally unexercised. A page that ignores the server was indistinguishable, under test, from one that acts on it. CB-WP-0014 embedded a real JS engine specifically so the script could be executed rather than string-matched, and CB-WP-0016 found that *a stub too thin to express a failure is how the failure survives*. This is the same finding one layer deeper: the stub was thin at the **reply**, and the reply is where the session's ending lives. The stub now delivers a real then-chain and `gesture_with_reply` reports which controls survive. The seal is mutation-proven — deleting the branch turns exactly one test red — and a negative control asserts `ok: dealing` does **not** seal, because a seal that fired on every reply would pass the first test and silently break `play again`. ### One browser-versus-stub trap, avoided by writing it down The first seal used `setAttribute('data-drop', null)`. In the stub that stores a real `null` and `getAttribute` returns `null`; **in a browser it writes the literal string `"null"`, which is truthy**, so the control would have stayed live while its own test called it sealed. `removeAttribute` is correct in both. The stub gained the method rather than the script gaining a workaround. ## 3. The reshuffle question: already ruled, already implemented T02 required settling whether the deck-exhaustion shuffle happens before drawing it, and to raise a finding if it did not. **It does.** `games/ground/src/lib.rs:1419-1435` (`draw_solution`): deterministic reshuffle of the discard, seeded `seed ^ round`, carried in a `DeckReshuffled` event so replay never re-derives it; if both are empty the draw is skipped. That is the **U4 default**, which ground-game **confirmed on 2026-08-03** — a ruled rule. So nothing was raised, which is the correct outcome and the one the task was written to allow. The piles show the state in which the *next* draw triggers it, because that is derivable from the view; a claim that a reshuffle *has* happened is not, and is not made. The event already reads out in the log. **Two days earlier this question would have been raised as a finding.** CB-WP-0026 applied the U4 ruling on 2026-08-05; this pass consumed it the same day. The register paying off inside 24 hours is not proof it works, but it is the first time the answer to *"is this underdetermined?"* was one lookup instead of a message. ## 4. What the controls caught **The coverage gate caught its own probe going stale.** Replacing the `17 remaining` text broke `solution_deck_len`'s classification — the gate does not care *how* a field is rendered, only that its token appears, so changing the rendering changed the token. Fixed by putting the count in the pile's `