--- 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.