CB-WP-0047: all four boards, and every mode named on the page
Some checks failed
ci / check (push) Failing after 3s
Some checks failed
ci / check (push) Failing after 3s
The modes were already implemented; nothing had ever COMPARED them. The scenarios were not implemented at all: edition::deal has taken a scenario_id since it was written and the only caller passed the literal "SCN_01", so 15 of 20 Problem cards had never been dealt by anything. The seam was the whole mechanism and it sat unused, with nothing red because nothing asked. Scenario is now state (serde default SCN_01, so all 26 recordings replay unchanged), selected by preset `scn-03-4p` with `standard-Np` still meaning SCN_01, and by --scenario/SCENARIO= accepting ids, numbers or titles, validated against the edition rather than a pattern. The threshold now comes off the Scenario card, closing F25's hardcoded 5/7/9. The first version of that control was worthless and mutation said so: all four scenarios print 5/7/9, so reverting to the bands left it green. Split threshold_from() so it can be handed a card that disagrees. The header read `scoring CommonProblem` where the Mode card is titled COMMON PROBLEM, PERSONAL EDGE -- the defect CB-WP-0034 deleted from the move buttons, still standing on the line that says what winning means. The coverage probe was matching that Debug output and went red when it was fixed: third instance (CB-WP-0024, CB-WP-0034). Page now carries the premise, the mode's rules text, and the tiebreak. scenario-panel plays 4x3x3. Findings: SCN_01 and SCN_02 are the same board (identical cells, pinned by a characterisation test); SCN_04 is the hard board at 2p (52% vs 67/73%, the only deck needing two Repair); and group success is EXACTLY equal across all three modes in all 36 cells, because greedy never reads state.mode -- filed F27, the two competitive modes are scoring lenses over cooperative play. F28: SHARED GROUND's mastery subtracts penalties from the claimed COUNT where the mode card's shared score is claimed VALUE. Raised, not fixed; scoring is ground-game's to rule on. Also fixes design.py reporting a backticked path as no reproduction. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
1d3f1bfe60
commit
d30938b259
19 changed files with 1351 additions and 109 deletions
169
workplans/CB-WP-0047-all-four-boards-and-all-three-modes.md
Normal file
169
workplans/CB-WP-0047-all-four-boards-and-all-three-modes.md
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
---
|
||||
id: CB-WP-0047
|
||||
kind: product
|
||||
title: "All four boards and all three modes"
|
||||
status: done
|
||||
---
|
||||
|
||||
# Purpose
|
||||
|
||||
```
|
||||
structural tier M (changes the state and therefore the recording, and
|
||||
moves a reported number -- the threshold -- from the
|
||||
engine to the edition)
|
||||
declared tier M
|
||||
```
|
||||
|
||||
> *"lets have a look at the cards and the rules to those cards again and
|
||||
> implement all the scenarios and modes"*
|
||||
|
||||
## What was actually missing
|
||||
|
||||
The two halves turned out to be very different sizes.
|
||||
|
||||
**The modes were already implemented.** `ScoringMode`'s three arms all
|
||||
score, `--mode` reaches them, F14 fixed the driver. What was missing was
|
||||
that **nothing had ever compared them**, and the page never named them —
|
||||
see below.
|
||||
|
||||
**The scenarios were not implemented at all.** `edition::deal` has taken a
|
||||
`scenario_id` since the day it was written, and the only caller passed the
|
||||
literal `"SCN_01"`:
|
||||
|
||||
```rust
|
||||
let dealt = crate::edition::deal("SCN_01", seats)?;
|
||||
```
|
||||
|
||||
**The seam was the whole mechanism and it sat unused.** 15 of the 20
|
||||
Problem cards had never been dealt by anything — not a gate, not a panel,
|
||||
not a player. Nothing was red, because nothing asked.
|
||||
|
||||
## Task: deal every board, name every mode
|
||||
|
||||
```task
|
||||
id: CB-WP-0047-T01
|
||||
status: done
|
||||
priority: high
|
||||
```
|
||||
|
||||
### The scenario is state
|
||||
|
||||
`GroundState.scenario`, `#[serde(default = "default_scenario")]` → `SCN_01`.
|
||||
In the state for the same reason `variant` is (CB-WP-0038): the board and
|
||||
the threshold follow from it, so a recording that did not carry it could
|
||||
not be replayed.
|
||||
|
||||
**`standard-Np` keeps meaning `SCN_01`.** Twenty-six recorded scenarios
|
||||
name that preset; a grammar that redefined it would have moved every one
|
||||
of their boards while their hashes still claimed to pin them. `scn-03-4p`
|
||||
names the rest. `--scenario` accepts `3`, `scn-03`, `SCN_03` or
|
||||
`confidence` — ids are the edition's vocabulary, *"Broken Confidence"* is
|
||||
the player's — and is validated against the edition, never a pattern, so
|
||||
`SCN_09` is refused by name.
|
||||
|
||||
### The threshold now comes off the Scenario card
|
||||
|
||||
`threshold()` was `match seats { 0..=2 => 5, 3..=4 => 7, _ => 9 }` — the
|
||||
engine's own copy of a number four cards already print, which is what F25
|
||||
was raised about.
|
||||
|
||||
**The first version of this control was worthless and mutation said so.**
|
||||
Reverting to the hardcoded bands left every test green, because all four
|
||||
scenarios print 5/7/9 and the two paths are observationally identical on
|
||||
every input the edition can supply. A control that cannot separate the
|
||||
thing it is about from its fallback is not a control.
|
||||
|
||||
Fixed by splitting `threshold_from(list, scenario, seats)`, which can be
|
||||
handed a card that **disagrees** (4/6/8). That test goes red under the
|
||||
mutation; the loop over real scenarios never could.
|
||||
|
||||
### The page names the mode, the board, and what winning means
|
||||
|
||||
The header read `scoring CommonProblem` — the Rust variant's name, where
|
||||
the Mode card is titled *"COMMON PROBLEM, PERSONAL EDGE"*. **CB-WP-0034
|
||||
deleted this exact defect from the move buttons** and it was still
|
||||
standing on the one line that says what winning means.
|
||||
|
||||
**And the coverage probe was holding it in place.** `("mode", "scoring
|
||||
BondedCoalitions")` — a probe matching `Debug` output, which went red the
|
||||
moment the defect was fixed. That is the **third** time this shape has
|
||||
been found (CB-WP-0024, CB-WP-0034, here), and it is now specific enough
|
||||
to state as a rule: *a probe that names a rendering pins that rendering;
|
||||
probes name facts.*
|
||||
|
||||
The page now carries the Scenario's premise (*what happened*) and the Mode
|
||||
card's rules text (*how this game is won*) — including the **tiebreak**,
|
||||
which is a rule a player can play for: "lower Stress, then more Bonds"
|
||||
changes what a losing seat should do in round five, and it lived in a
|
||||
column nothing read.
|
||||
|
||||
### Mutations
|
||||
|
||||
| mutation | what went red |
|
||||
|---|---|
|
||||
| `setup` deals `"SCN_01"` regardless of preset | *"the four scenarios yield 1 distinct board"* |
|
||||
| `threshold_from` ignores the card | *"the threshold did not come off the Scenario card"* |
|
||||
| header back to `{mode:?}` | *"the page shows the Rust variant's name"* |
|
||||
|
||||
**Done 2026-08-08.** `make all` green. Verified live on
|
||||
`make ground SCENARIO=4 MODE=coalitions`.
|
||||
|
||||
## What the panel found
|
||||
|
||||
`make panels` gained `scenario-panel`: 4 scenarios × 3 modes × 3 seat
|
||||
bands, greedy throughout, 100 games per cell.
|
||||
|
||||
**1. Two of the four scenarios are the same board.** SCN_01 and SCN_02
|
||||
have identical suits and values at every priority; every cell matches
|
||||
exactly. Not a defect — a designed reskin is a legitimate choice — but
|
||||
"four scenarios" buys **three** boards, and a panel that measured them as
|
||||
four independent boards would be measuring one of them twice. Pinned by a
|
||||
characterisation test so a future divergence is a decision, not a drift.
|
||||
|
||||
**2. SCN_04 is the hard board at 2 players** — 52% group success against
|
||||
67% and 73%. It is the only deck that needs **two Repair** solutions in
|
||||
the 2p deal, and the 2p Solution draw cannot always supply them. The seat
|
||||
band the thresholds treat as uniform is not uniform across boards.
|
||||
|
||||
**3. The three modes produce identical play.** Group success is *exactly*
|
||||
equal across all three modes in every cell. That is correct arithmetic and
|
||||
a real finding: `GreedyPolicy` maximises the group outcome and never
|
||||
consults `state.mode`, so **the two competitive modes are scoring lenses
|
||||
over cooperative play**. `win/g` differs only by how the winner set is
|
||||
carved from the same games. Whether COMMON PROBLEM and BONDED COALITIONS
|
||||
change how the game is *played* is untested and cannot be tested by this
|
||||
panel — it needs a policy that plays for personal score. Filed as F27.
|
||||
|
||||
**4. Every board is a formality at 6 players** — 100% group success in all
|
||||
twelve cells. Consistent with F17's shape and with H2's motivation; noted,
|
||||
not acted on.
|
||||
|
||||
## Not done here
|
||||
|
||||
- **No policy plays for personal score**, so F27 stands open and the two
|
||||
competitive modes remain unexercised as *incentives*. This is the
|
||||
largest remaining gap and it is the natural next pass.
|
||||
- **SHARED GROUND's mastery rating counts CLAIMED CARDS, not points.**
|
||||
The Mode card says *"All claimed Problem cards form one shared score …
|
||||
subtract 1 for each Blame token still in play and 1 for each Denied
|
||||
Problem"* — and the shared score is the claimed **value**, while
|
||||
`mastery` subtracts from the claimed **count**. Underdetermined rather
|
||||
than plainly wrong; raised for `ground-game` rather than changed here,
|
||||
because scoring is theirs to rule on.
|
||||
- **The trial log stamps the variant (CB-WP-0046) but not the scenario or
|
||||
the mode.** A note from SCN_04 coalitions is indistinguishable from a
|
||||
baseline SHARED GROUND note, which is the same defect one pass later in
|
||||
two new axes. The marker already carries attributes, so this is small.
|
||||
- **`design.py` reported an existing reproduction as absent.** It stats
|
||||
`row["repro"]` directly, and the register writes **code spans** — so a
|
||||
backticked file path was `os.path.exists("`games/…/x.rs`")` = False.
|
||||
Named tests survived because `::` short-circuits before the stat, which
|
||||
is why it had never shown. F27's panel existed and counted as debt
|
||||
against a target of zero. ADR-0018's shape again: right computation,
|
||||
wrong string. Fixed with three checks, including that stripping the
|
||||
span must not turn the check off.
|
||||
|
||||
- **`catalog.yaml` and both `VARIANT.md`s were re-vendored in this pass**: `ground-game` moved H2
|
||||
from `experimental` to `measured`, `decision: keep-as-experiment`,
|
||||
citing our CB-EV-0032. That is their ruling on the previous pass, not
|
||||
work done here.
|
||||
Loading…
Add table
Add a link
Reference in a new issue