clay-borg/workplans/CB-WP-0028-the-table-you-sit-at.md
tegwick 4d3e30eda4 CB-WP-0028 T04-T07: a game you solve, rankings that cite their source, and
a feature deliberately not built

T04 BUILT NOTHING, WHICH IS THE CORRECT OUTCOME. "Click the draw stack to
get hand cards" 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." Drawing is a
consequence, never an action. Implementing 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, inside
INVESTIGATE, with no player input. An auto-draw option was asked for a
thing that has never been manual.

Both observations have one root cause and T02 fixed it. The maintainer
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. No finding raised: a player's instinct differing from a legible
rule is a comprehension gap, not a rules gap. Whether the instinct recurs
now that the text is present is a testable question and was not before.

T06: "game solved" on a win, "game over" on a loss, "the game stopped"
with no outcome. Asserted all three ways, because a test checking only the
win case passes for a page that always says solved. More than tone --
GROUND is co-operative and about repairing something, and arcade
failure-state vocabulary for a win tells a player the wrong thing about
what they just did.

T05: the ending page gets the table's two-column shape. Result left;
rankings, controls and the full log right. The seal still removes every
control wherever they now live.

T07's interesting decision was NOT TO RANK. Modes.csv defines
scoring_tiebreak per mode, so ordering is the GAME's where one exists --
"Lower combined Stress, then fewer Blame tokens" for coalitions. For
SHARED GROUND it says "Not applicable", because the table succeeds or
fails together. So co-op shows contributions and refuses to order them,
and says why. Drawing a leaderboard because a leaderboard is easy would
invent scoring the rules do not have. The one derived superlative is
labelled "clay-borg's reading, not a rule" and appears only where the mode
ranks; ties are shown as ties.

52 render tests pass. check clean, loop-lint clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-06 17:25:48 +02:00

16 KiB
Raw Blame History

id kind title status state_hub_workstream_id
CB-WP-0028 product The table you sit at: the cards' own words, an overhead view, and a game you solve rather than survive active 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 or why other cards should be played to the table" reads as a design problem. It is not. The card explains itself in the dataset and we never imported the explanation.

ground-game/editions/*/Actions.csv, the GROUND row:

tagline: "Regulate. Restore the frame. Decide." rules_text: "After all actions are revealed, choose one mode: GR—Ground & Restate: 2 Stress, ready Freedom… OU—Observe & Uphold…"

We vendored one file of nineteen. editions/ground-darvo-r0/ holds Problems.csv and nothing else; Actions, Solutions, Modes, Scenarios, Relations, DARVO, Tokens, Glossary and the rest live only in ground-game. Everything the engine knows about them is a hand-transcription into GroundRules.md's 59 numbered rules — which is enough to play the game and gives a player nothing to read.

So the page shows Clarify where the card says "Ask What Happened — Invite a concrete account before judging."

This is the most valuable thing in the pass, and it was found by a player saying he did not understand something rather than by any gate. Rule coverage is 59/59 and has been for weeks.

Task: decide what else to import, and what it costs

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, 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 columnstitle, problem_text, front_rules, reveal_effect and unresolved_effect were discarded at parse time. The cheapest part of this pass costs no new bytes and was sitting in the repo for eight days. And SCN_01 is hardcoded at lib.rs:1824: the edition ships four scenarios and the engine has never dealt three of them.

ADR-0011's revisit condition is measurably absent, so the dependency argument does not get re-run. Across Actions, Solutions, Modes and Scenarios: zero doubled quotes, zero embedded newlines. The hand reader's only job is comma-in-quoted-field, which it already did.

Vendored Actions, Solutions, Modes — the text a player reads. Not the production artifacts. Not Extensions.csv, because it names content the designer placed outside the core, and importing it would break the as-printed claim — but it is now known to exist, which was the real risk.

Task: the cards say what they do

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, and ProblemText for the columns already vendored.

The GROUND card now explains itself: "Regulate. Restore the frame. Decide." as the tagline, its GR/OU/ND text behind a disclosure. Problems show their own titles where a priority number used to be.

The load-bearing test asserts the text is a substring of the vendored file, not equal to a Rust literal — a test comparing against a hardcoded expectation would pass for a hand-copied string, which is the drift this ends. Plus counts (5 actions, 24 solutions, 3 modes), because a reader returning one row would pass a "the text is real" test.

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 shipped runtime now reads it. Test machinery and game content are different things and only one of them is optional.

edition-check was written for a single-file world and compared the first recorded digest against Problems.csv regardless of which file it described. It now checks every file both ways — a vendored file with no digest fails, and a digest naming an absent file fails — and asserts ADR-0015 D3's falsifier directly: no doubled quotes, no embedded newlines.

Task: an overhead view of a real table

id: CB-WP-0028-T03
status: todo
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.

Task: take cards from the stack, or let the table do it

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

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

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

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

id: CB-WP-0028-T08
status: todo
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.