Reported as "I did a session and noted no changes" — correct, and the
fault was ours twice.
make ground passes no --variant, so the session was baseline, and
CB-WP-0043 deliberately leaves the baseline layout untouched because a
variant that redraws the baseline invalidates every prior look at it.
But the deeper defect is that nothing said so. The page named the round,
the step, the Lead, the scoring mode and the viewer, and never which rules
it was playing — GroundView did not even carry the variant. There was no
way from the screen to tell baseline from H1 from H2. A session that
cannot say which rules it is playing cannot report a rules change; the
player did the right thing and the instrument had nothing to tell them.
Now: variant on GroundView, `rules <id>` in the page header beside the
scoring mode, `rules <id>` in the inspector because a replay that cannot
say which rules produced it is the same defect in the other tool, and
make ground VARIANT=h2 so the capability is reachable.
Both coverage probes caught the new field independently — the render
crate's and cb-play's — the second time in two passes that they have
turned an addition into a legibility requirement instead of letting it be
silent state.
Verified by fetching the served page rather than by reading the code:
make ground VARIANT=h2 prints "rules: h2" and the page carries
"rules h2-scoped-problem-stress" with the scope labels; the baseline says
"rules ground-darvo-r0" and keeps its row.
Still open: nothing explains what a scope DOES, and the trial log header
does not record the variant either — the same defect one artifact along.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The picture had become a lie. A row across the middle says "these are the
table's" — true under the baseline, false under H2, where three of five
cards fall on particular seats.
Global goes to the middle, personal beside its owner, and bond on the mean
midpoint of the owner's Bond edges. A bond Problem whose owner has no Bond
is drawn as personal, because that is the rule — bond_network falls back
to the owner at degree 0 — and the picture must agree with the arithmetic.
The baseline page is untouched: the scoped layout is taken only when a
non-global scope exists, so every prior look at the baseline still holds.
The scope reaches the view as a separate marker rather than a field on
ProblemView, because the delta says "place owner marker on the card" — a
token beside a card — and it is public while the card is face down, which
a ProblemView variant could not express.
The coverage probe forced a real improvement. It demanded a text token for
the new fields and a POSITION is not a token — which is the probe being
right: position alone is invisible to text_of and to a screen reader, and
illegible when two anchors coincide. So each scoped Problem now says whose
it is: everyone's, P1's alone, P2's Bond network, and "P1's alone — no
Bond to share it" at degree 0.
The fixture gained a third Problem. With two, one of the three placement
rules was unexercised and the probe unsatisfiable — a fixture that cannot
reach a branch is how a rule ships untested.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Reported three times across three sessions, two days apart, and it
survived a whole UI rebuild: "i cant see whos support i accept".
It was not styling. The move button's label was format!("{c:?}"), so the
player read `RespondToSupport { response: AcceptBond }` — Rust struct
syntax with no name in it. And the command does not carry the
counterparty, so nothing rendering it alone could have said who; it comes
off the view, as whoever played Support at this seat.
Four more seat-panel fields had the same defect, including `support
AcceptBond` — the one the report names. CB-WP-0020 fixed exactly this for
selections and left its four neighbours as they were.
command_label has no catch-all arm, and that earned its keep before any
test ran: GroundChoice::RejectReverse and SupportResponse::BreakRivalry
both failed to compile — two moves that would have shipped as struct
dumps. An offer the view cannot see is said to be unseen rather than given
an invented name.
The finding underneath: the coverage probe that exists to prove every view
field reaches the PLAYER was matching "player: Some(PlayerId(1))" and
"members: [PlayerId(1)". It was certifying the defect as coverage and
would have gone red had anyone fixed it. Second confirmation of
CB-WP-0024's finding, from the sharper side: a probe naming Debug output
does not merely fail to protect, it pins the defect in place.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Delivers ADR-0007 Decision 1: visualization, drag-to-propose and hot-seat
play, at a measured marginal AM-4a cost of zero.
games-ground shipped: 23 third-party crates
cb-render-html: 23 third-party crates
new crates introduced: 0
Measured, not asserted — the survey's own lesson. AM-4a is unmoved at
246,250; own source is 7,636 -> 9,652.
What shipped:
crates/cb-render-html doc.rs (HTML/SVG emission, incl. the relationship
graph), input.rs (pointer facts -> commands),
serve.rs (Guard, Request, loopback bind)
tools/cb-play hotseat.rs + `--serve PORT`
Per ADR-0007 Decision 2 there is NO cb-render-api and NO cb-render-null.
The renderer targets the existing Project trait; the port waits for
stage 2's wgpu implementation to be its second use.
The six controls, all live, all mutation-checked (8 mutations, each red
for its stated reason):
1-3 token / Origin+Sec-Fetch-Site / explicit 127.0.0.1 bind
4 a token-less request is refused, in the unit AND over a real socket
5 JS may not construct commands — the page reports pointer facts, Rust
resolves them against the legal list the aggregate already offered,
and a test asserts the emitted script contains no game vocabulary
6 the coverage gate crosses the language boundary: it walks the
serialized view for leaf paths and requires each token to appear in
the PARSED emitted document, with a test that the parse really is a
parse (script/style contents must not count as rendered)
The gate fired on its author again, on its first run: ground_choices.*.
choice, ground_choices.*.problem and players.*.blame_from were in neither
list. The last is the one worth keeping — an EMPTY vector is a leaf path
of its own, and it now renders as an explicit absence.
Also, a mutation that did not go red: removing the Sec-Fetch-Site arm
alone left the cross-site test green, because the Origin check caught it
independently. Both had to be removed before the control bit. Recorded
because a control that passes for a reason you did not intend has not
been demonstrated.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>