Some checks failed
ci / check (push) Has been cancelled
turned out to be T03. One table_svg: seats around an elliptical table starting at the BOTTOM -- the viewer sits nearest the reader, as at a real table -- Problems and both stacks in the middle, each seat's played card between it and the centre, relations drawn between seats. Two renderers were DELETED: relations_svg and piles_svg. The task said one table not two diagrams, and leaving the old ones would have meant drawing the same thing twice and letting them drift. No coverage probe cost, through a restructure that merged three diagrams and removed two functions. Second confirmation of CB-WP-0027's finding: a probe naming a FACT survives a reflow, one naming a PRESENTATION does not. CB-WP-0024's "17 remaining" broke on a rendering change; this far larger reflow broke nothing. The new control is per seat count -- no two seat circles closer than 70px at 2 through 6 -- asserted rather than eyeballed at three, which is the only count anyone ever looks at. T08 (CB-EV-0026). Seven of nine observations were engine defects, one was a design finding, one was already true and nobody could tell. Observations 4 and 5 both dissolved and had ONE cause: nothing on the page said how drawing works, so a player built a mental model to fill the gap and reported the gap as two feature requests. The import gap was worse than "one of nineteen" -- 5 of 13 columns read from the file we DID vendor, discarded at parse time for eight days. Rule coverage was 59/59 throughout. The gate measures whether rules are EXERCISED; nothing measures whether a player can READ the game, and nothing cheaply could, which is why the person playing it is the instrument. TWO GATES WERE WRITTEN FOR A SMALLER WORLD, and neither was wrong when written. edition-check compared one recorded digest against Problems.csv regardless of which file it described -- correct with one vendored file, comparing across files with four. And a cb-play test asserted the literal "game over" and went red when a won game said "solved", which was T06 working; it now asserts the heading against the OUTCOME and covers the no-outcome case the original never touched. Chaos window 2 closes with zero overrides in eleven declarations at d8. Third and final statement of it: d8 bought rarity by spending evidence, and a mechanism producing no data across a full window cannot be evaluated by that window. make all: exit 0. 57 render tests, 26 cb-play, loop-lint clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
399 lines
17 KiB
Markdown
399 lines
17 KiB
Markdown
---
|
|
id: CB-WP-0028
|
|
kind: product
|
|
title: "The table you sit at: the cards' own words, an overhead view, and a game you solve rather than survive"
|
|
status: done
|
|
state_hub_workstream_id: "d37c8671-54e4-447f-af64-56f482483282"
|
|
---
|
|
|
|
# Purpose
|
|
|
|
```
|
|
structural tier M (imports more of the authoritative edition, which is
|
|
an external dataset under AM-4's budgets, and touches
|
|
the rendering the coverage gate is written against)
|
|
chaos d8 = 1 → no override
|
|
declared tier M
|
|
```
|
|
|
|
Declaration 11 of chaos window 2. Tier M: survey and decision merged;
|
|
adversarial review optional.
|
|
|
|
## Nine observations from play
|
|
|
|
The maintainer played with the new meta panel and reported nine things.
|
|
**Two are findings about the game, seven are about the engine**, and the
|
|
split matters because they go to different places.
|
|
|
|
| # | observation | where it goes |
|
|
|---|---|---|
|
|
| 1 | no incentive to attack while holding positive cards | **register** — a game-design finding |
|
|
| 2 | *"I don't understand the GROUND card"* | **here** — and it is not a design gap (below) |
|
|
| 3 | overhead view: players around a table, stacks on it | T03 |
|
|
| 4 | click the draw stack to take cards | T04 |
|
|
| 5 | optional auto-draw | T04 |
|
|
| 6 | play again / stop belong in the meta column | T05 |
|
|
| 7 | so does the full log | T05 |
|
|
| 8 | *"Game over"* is wrong when you won | T06 |
|
|
| 9 | rankings — MVP, most problems solved | T07 |
|
|
|
|
## Observation 2 is a data-import gap, and it reframes the pass
|
|
|
|
*"I don't understand the GROUND card"* reads as a design problem. It is
|
|
not: `Actions.csv` carries that card's tagline (*"Regulate. Restore the
|
|
frame. Decide."*) and its full rules text, and **we vendored one file of
|
|
nineteen**. Everything else the engine knows is a hand-transcription into
|
|
`GroundRules.md`'s 59 rules — enough to *play* the game, and nothing to
|
|
*read*. The page shows `Clarify` where the card says *"Ask What Happened."*
|
|
|
|
**Found by a player saying he did not understand something.** Rule
|
|
coverage is 59/59 and has been for weeks. See F18 and
|
|
[ADR-0015](../decisions/ADR-0015-the-cards-own-words.md).
|
|
|
|
## Task: decide what else to import, and what it costs
|
|
|
|
```task
|
|
id: CB-WP-0028-T01
|
|
status: done
|
|
priority: high
|
|
state_hub_task_id: "17e6f38c-1903-4bb2-aa20-37e76c8fc4e0"
|
|
```
|
|
|
|
`decisions/ADR-0015-*.md` (tier M merges survey and decision).
|
|
|
|
**ADR-0011 is the precedent and it constrains this.** It vendored
|
|
`Problems.csv` with a checked digest and a ~50-line hand reader, and
|
|
**refused the `csv` crate on proportion** — 17,651 lines against AM-4b's
|
|
19,742 of remaining headroom, 89% of the budget to read 20 rows.
|
|
|
|
Decide:
|
|
|
|
- **which files**, and the answer is not "all of them". `Actions`,
|
|
`Solutions` and `Modes` carry text a player reads. `BOM`, `Print_Manifest`,
|
|
`Back_Designs`, `Symbols` are production artifacts for a physical print
|
|
run and have no business here.
|
|
- **whether the hand reader survives contact.** `Solutions.csv` has
|
|
`microcopy` and `rules_text` — prose fields with commas, quotes and
|
|
possibly embedded newlines. ADR-0011 named exactly this as the revisit
|
|
condition: *"nested quoting, embedded newlines, multiple dialects."*
|
|
**If the reader cannot parse them correctly, say so and re-run the
|
|
dependency argument rather than writing a fragile parser.**
|
|
- **what happens when text and rules disagree.** `GroundRules.md` was
|
|
derived by hand from these files. If a `rules_text` contradicts a
|
|
numbered rule, that is a **finding**, and it goes to the register — not
|
|
a quiet edit of either.
|
|
- **`Extensions.csv` exists** and names content deliberately outside the
|
|
core. Decide whether it is imported at all; the answer is probably no,
|
|
but *"we did not know it existed"* must not be the reason.
|
|
|
|
**Done 2026-08-06.**
|
|
[ADR-0015](../decisions/ADR-0015-the-cards-own-words.md), six decisions.
|
|
|
|
**The gap is bigger than "one file of nineteen", and the measurement is
|
|
the decision.** Of the file we *did* vendor the engine reads **5 of 13
|
|
columns**; the discarded ones are player-facing text that had been in the
|
|
repo for eight days. And `SCN_01` is hardcoded — the edition ships **four**
|
|
scenarios and the engine has never dealt three.
|
|
|
|
**ADR-0011's revisit condition is measurably absent** — zero doubled
|
|
quotes, zero embedded newlines across every candidate file — so the
|
|
dependency argument does not get re-run. Vendored `Actions`, `Solutions`,
|
|
`Modes`. Not the production artifacts, and **not `Extensions.csv`**, which
|
|
names deliberately non-core content; it is now known to exist, which was
|
|
the real risk.
|
|
|
|
## Task: the cards say what they do
|
|
|
|
```task
|
|
id: CB-WP-0028-T02
|
|
status: done
|
|
priority: high
|
|
state_hub_task_id: "aa4453d2-a84e-4afc-8534-1feb835c4d5b"
|
|
```
|
|
|
|
Every card a player can see carries its own title, tagline and rules text,
|
|
from the edition — not from a phrase we invented.
|
|
|
|
- action cards: GROUND, SOLVE, INVESTIGATE, SUPPORT, ATTACK;
|
|
- Solution cards: the title and microcopy, not just the suit;
|
|
- the mode in play, with its own description.
|
|
|
|
**Controls:**
|
|
- **a test asserts the text comes from the dataset**, not from a Rust
|
|
literal — the whole point is that the game's own words reach the player,
|
|
and a hand-copied string drifts from the source it copies;
|
|
- the drag affordance still works: the explanation is *additional*, and
|
|
CB-WP-0020 T02 already found that replacing a label with an explanation
|
|
loses the label;
|
|
- **the page stays readable.** Five action cards with full rules text is a
|
|
wall; the tagline is the default and the rules text is on demand.
|
|
|
|
**Done 2026-08-06.** One `Table` reader with four callers (a per-file
|
|
copy is how a parser acquires four subtly different bugs), `CardText` for
|
|
Actions/Solutions/Modes, `ProblemText` for the columns already vendored.
|
|
The GROUND card now explains itself; Problems show their own titles.
|
|
|
|
**The load-bearing test asserts the text is a substring of the vendored
|
|
file**, not equal to a Rust literal — a hardcoded expectation would pass
|
|
for a hand-copied string, which is the drift this ends.
|
|
|
|
**`edition` came out from behind `#[cfg(feature = "scenarios")]`**: it was
|
|
gated because its only consumer was, but the edition is the game's own
|
|
data and the runtime now reads it. **Test machinery and game content are
|
|
different things and only one is optional.** `edition-check`, written for
|
|
a single-file world, now checks every file both ways.
|
|
|
|
## Task: an overhead view of a real table
|
|
|
|
```task
|
|
id: CB-WP-0028-T03
|
|
status: done
|
|
priority: high
|
|
state_hub_task_id: "2ff677ac-80ff-4618-ad7c-05b62c8f80c8"
|
|
```
|
|
|
|
> *"Players sitting around the table, the draw and discard stacks on it.
|
|
> An overhead view of a game table would instantly help with understanding
|
|
> what is going on."*
|
|
|
|
The seats become positions around a table rather than a row of cards; the
|
|
Problems, draw and discard sit in the middle; each seat's played card
|
|
appears in front of that seat.
|
|
|
|
**This subsumes `relations_svg`**, which already places seats on a circle
|
|
for the relationship graph — so the layout exists and is drawn twice, once
|
|
as a circle and once as a row. **One table, not two diagrams.**
|
|
|
|
**Controls:**
|
|
- the coverage gate still passes: every view field appears in the parsed
|
|
document. CB-WP-0027 showed a reflow costs nothing when probes name
|
|
facts; this is a bigger reflow and the same rule applies;
|
|
- **the viewer's own seat is identifiable at a glance** — a table where
|
|
you cannot find yourself is worse than a list;
|
|
- 2 through 6 seats all lay out without overlap, asserted per seat count
|
|
rather than eyeballed at 3.
|
|
|
|
**Done 2026-08-06.** One `table_svg`: seats around an elliptical table
|
|
starting at the **bottom** (the viewer sits nearest the reader, as at a
|
|
real table), Problems and both stacks in the middle, each seat's played
|
|
card between it and the centre, relations drawn between seats.
|
|
|
|
**Two renderers were deleted** — `relations_svg` and `piles_svg`. The task
|
|
said *one table, not two diagrams*, and leaving the old ones would have
|
|
meant drawing the same thing twice and letting them drift.
|
|
|
|
**No coverage probe cost**, through a restructure that merged three
|
|
diagrams and removed two functions. **Second confirmation of CB-WP-0027's
|
|
finding**: a probe naming a *fact* survives a reflow; one naming a
|
|
*presentation* does not.
|
|
|
|
The new control is per seat count: **no two seat circles closer than 70px
|
|
at 2, 3, 4, 5 or 6 seats** — asserted rather than eyeballed at three,
|
|
which is the only count anyone ever looks at. Plus: the viewer's seat is
|
|
labelled *and* visually distinct, and a spectator is not given one.
|
|
|
|
## Task: take cards from the stack, or let the table do it
|
|
|
|
```task
|
|
id: CB-WP-0028-T04
|
|
status: done
|
|
priority: medium
|
|
state_hub_task_id: "1106c60e-112b-401f-b854-eeec566ef3d1"
|
|
```
|
|
|
|
Observations 4 and 5. Clicking the draw stack to take a card is the
|
|
natural gesture; auto-draw is for when that stops being interesting.
|
|
|
|
**Both are subject to a rule the engine already has.** Drawing is not a
|
|
free action — GR-A01 draws a Solution as part of INVESTIGATE, and the deck
|
|
is not a thing a player may simply take from. **So this task must first
|
|
establish whether "click to draw" is a legal move at all**, and if it is
|
|
not, it is a **finding for `ground-game`**, not a feature: the maintainer
|
|
expected an interaction the rules do not offer, and that gap is the
|
|
signal.
|
|
|
|
**Do not implement a draw the rules do not have.** CB-WP-0023 exists
|
|
because SOLVE was offered where it could not act.
|
|
|
|
**Controls:**
|
|
- the answer to *"is clicking the deck a legal move?"* is in the task
|
|
record with the rule that settles it;
|
|
- auto-draw changes no outcome — a game played with it and without it from
|
|
the same seed produces the same end-state hash, or it is not automation
|
|
but a rules change.
|
|
|
|
**Done 2026-08-06 — and NOTHING WAS BUILT, which is the correct outcome.**
|
|
|
|
**Clicking the deck is not a legal move.** `GroundCommand` has no
|
|
standalone draw, and the edition's own INVESTIGATE text settles it:
|
|
|
|
> *"Choose one hidden, non-Denied Problem and reveal it. **Then draw one
|
|
> Solution.** If no hidden Problems remain, draw one Solution only."*
|
|
|
|
Drawing is a **consequence** of INVESTIGATE, never an action. Implementing
|
|
a click-to-draw would have invented a rule — which is what CB-WP-0023
|
|
exists to stop.
|
|
|
|
**And observation 5 is already true.** Drawing is *already* automatic: it
|
|
happens inside INVESTIGATE with no player input at all. The maintainer
|
|
asked for an auto-draw option for a thing that has never been manual.
|
|
|
|
**Both observations have the same root cause, and T02 fixed it.** He
|
|
expected to take cards from the deck because **nothing on the page said
|
|
how drawing works** — the INVESTIGATE card's own text was in a file we had
|
|
not imported. It now reads on the card.
|
|
|
|
**No finding raised.** The rules are clear and were simply not visible; a
|
|
player's instinct differing from a legible rule is a comprehension gap,
|
|
not a rules gap. Worth ground-game knowing as design feedback if the
|
|
instinct recurs with the text present — **which is now a testable
|
|
question and was not before.**
|
|
|
|
## Task: the meta column takes the controls and the log
|
|
|
|
```task
|
|
id: CB-WP-0028-T05
|
|
status: done
|
|
priority: medium
|
|
state_hub_task_id: "6c78e44e-38fc-451b-b1a0-205b1d079ca0"
|
|
```
|
|
|
|
Observations 6 and 7. `play again` and `end session` move to the meta
|
|
column, and the ending page gets the same two-column shape as the table —
|
|
it currently has none.
|
|
|
|
The full log belongs there too, which CB-WP-0027 did for the live page and
|
|
not for the ending page.
|
|
|
|
**Controls:**
|
|
- CB-WP-0024 T01's seal still works: acknowledging the end must still
|
|
remove every control, wherever they now live;
|
|
- the ending page's existing tests pass unchanged or the change is a
|
|
regression.
|
|
|
|
**Done 2026-08-06.** The ending page gets the table's two-column shape:
|
|
result on the left, rankings + controls + the full log on the right. The
|
|
seal still removes every control wherever it now lives, and the existing
|
|
ending tests passed unchanged.
|
|
|
|
## Task: a game you solve
|
|
|
|
```task
|
|
id: CB-WP-0028-T06
|
|
status: done
|
|
priority: medium
|
|
state_hub_task_id: "df0a967e-636b-4fe5-9926-4d73030a87d7"
|
|
```
|
|
|
|
> *"'Game Over' is negative and should only be used for lost games. If the
|
|
> players won, let's use 'Game solved'."*
|
|
|
|
**Right, and it is more than tone.** GROUND is a co-operative game about
|
|
repairing a situation; `group_success` means the table *solved* something.
|
|
"Game over" is arcade vocabulary for a failure state, and using it for a
|
|
win tells the player the wrong thing about what they just did.
|
|
|
|
**Controls:**
|
|
- the heading is a function of `outcome.group_success`, asserted **both
|
|
ways** — a test that only checks the win case passes for a page that
|
|
always says "solved";
|
|
- the no-outcome case (a game that ended badly) keeps its own wording and
|
|
claims neither.
|
|
|
|
**Done 2026-08-06.** `game solved` on a win, `game over` on a loss, **the
|
|
game stopped** when there is no outcome — asserted all three ways, because
|
|
a test checking only the win case passes for a page that always says
|
|
"solved".
|
|
|
|
## Task: who did what — rankings that are not invented
|
|
|
|
```task
|
|
id: CB-WP-0028-T07
|
|
status: done
|
|
priority: medium
|
|
state_hub_task_id: "ad6e6f6f-e531-494c-b8a9-18dfdd14681c"
|
|
```
|
|
|
|
> *"A ranking of players in the final stats. 'Most valuable player', 'most
|
|
> problems solved' and other conditions that might apply."*
|
|
|
|
`OutcomeView` already carries `personal`, `winners`, `coalitions` and
|
|
`mastery`, and the aggregate knows who claimed each Problem.
|
|
|
|
**The risk is inventing scoring the game does not have.** *"Most problems
|
|
solved"* is countable from `claimed_by` and is a fact. *"Most valuable
|
|
player"* is a **judgement**, and any formula for it is a rule we made up.
|
|
|
|
So: **report what the game counts, and mark anything derived as ours.**
|
|
A superlative computed from real data is fine; a superlative presented as
|
|
if the rules defined it is the same defect as a provisional default
|
|
silently canonised.
|
|
|
|
**Controls:**
|
|
- every ranking names its source: a rule id, or *"clay-borg's reading"*;
|
|
- ties are handled and shown as ties, not broken arbitrarily — `Modes.csv`
|
|
has a `scoring_tiebreak` column, so the game may already say how;
|
|
- a ranking that no seat leads (nobody solved anything) renders as that,
|
|
not as an empty list.
|
|
|
|
**Done 2026-08-06, and the interesting decision was not to rank.**
|
|
|
|
`Modes.csv` gives `scoring_tiebreak` per mode, so the ordering is **the
|
|
game's own** where it defines one — *"Lower combined Stress, then fewer
|
|
Blame tokens"* for coalitions. **For SHARED GROUND it says "Not
|
|
applicable"**, because the table succeeds or fails together.
|
|
|
|
So in co-op the page shows **contributions and refuses to order them**,
|
|
and says why. Drawing a leaderboard because a leaderboard is easy would
|
|
have invented scoring the rules do not have — the same defect as
|
|
canonising a provisional default.
|
|
|
|
Facts the game counts (Problems claimed, personal score, Stress, Blame)
|
|
are shown plainly. The one derived superlative is labelled **"clay-borg's
|
|
reading, not a rule"** and appears only where the mode ranks at all. Ties
|
|
are shown as ties.
|
|
|
|
## Task: evidence
|
|
|
|
```task
|
|
id: CB-WP-0028-T08
|
|
status: done
|
|
priority: medium
|
|
state_hub_task_id: "a20a529e-0edf-49cc-9c80-7dba3b76cff5"
|
|
```
|
|
|
|
`evidence/CB-EV-0026-*.md`.
|
|
|
|
- **Whether importing the card text changed what the maintainer
|
|
understood** — observation 2 is the acceptance test and it has a person
|
|
attached to it.
|
|
- **Whether any `rules_text` contradicted `GroundRules.md`.** Nineteen
|
|
files were hand-transcribed into 59 rules; if the import surfaces a
|
|
disagreement, that is the most valuable output of this pass.
|
|
- **Whether "click the deck to draw" was legal**, and if not, what went to
|
|
`ground-game`.
|
|
- **What the overhead view cost the coverage gate**, against CB-WP-0027's
|
|
finding that a probe naming a fact survives a reflow.
|
|
- **Quote CB-WP-0027's cost by re-running the instrument.**
|
|
|
|
**Done 2026-08-06.**
|
|
[CB-EV-0026](../evidence/CB-EV-0026-the-table-you-sit-at.md).
|
|
|
|
- **Seven of nine observations were engine defects**, one was a design
|
|
finding, and one was already true and nobody could tell.
|
|
- **Observations 4 and 5 both dissolved**, and had one cause: nothing on
|
|
the page said how drawing works, so a player built a mental model to
|
|
fill the gap and reported the gap as two feature requests.
|
|
- **The import gap was worse than "one of nineteen"** — 5 of 13 columns
|
|
read from the file we *did* vendor, discarded at parse time for eight
|
|
days. Rule coverage was 59/59 throughout: the gate measures whether
|
|
rules are *exercised*, and **nothing measures whether a player can read
|
|
the game.**
|
|
- **Two gates were written for a smaller world** — `edition-check`
|
|
compared one digest across four files, and a `cb-play` test asserted the
|
|
literal `"game over"` and went red when a won game said *"solved"*.
|
|
Neither was wrong when written.
|
|
- **Chaos window 2 closes with zero overrides in eleven declarations.**
|
|
Third and final statement: d8 bought rarity by spending evidence, and a
|
|
mechanism producing no data across a full window cannot be evaluated by
|
|
it.
|