Some checks failed
ci / check (push) Failing after 4s
Provenance (tier M, structural S, chaos d4=4 -> OVERRIDE drawn M): the maintainer could drag after CB-WP-0016 but could not tell what was pickable, held, or droppable. Underneath that, the page was WRONG about which moves exist: 9 legal commands rendered as 5 cards each claiming all three target kinds, from a const string in the emitter. Investigate is legal on problems 2 and 3 but not 1; Solve on 1 but not 2 or 3. The live page now says 'Solve onto problem 1'. ADR-0010 restates control 5, which this work would otherwise have outgrown in silence: every game fact the page acts on must arrive from Rust as data; the script may read, match and render it, never compute, infer, filter or default one. The survey's real finding is that the permitted and forbidden designs are indistinguishable from outside, so the vocabulary grep is demoted to a cheap first line and two behavioural properties become the controls -- the highlighted set EQUALS the set Rust emitted, and anything the page marks legal must resolve. Both mutation-proven; the derive-legality mutation produces a plausible highlight (seat-0,1,2 where only seat-1 is legal) and is caught. Visible now: .pick resting shadow, .held on the grabbed element, .dropok on every legal target including BOTH drawings of a seat, and a ghost following the pointer. Nothing perceptual is verified and ADR-0010 D5 says so. The DOM stub now models classList/querySelectorAll/createElement and builds its node set from the real emitted page. Trap recorded: QuickJS fixes its stack limit at Context creation relative to that frame, so a helper returning a Context makes every later eval report 'SyntaxError: stack overflow'. CHAOS WINDOW CLOSED, 12 declarations, 2 overrides, one each way. Both changed the outcome, so the retirement condition is not met. Verdict: keep, and recommend d4 -> d8 with a second window of 12 -- that is a change to the loop's own constraints and is owed to the next declaration as tier-M work, not made here. CB-EV-0014 corrected: it quoted CB-WP-0015 at $15.14/136 and called it the first settled figure quoted. Now $22.70/166. The number had been read during CB-WP-0015 itself, so there are two defects -- the boundary, and quoting from memory instead of re-running the instrument. make all exits 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
221 lines
10 KiB
Markdown
221 lines
10 KiB
Markdown
# CB-EV-0015 — legible interaction, and the chaos window's verdict
|
|
|
|
CB-WP-0017 T04. Measured 2026-08-02 at `ca92db5`+. Pass kind `product`,
|
|
tier **M** (structural S, **chaos d4=4 → OVERRIDE, drawn M**).
|
|
**Declaration 12 of 12 — the chaos calibration window closes here.**
|
|
|
|
---
|
|
|
|
## 1. The page was lying, and now it is not
|
|
|
|
The maintainer could drag after CB-WP-0016 but could not tell what was
|
|
draggable, what was held, where it could go, or what any of it would do.
|
|
Underneath that was something worse than a missing affordance: the page
|
|
was **wrong about which moves exist**.
|
|
|
|
Seat P1, round 1, step Select — **9 legal commands**, rendered as 5 cards
|
|
each claiming all three target kinds. Before and after, from the live
|
|
server:
|
|
|
|
| card | before | after |
|
|
|---|---|---|
|
|
| Investigate | *"onto a seat, a problem, or the table"* | **onto problem 2, problem 3** |
|
|
| Solve | *"onto a seat, a problem, or the table"* | **onto problem 1** |
|
|
| Attack | *"onto a seat, a problem, or the table"* | **onto P2, P3** |
|
|
| Support | *"onto a seat, a problem, or the table"* | **onto P2, P3** |
|
|
| Ground | *"onto a seat, a problem, or the table"* | **onto the table** |
|
|
|
|
Investigate is legal on problems 2 and 3 but **not** 1; Solve on 1 but not
|
|
2 or 3. The old text was a `const` in the emitter, printed whenever *any*
|
|
legal command used that action. `legal` carried the exact targets and the
|
|
renderer threw them away.
|
|
|
|
So drop-target highlighting is not decoration on a working table. It is
|
|
the first time the page tells the truth about what is legal.
|
|
|
|
## 2. ADR-0010: the constraint that replaced "it does one thing"
|
|
|
|
ADR-0007 D5 said the page *"reports raw pointer facts and nothing else"*
|
|
and `doc.rs` said `SCRIPT` *"does one thing"*. Everything asked for here
|
|
needs it to do more — hold a drag, follow the pointer, mark other
|
|
elements. Restating a control in order to permit what it forbade is how
|
|
controls die, so it was restated out loud:
|
|
|
|
> **Every game fact the page acts on must arrive from Rust as data.** The
|
|
> script may read it, match it, and turn it into presentation. It may not
|
|
> compute, infer, filter, or default one.
|
|
|
|
The survey's real finding: the permitted design (Rust emits legality, the
|
|
script matches it) and the forbidden one (the script derives legality from
|
|
the DOM) are **indistinguishable from the outside** — both are "the page
|
|
highlights some elements". A control that cannot separate them is not a
|
|
control.
|
|
|
|
The old control was a grep of `SCRIPT` for game vocabulary. CB-WP-0014
|
|
already found that shape too weak once. It is now demoted to a cheap first
|
|
line, and the load-bearing control is stated over behaviour:
|
|
|
|
**Property 1 — the highlighted set equals the set Rust emitted.** The
|
|
mutation that makes the script derive targets by pattern-matching ids
|
|
produces a *plausible* highlight — `seat-0, seat-1, seat-2` where only
|
|
`seat-1` is legal — and the test catches it. That is Decision 1 actually
|
|
enforced rather than asserted.
|
|
|
|
**Property 2 — a target the page marks legal must `resolve`.** A page that
|
|
advertises a drop Rust then refuses is worse than no highlighting, because
|
|
it teaches the player something false. Mutation: adding `table` to
|
|
Investigate's targets → *"the page advertises action-investigate -> table
|
|
but resolve refuses it"*.
|
|
|
|
## 3. What is visible now, and what is merely tested
|
|
|
|
| request | done | verified how |
|
|
|---|---|---|
|
|
| what can be picked up | `.pick` — shadow, lift on hover, `grab` cursor | **not verified.** Whether it *reads* as pickable is a human check |
|
|
| what is held | `.held` — dimmed and scaled where it sat | JS test: `__heldKeys()` is exactly the grabbed key |
|
|
| where it can go | `.dropok` on every legal target, **both drawings of a seat** | JS test: set equality with `data-targets` |
|
|
| where it is going | a ghost following the pointer | JS test: ghost exists, and its `left` tracks `clientX` |
|
|
| what moves exist | the card names its real targets | live server, §1 |
|
|
|
|
**A seat is marked on both of its drawings** — card and graph node. That
|
|
is asserted rather than tolerated: highlighting only one would send the
|
|
player back to hunting for the one that works, which is the CB-WP-0016
|
|
defect in a new form. The first draft of that assertion was *wrong* about
|
|
it, expecting `seat-1` and reading `seat-1,seat-1`.
|
|
|
|
**Third mutation:** dropping the `pointercancel` handler and the `clear()`
|
|
on pointerup leaves marks behind — *"marks survived `__up('seat-1')`"*. A
|
|
stale highlight set is worse than none.
|
|
|
|
### What this pass does not claim
|
|
|
|
No visual property is verified. Whether the shadow reads as *"pick me
|
|
up"*, whether the highlight is noticeable, whether the drag feels
|
|
followable — none of it is reachable from here, and ADR-0010 D5 says so
|
|
rather than letting the tests imply otherwise.
|
|
|
|
## 4. The harness had to get deeper, and cost an hour to a real trap
|
|
|
|
The DOM stub could not express any of this: it synthesized
|
|
`{target:{id}}` from whatever key the test passed. It now models
|
|
`classList`, `querySelectorAll`, `createElement`, and a body — **and its
|
|
node set is built from the real emitted page** via `droppables(html)`,
|
|
not from a list the harness invented.
|
|
|
|
**The trap, recorded because it will recur:** QuickJS fixes its stack
|
|
limit at `Context` creation *relative to the frame it was created in*. A
|
|
helper that creates a context and returns it leaves every later `eval`
|
|
running in a shallower frame, the comparison underflows, and QuickJS
|
|
reports `SyntaxError: stack overflow` — for `__all.length`. The fix is
|
|
that the caller owns the `Context` and the helper only prepares it.
|
|
|
|
That is also why one test had silently skipped registration: each test
|
|
hand-rolled its setup. `prepare()` is now shared, so a test cannot set up
|
|
a different page than the harness runs.
|
|
|
|
## 5. The chaos calibration window: the verdict it has owed
|
|
|
|
`gates.toml` states the retirement condition in its own words:
|
|
|
|
> *"the window closes with no overridden tier producing a different outcome
|
|
> than the argued one — the evaluation this window exists to make
|
|
> possible"*
|
|
|
|
Twelve declarations, **two overrides**, one in each direction. That is the
|
|
minimum that makes an evaluation possible at all, and it arrived on the
|
|
last declaration.
|
|
|
|
### Override 1 — CB-WP-0011, structural L → S
|
|
|
|
The deleted survey would have opened on 2D toolkits. What the pass found
|
|
instead, at tier S, was that the **existing** text renderer was showing 24
|
|
of 41 view fields (CB-EV-0009 §1) — a defect a toolkit survey would have
|
|
walked straight past. Priced on the same subject: **0.099 $/response at S
|
|
against 0.123 at L** (CB-EV-0010 §5).
|
|
|
|
**Different outcome than the argued one: yes.** The argued tier would have
|
|
bought a survey of alternatives; the rolled tier bought a defect in what
|
|
already existed.
|
|
|
|
### Override 2 — CB-WP-0017, structural S → M
|
|
|
|
The question the retirement condition asks: **what did the extra ADR buy
|
|
that a tier-S provenance paragraph would not have?**
|
|
|
|
It bought the restatement of control 5. At tier S this pass would have
|
|
widened what the JavaScript does — pointermove, class-toggling on other
|
|
elements, a ghost node — under a one-paragraph commit note, and ADR-0007
|
|
D5's *"reports raw pointer facts and nothing else"* would have been
|
|
silently outgrown rather than replaced. The forced document is what
|
|
produced Decision 1's rule and, more importantly, the finding that the
|
|
permitted and forbidden designs are indistinguishable from outside — which
|
|
is what turned the vocabulary grep from *the* control into a cheap first
|
|
line, and produced the two properties that are now the real controls.
|
|
|
|
**Different outcome than the argued one: yes**, and in the direction that
|
|
is harder to see from inside — the extra process caught a control quietly
|
|
expiring.
|
|
|
|
### Verdict: keep, at a lower rate
|
|
|
|
Both overrides changed the outcome, so the retirement condition is not
|
|
met. But the honest reading of the cost is that d4 fired twice in twelve
|
|
and both were informative *because they were rare*; a mechanism that
|
|
overrides a quarter of all declarations stops being a calibration and
|
|
starts being the tier system.
|
|
|
|
**Recommendation: keep the chaos roll, drop the rate from d4 to d8, and
|
|
open a second window of 12** with a new retirement condition — retire if
|
|
an override changes nothing twice running. This is a change to how the
|
|
loop constrains its own operation and is therefore **tier M work that this
|
|
pass does not do**: it is recorded here as the recommendation and owed to
|
|
the next declaration, which must make it with its own tier and its own
|
|
roll.
|
|
|
|
## 6. Cost
|
|
|
|
| pass | kind | responses | cost | $/response |
|
|
|---|---|---|---|---|
|
|
| **CB-WP-0016** | product | 64 | **$14.93** | 0.233 |
|
|
| CB-WP-0017 | product | *provisional — not quoted* | | |
|
|
|
|
Read from `make status` **at the moment of writing**, after CB-WP-0017's
|
|
declaration closed CB-WP-0016's window.
|
|
|
|
### The self-quoting rule failed a second way, and CB-EV-0014 is corrected
|
|
|
|
CB-EV-0014 §5 quoted CB-WP-0015 at **$15.14 / 136** and claimed it was
|
|
*"the first figure this project has quoted at a boundary that had actually
|
|
settled."* Both parts were wrong. The same tool now reports CB-WP-0015 at
|
|
**$22.70 / 166** — higher by 50%. CB-EV-0014 has been corrected in place.
|
|
|
|
$15.14/136 was read during CB-WP-0015 itself and carried forward into the
|
|
next pass's write-up. So there are **two** defects, not one:
|
|
|
|
1. the boundary is wrong — a window runs to the *next* pass's first commit
|
|
(CB-EV-0013 §5);
|
|
2. **a figure read earlier in a session is an in-flight figure regardless
|
|
of whose name is on it.** Quoting from memory defeats the rule even
|
|
when the boundary is right.
|
|
|
|
Five for five now, always low: every self-reported cost in this project
|
|
has been an underestimate. The rule owed is therefore not just *"quote two
|
|
passes back"* but *"re-run the instrument at the moment you quote it"* —
|
|
and the second half is what this file did.
|
|
|
|
**Meta budget: 0% `[ok]`** over the trailing three, all product.
|
|
|
|
## 7. Open
|
|
|
|
- **INTENT stage 1: the human check, again.** Everything perceptual here
|
|
is unverified by construction. `cb-play --serve 0`: can you see what is
|
|
pickable, what you are holding, and where it may go?
|
|
- **Chaos: the d4→d8 recommendation** and a second window. §5.
|
|
- **The self-quoting rule still names the wrong boundary.** CB-EV-0013 §5.
|
|
- **AM-4b's scope defect (408,237 uncounted lines)** and its 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** unratified after deciding two
|
|
dependency questions; **ADR-0010** now rests on D5, which is also
|
|
unratified.
|