clay-borg/workplans/CB-WP-0029-the-tokens-on-the-table.md
tegwick cf52e6bcbf
Some checks failed
ci / check (push) Has been cancelled
CB-WP-0029: the tokens on the table — declare and register
Declaration 12 of chaos window 2, which CLOSES IT. Structural M (imports
another edition file under AM-4's budgets), chaos d8=4, no override.

Tokens.csv turns out to carry more than names. Every token has a
`quantity` -- 6 Protection, 5 Denied, 12 relation links -- and a component
count is a limit a simulation does not have unless it is told. protection
is saturating_add(1) at lib.rs:986 with no upper bound, against an edition
that ships six tokens for six players. T03 measures whether that matters
rather than assuming either way.

And `sides` is the second interesting column: Freedom and Focus/Blame are
each ONE DOUBLE-SIDED TOKEN, not two states. The engine holds Focus in a
map and Blame in a list; whether those can disagree with a single physical
token is worth checking.

T03 is shaped against a specific error: whatever it finds is a FINDING,
not a fix. A component limit the rules do not state is underdetermined and
belongs to ground-game, and the engine must not start enforcing a bound
nobody ruled. CB-WP-0023 exists because SOLVE was offered where it could
not act; inventing a limit is the same error in the other direction.

The workplan also names the window-2 verdict as DUE. Its retirement
condition was untestable throughout -- eleven declarations, zero 8s, zero
overrides -- and recording that is a change to how the loop constrains
itself, so it is its own tier-M pass rather than a task here. Named so it
is not lost between passes, which is how the ten rulings went uncollected.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 09:45:41 +02:00

176 lines
6.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
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
---
# Purpose
```
structural tier M (imports another edition file under AM-4's budgets and
touches the rendering the coverage gate is written
against)
chaos d8 = 4 → no override
declared tier M
```
**Declaration 12 of chaos window 2 — the last.** The window closes with
this pass and its verdict is due; see §The window closes here.
## The ask
> *"Let's do the token objects first."*
The engine models every token correctly. It shows them as **numbers on a
seat card** — `protect 2`, `blamed by P3`, `freedom READY`. A real table
has objects you count at a glance.
## What `Tokens.csv` turns out to carry
Nine token types, and the columns are more interesting than the names:
| token | qty | sides | what the engine has |
|---|---:|---|---|
| Stress marker | 6 | Single | `stress: u8` — a marker on a 05 track |
| Freedom | 6 | **Double** (READY/spent) | `freedom_ready: bool` |
| DARVO stage | 6 | Single | `darvo: DarvoStage` on an OFF/DENY/ATTACK/REVERSE track |
| Relation link | **12** | Single | *"two per player"* — GR-L01's two slots |
| Focus / Blame | 6 | **Double** (FOCUS/BLAME) | `focus` map **and** `blame_from` list |
| Protection | 6 | Single | `protection: u8` |
| Denied | **5** | Single | `denied: bool` per Problem |
| Lead | 1 | Single | `lead: PlayerId` |
| Round | 1 | Single | `round: u8` |
**`quantity` is a component limit, and a simulation does not have one
unless it is told.** `protection` is `saturating_add(1)` at `lib.rs:986`
with **no upper bound** — the edition ships six Protection tokens for up
to six players. T03 is about whether that matters.
**`sides` is the second interesting column.** Freedom and Focus/Blame are
*one double-sided token each*, not two states. The engine holds Focus in a
map and Blame in a list; whether those can disagree with a single physical
token is worth checking.
## The window closes here
Window 2 opened 2026-08-03 at d8 and runs to twelve declarations. **This is
the twelfth.**
Its retirement condition — *retire if an override changes nothing twice
running* — has been **untestable throughout**: eleven declarations, zero
8s, zero overrides. CB-EV-0024, CB-EV-0025 and CB-EV-0026 each said so.
**Recording the verdict is a change to how the loop constrains itself and
is therefore its own tier-M pass**, not a task here. This workplan names
it as due so it is not lost between passes, which is how the ten rulings
went uncollected.
## Task: decide what a token is, here
```task
id: CB-WP-0029-T01
status: todo
priority: high
```
`decisions/ADR-0016-*.md` (tier M merges survey and decision).
- **Vendor `Tokens.csv`?** ADR-0015's test applies: does it carry text a
player reads? `front_text` (READY, DENIED, PROTECTION…) and `use` do.
`shape` and `size` are print instructions and do not.
- **What is a token in the renderer?** The engine has no `Token` type and
should probably not gain one: a token is a *view* of state the aggregate
already holds. Deciding otherwise means a second source of truth for
Stress.
- **Where do they sit?** Player tokens belong with their seat; Denied
belongs on its Problem; Lead and Round belong on the table. **The
overhead view is what makes that placement meaningful** — a token
drawn in a list is a number with a picture.
- **Does `quantity` bind?** The decision T03 needs: is the component count
a rule the engine must enforce, an artifact of physical production, or
undetermined? **Do not answer it here from taste** — T03 measures first.
## Task: tokens as objects
```task
id: CB-WP-0029-T02
status: todo
priority: high
```
Draw them, on the table built in CB-WP-0028.
- **Stress on a 05 track**, not the number `5`. The track is the thing
that makes "one more Attack and I trigger DARVO" visible before it
happens.
- **DARVO on its OFF→DENY→ATTACK→REVERSE track**, which is the game's
namesake mechanic and currently the least visible thing on the page.
- **Freedom as a two-sided disc** — READY or spent, using the edition's own
`front_text`.
- **Protection, Blame and Focus as counted objects** by their seat.
- **Denied on its Problem**, not as the word `denied` in a corner.
**Controls:**
- **every existing coverage probe still passes.** They name facts, and
CB-WP-0027 and CB-WP-0028 both showed a fact-naming probe survives a
reflow. A third confirmation is worth having;
- **the token text comes from the edition**, asserted as a substring of
the vendored file — the rule ADR-0015 established and the thing that
stops a hand-copied label drifting;
- 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.
## Task: does the engine respect the supply?
```task
id: CB-WP-0029-T03
status: todo
priority: high
```
**Measure before deciding.** For each token with a `quantity`, ask whether
the aggregate can exceed it:
- **Protection (6)** — `saturating_add(1)` with no bound. Can one seat
hold three? Can the table hold seven? **Write the check, run it, report
the number.**
- **Denied (5)** — five tokens, and a scenario deals at most five
Problems. Probably safe; *probably* is not an answer.
- **Relation links (12, two per player)** — GR-L01 enforces two slots, so
this one is likely already respected. Confirm rather than assume.
- **Focus/Blame (6, double-sided)** — one token per player that flips.
Can a seat hold Focus *and* have Blame from the same source at once? If
so, the model and the component disagree.
**Whatever this finds is a finding, not a fix.** A component limit the
rules do not state is `underdetermined` and belongs to `ground-game`; the
engine must not start enforcing a bound nobody ruled. **CB-WP-0023 exists
because SOLVE was offered where it could not act** — inventing a limit is
the same error in the other direction.
**Controls:**
- each answer is a runnable check, per GameDesign §1 — a claim about the
supply is arithmetic and needs its reproduction;
- **the register gets a row per token that can exceed its quantity**, or a
stated "none found", because a survey that reports nothing and leaves no
trace is indistinguishable from one that was not run.
## Task: evidence
```task
id: CB-WP-0029-T04
status: todo
priority: medium
```
`evidence/CB-EV-0027-*.md`.
- **Whether the supply is exceeded**, with the numbers.
- **Whether the tracks changed what the maintainer could see coming** —
the Stress track exists so a player can see DARVO approaching, and that
is a claim about play, not about pixels.
- **What the reflow cost the coverage gate**, third data point.
- **The window-2 verdict is due** (§The window closes here) — name it as
outstanding if the closing pass has not run.
- **Quote CB-WP-0028's cost by re-running the instrument.**