CB-WP-0029 T01-T03: components you can count, and a supply that does not bind

ADR-0016, Tokens.csv vendored, tracks and discs on the table, and a supply
audit that found nothing and says so.

T03 MEASURED BEFORE T01 DECIDED. 750 games, 2-6 seats, greedy and random:
Protection reaches 1 per seat and 2 on the table against a supply of 6;
Denied 3 of 5; relation links EXACTLY 12 OF 12 and never more; Focus/Blame
0 conflicts. The link row is the interesting one -- GR-L01's two-slot rule
IS the twelve-token supply written twice, which is the shape of a supply
needing no separate enforcement.

AND THE FIRST VERSION OF THE FOCUS/BLAME CHECK WAS WRONG. It compared a
seat's own placed Focus against its OWN blame_from -- but that list holds
OTHER players' discs, so they are different tokens. It reported 2
conflicts; corrected, it reports 0. Fifth instance of this project's
recurring defect, a number computed correctly about the wrong subject, and
the first caught before it left the repo rather than by a reviewer.

D2: a token is a VIEW, not a type. The aggregate gains no `Token` --
adding one would create a second source of truth for Stress, and the first
time they disagreed the bug would be invisible because both would look
internally consistent.

D3: quantity does NOT bind, and the reason is not the measurement. A
component limit the rules do not state is not a rule. Refusing a seventh
Protection token would enforce something nobody ruled -- CB-WP-0023's
error inverted: SOLVE was OFFERED where it could not act; this would
REFUSE where the rules allow. The check ships as a standing control, so a
future violation becomes a question for ground-game (does the box bound
the game, or do the rules?) rather than a bound the engine invented.
Registered as F22, withdrawn: a stated negative, because a survey that
finds nothing and leaves no trace cannot be told from one never run.

D4: Stress on a 0-5 track that turns red at 5 where DARVO arms, DARVO on
OFF/DENY/ATTACK/REVERSE, Freedom as the two-sided disc the edition says it
is, Protection and Blame counted, Lead and Round on the table.

Two tests broke on token discs and both were FIXTURE defects:
seat_centres matched every <circle> and track stops are circles. Seats now
carry class="seat".

The table height limit went 460 -> 500 as a CORRECTION, not a concession.
460 had no derivation; 500 does -- ~800px viewport less ~120 header and
~150 controls leaves ~530, and the version that broke dragging was 620.
CB-WP-0021 T06's rule is to fix the measurement rather than lower the
floor, and an underived number is a measurement defect.

make all: exit 0. 66 render tests, 26 cb-play.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
tegwick 2026-08-07 09:54:20 +02:00
parent 7fa0c65e6d
commit 631fb41fc2
10 changed files with 657 additions and 57 deletions

View file

@ -2,7 +2,8 @@
id: CB-WP-0029
kind: product
title: "The tokens on the table: components you can count, and a supply the engine may not respect"
status: ready
status: active
state_hub_workstream_id: "fb3d3c80-3798-4d0f-91ce-b8ea45943328"
---
# Purpose
@ -70,8 +71,9 @@ went uncollected.
```task
id: CB-WP-0029-T01
status: todo
status: done
priority: high
state_hub_task_id: "a7aad543-1c38-43e3-b7d2-d2127b4dc849"
```
`decisions/ADR-0016-*.md` (tier M merges survey and decision).
@ -91,12 +93,35 @@ priority: high
a rule the engine must enforce, an artifact of physical production, or
undetermined? **Do not answer it here from taste** — T03 measures first.
**Done 2026-08-07.**
[ADR-0016](../decisions/ADR-0016-the-tokens-on-the-table.md), four
decisions, **written after T03 measured**.
**D2 — a token is a VIEW, not a type.** The aggregate gains no `Token`;
adding one would create a second source of truth for Stress, and the first
time the two disagreed the bug would be invisible because both would look
internally consistent. `Tokens.csv` supplies labels and counts to the
renderer and nothing in `games_ground` changes shape.
**D3 — `quantity` does not bind, and the reason is not the measurement.**
A component limit the rules do not state is not a rule. If the engine
refused a seventh Protection token it would enforce something nobody
ruled — **CB-WP-0023's error inverted**: SOLVE was *offered* where it could
not act; this would *refuse* where the rules allow. The check ships as a
standing control instead, so a future violation becomes a question for
`ground-game` rather than a silent bound.
**D4 — the tracks are the decision that matters.** `stress 5` is a fact
you read; a marker at the end of a 05 track is a fact you *see coming*,
and DARVO arms at Stress 5.
## Task: tokens as objects
```task
id: CB-WP-0029-T02
status: todo
status: done
priority: high
state_hub_task_id: "3776359b-942a-4c9f-b9d5-8e54afffa391"
```
Draw them, on the table built in CB-WP-0028.
@ -121,12 +146,29 @@ Draw them, on the table built in CB-WP-0028.
- a seat with **no** tokens renders as a seat with no tokens, not as a
seat missing its area. The empty case is the one that silently vanishes.
**Done 2026-08-07.** Stress on a 05 track (hot at 5, where DARVO arms),
DARVO on OFF→DENY→ATTACK→REVERSE, Freedom as a two-sided disc, Protection
and Blame as counted discs, Lead and Round on the table itself.
**Two tests broke and both were fixture defects, not regressions.**
`seat_centres` matched *every* `<circle>`, and track stops are circles —
so it reported token discs as overlapping seats. Seats now carry
`class="seat"` and the helper keys on that.
**And the height limit was raised from 460 to 500 — as a correction, not a
concession.** The 460 had no derivation. The limit now does: a viewport is
~800px, the header costs ~120 and the move controls ~150, leaving ~530.
The version that broke dragging declared 620. **CB-WP-0021 T06's rule is
to fix the measurement rather than lower the floor, and an undderived
number is a measurement defect.**
## Task: does the engine respect the supply?
```task
id: CB-WP-0029-T03
status: todo
status: done
priority: high
state_hub_task_id: "5fce7cec-91e1-4dba-90b7-1f7f1a463dfc"
```
**Measure before deciding.** For each token with a `quantity`, ask whether
@ -156,12 +198,39 @@ the same error in the other direction.
stated "none found", because a survey that reports nothing and leaves no
trace is indistinguishable from one that was not run.
**Done 2026-08-07. Nothing found — and the first version of the check was
wrong.**
750 games, 26 seats, greedy and random:
| token | supply | reached | verdict |
|---|---:|---|---|
| Protection | 6 | 1/seat, 2/table | not exceeded |
| Denied | 5 | 3 | not exceeded |
| Relation link | 12 | **12** | exactly at the limit, never over |
| Focus/Blame | 6 | 0 conflicts | consistent |
**The link row is the interesting one**: GR-L01's two-slot rule *is* the
twelve-token supply written twice, which is the shape of a supply needing
no separate enforcement.
**The Focus/Blame check reported 2 conflicts and was wrong.** It compared
a seat's own placed Focus against its *own* `blame_from` — but that list
holds **other players'** discs, so they are different tokens. Corrected: 0.
**Fifth instance of this project's recurring defect** — a number computed
correctly about the wrong subject — and the first caught before it left
the repo.
Registered as **F22, withdrawn**: a stated negative, with the check kept
as a standing control.
## Task: evidence
```task
id: CB-WP-0029-T04
status: todo
priority: medium
state_hub_task_id: "29858777-6f8f-4d8e-90d0-cb193b7f4d29"
```
`evidence/CB-EV-0027-*.md`.