Close the three items CB-REV-0001 left open
Some checks failed
ci / check (push) Failing after 4s

H1-B on the DARVO extra Attack: the delta says the extra Attack shares
the Attack resolution "so it can self-soothe too if Stress >= 4".
CB-WP-0038 asserted it because the code shares resolve_attack; nothing
tested it, and CB-EV-0031's withdrawn mechanism story ran through that
exact path. Now tested and mutation-verified.

Round-5 pressure did not reach the score, and this was a real defect
rather than a reporting one. end_round_events scored from `self` while
H1-A's pressure went into `work`, and score() reads Stress for the GR-E03
and GR-E04 tiebreaks — so the final round's pressure was invisible to the
two modes CB-EV-0030 reports on. Fixed. The test uses the case that bites:
uniform pressure preserves an ordering, so it takes the clamp at 5 to
collapse a gap and change who wins.

Inert arms reported separately: a DARVO arm at the End of Round 5 can
never advance a stage, and criterion 1 is about DARVO mattering. 29 of 363
at 2p, none above — matching the reviewer's independent figure, so
criterion 1 stands as met.

That fix produced one more wrong-subject error, caught before reporting:
the first inert-arm metric tested `g.rounds >= 5`, a property of the GAME
rather than the EVENT, so it marked every arm in every completed game
inert and briefly read as "criterion 1 fails after all". An arm is inert
when no RoundEnded follows it.

regulation.rs no longer skips setup failures silently: they are counted,
and a short cell fails an assertion rather than printing a number a reader
has to notice — which is the credit CB-EV-0030 §3 took and half earned.

All thirteen challenges closed. Re-review is owed before any of this
travels: the corrections were made by the author of the errors.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
tegwick 2026-08-08 02:14:19 +02:00
parent 041c0e7c3e
commit 84aa09264c
4 changed files with 218 additions and 16 deletions

View file

@ -124,7 +124,50 @@ failed.
when a player feels cornered — that a human table answers and 3,200 when a player feels cornered — that a human table answers and 3,200
simulated games do not. simulated games do not.
## 5. Open ## 5. The three items the review left open, now closed
**H1-B on the DARVO extra Attack** — the delta says the extra Attack
shares the Attack resolution *"so it can self-soothe too if Stress ≥ 4"*.
CB-WP-0038 asserted it because the code shares `resolve_attack`; nothing
tested it, and the withdrawn §3 ran straight through this path.
`h1b_soothes_the_darvo_stage_attack_too` now covers it, mutation-verified.
**Round-5 pressure did not reach the score — a real defect, not a
reporting one.** `end_round_events` scored from `self` while H1-A's
pressure went into `work`, and `score` reads Stress for the GR-E03 and
GR-E04 tiebreaks. The final round's pressure was invisible to **the two
modes CB-EV-0030 reports on**. Fixed, and the test uses the case that
actually bites: uniform pressure preserves an ordering, so it takes the
**clamp** at 5 to collapse a gap and change who wins.
**Inert arms, and a second wrong-subject error caught on the way.** A
DARVO arm at the End of Round 5 can never advance a stage — `GameEnded`
follows immediately — and ground-game's criterion 1 is about DARVO
*mattering*. Now reported separately:
| seats | arms | of which inert |
|---|---:|---:|
| 2p | 363 | **29** (8%) |
| 3p | 600 | 0 |
| 4p | 800 | 0 |
| 6p | 1200 | 0 |
**The first version of that metric was wrong and equalled `darvo` in
every cell**, because it tested `g.rounds >= 5` — a property of the
*game*, not of the *event*. Every arm in every completed game was marked
inert, which briefly looked like "criterion 1 is not met after all". An
arm is inert when no `RoundEnded` follows it; that figure matches the
reviewer's independent 29-of-363.
**Criterion 1 stands as met**: 92% of arms at 2p and all of them above are
live.
**`regulation.rs` no longer skips setup failures silently.** They are
counted, and a short cell now **fails an assertion** rather than printing
a number a reader has to notice — which is what CB-EV-0030 §3 claimed
credit for and only half did.
## 6. Open
- **The baseline's Stress economy being unreachable (§2) deserves its own - **The baseline's Stress economy being unreachable (§2) deserves its own
finding**, and is not raised here because it wants the plural panel of finding**, and is not raised here because it wants the plural panel of

View file

@ -78,6 +78,15 @@ struct Cell {
atk: u32, atk: u32,
darvo: u32, darvo: u32,
peak_stress: u8, peak_stress: u8,
/// Setups the engine refused. **Counted, not skipped** (CB-REV-0001
/// #11): CB-EV-0030 §3 credited this pass with fixing silent skips
/// and only the `play` path was instrumented.
setup_fails: u32,
/// DARVO arms at the End of Round 5. `GameEnded` is pushed
/// immediately after, so the sequence never advances a stage — the
/// arm is real and can do nothing. Reported separately, because
/// ground-game's criterion 1 is asking about DARVO *mattering*.
inert_arms: u32,
} }
fn sweep(mode: ScoringMode, variant: Variant, players: u8, reactive: bool) -> Cell { fn sweep(mode: ScoringMode, variant: Variant, players: u8, reactive: bool) -> Cell {
@ -87,6 +96,8 @@ fn sweep(mode: ScoringMode, variant: Variant, players: u8, reactive: bool) -> Ce
atk: 0, atk: 0,
darvo: 0, darvo: 0,
peak_stress: 0, peak_stress: 0,
setup_fails: 0,
inert_arms: 0,
}; };
for seed in 0..200u64 { for seed in 0..200u64 {
let Ok(mut st) = GroundState::setup( let Ok(mut st) = GroundState::setup(
@ -97,6 +108,7 @@ fn sweep(mode: ScoringMode, variant: Variant, players: u8, reactive: bool) -> Ce
}, },
seed, seed,
) else { ) else {
c.setup_fails += 1;
continue; continue;
}; };
st.mode = mode; st.mode = mode;
@ -140,12 +152,25 @@ fn sweep(mode: ScoringMode, variant: Variant, players: u8, reactive: bool) -> Ce
// built its headline claim on that number. Wrong subject: the // built its headline claim on that number. Wrong subject: the
// metric answered "highest value ever assigned", the prose said // metric answered "highest value ever assigned", the prose said
// "highest Stress reached". // "highest Stress reached".
// An arm is inert when NO `RoundEnded` follows it: the game
// ended in the same End step, so the sequence never advances a
// stage. `g.rounds >= 5` is a property of the GAME, not of the
// event, and using it marked every arm in every completed game
// as inert — which is how a metric ends up equal to the thing it
// was supposed to be a subset of.
let last_round_ended = g
.events
.iter()
.rposition(|e| matches!(e, games_ground::GroundEvent::RoundEnded { .. }));
let mut held: std::collections::BTreeMap<PlayerId, u8> = let mut held: std::collections::BTreeMap<PlayerId, u8> =
g.state.players.keys().map(|s| (*s, START_STRESS)).collect(); g.state.players.keys().map(|s| (*s, START_STRESS)).collect();
c.peak_stress = c.peak_stress.max(START_STRESS); c.peak_stress = c.peak_stress.max(START_STRESS);
for e in &g.events { for (i, e) in g.events.iter().enumerate() {
if matches!(e, games_ground::GroundEvent::DarvoTriggered { .. }) { if matches!(e, games_ground::GroundEvent::DarvoTriggered { .. }) {
c.darvo += 1; c.darvo += 1;
if last_round_ended.is_none_or(|last| i > last) {
c.inert_arms += 1;
}
} }
if let games_ground::GroundEvent::StressSet { player, stress } = e { if let games_ground::GroundEvent::StressSet { player, stress } = e {
held.insert(*player, *stress); held.insert(*player, *stress);
@ -154,6 +179,22 @@ fn sweep(mode: ScoringMode, variant: Variant, players: u8, reactive: bool) -> Ce
} }
let _ = held; let _ = held;
} }
// Reported as a REFUSAL, not left for a reader to notice a short
// column. CB-REV-0001 #11: `games != 200` was printed, never asserted.
assert_eq!(
c.games + c.setup_fails,
200,
"{players}p {variant:?}: {} games ran and {} setups failed — the cell is short, \
so every number in it is over a sample nobody chose",
c.games,
c.setup_fails
);
if c.setup_fails > 0 {
eprintln!(
" !! {players}p {variant:?}: {} setups refused",
c.setup_fails
);
}
c c
} }
@ -169,12 +210,12 @@ fn main() {
] { ] {
println!("{vlabel}"); println!("{vlabel}");
println!(" greedy (regulates) reactive (does not)"); println!(" greedy (regulates) reactive (does not)");
println!("seats games won atk darvo peak games won atk darvo peak"); println!("seats games won atk darvo peak games won atk darvo peak inert");
for players in [2u8, 3, 4, 6] { for players in [2u8, 3, 4, 6] {
let g = sweep(ScoringMode::SharedGround, variant, players, false); let g = sweep(ScoringMode::SharedGround, variant, players, false);
let r = sweep(ScoringMode::SharedGround, variant, players, true); let r = sweep(ScoringMode::SharedGround, variant, players, true);
println!( println!(
" {players}p {:>4} {:>4} {:>4} {:>5} {:>4} {:>4} {:>4} {:>4} {:>5} {:>4}", " {players}p {:>4} {:>4} {:>4} {:>5} {:>4} {:>4} {:>4} {:>4} {:>5} {:>4} {:>6}",
g.games, g.games,
g.won, g.won,
g.atk, g.atk,
@ -184,7 +225,8 @@ fn main() {
r.won, r.won,
r.atk, r.atk,
r.darvo, r.darvo,
r.peak_stress r.peak_stress,
r.inert_arms
); );
} }
println!(); println!();

View file

@ -1572,9 +1572,15 @@ impl GroundState {
.map_or(self.lead, |i| seats[(i + 1) % seats.len()]); .map_or(self.lead, |i| seats[(i + 1) % seats.len()]);
// GR-R09: after Round 5's End the game ends and scoring applies. // GR-R09: after Round 5's End the game ends and scoring applies.
// **Scored from `work`, not `self`** (CB-REV-0001 #13). H1-A's
// pressure goes into `work` above, and `score` reads Stress for
// the GR-E03 and GR-E04 tiebreaks — so scoring from `self` made
// the final round's pressure invisible to exactly the two modes
// CB-EV-0030 reports on. Under the baseline `work` is a clone and
// this is a no-op.
if self.round >= 5 { if self.round >= 5 {
events.push(GroundEvent::GameEnded { events.push(GroundEvent::GameEnded {
outcome: self.score(), outcome: work.score(),
}); });
return events; return events;
} }
@ -2312,6 +2318,106 @@ mod tests {
); );
} }
/// **H1-B applies to the DARVO extra Attack** (review M12).
///
/// The delta says so outright — *"DARVO-stage extra Attack uses
/// the same Attack resolution (so it can self-soothe too if
/// Stress >= 4)"* — and CB-WP-0038 asserted it on the strength of
/// the code sharing `resolve_attack`. **Nothing tested it**, and
/// CB-EV-0031's withdrawn mechanism story ran through this path.
#[test]
fn h1b_soothes_the_darvo_stage_attack_too() {
let soothe_count = |variant: Variant| {
let mut s = setup(3, variant, 5);
let seats: Vec<PlayerId> = s.players.keys().copied().collect();
let (owner, target) = (seats[0], seats[1]);
s.step = RoundStep::Resolve;
s.players.get_mut(&owner).expect("o").stress = 4;
s.players.get_mut(&owner).expect("o").darvo = DarvoStage::Attack;
s.darvo_targets.insert(
owner,
DarvoTarget {
problem: None,
player: Some(target),
},
);
s.resolution_events()
.iter()
.filter(|e| {
matches!(e, GroundEvent::StressSet { player, stress }
if *player == owner && *stress == 3)
})
.count()
};
assert_eq!(
soothe_count(Variant::H1ProblemStress),
1,
"the DARVO extra Attack did not self-soothe, though the delta says it \
shares the same Attack resolution"
);
assert_eq!(
soothe_count(Variant::Baseline),
0,
"the baseline soothed on a DARVO stage Attack"
);
}
/// **Round-5 pressure must reach the score** (review #13).
///
/// `end_round_events` scored from `self` while H1-A's pressure
/// went into `work`, so the last round's Stress was invisible to
/// the GR-E03 and GR-E04 tiebreaks — the two modes CB-EV-0030
/// reports on.
///
/// Uniform pressure preserves an ordering, so the case that bites
/// is the **clamp**: two seats with equal claims, one at 5 and one
/// at 4, become equal once both are pushed to 5.
#[test]
fn the_last_rounds_pressure_reaches_the_tiebreak() {
let mut s = setup(3, Variant::H1ProblemStress, 5);
s.mode = ScoringMode::CommonProblem;
s.round = 5;
let seats: Vec<PlayerId> = s.players.keys().copied().collect();
// A CONSTRUCTED board, not the deal: the tiebreak only
// decides among seats tied at the top, and no natural 3p deal
// splits evenly while leaving a Problem unclaimed.
//
// Two Problems worth 4 (one each to the two seats, so they
// tie on personal) and one worth 1 left unclaimed, so H1-A
// fires. Claimed = 8 against a threshold of 7.
let ids: Vec<u32> = s.problems.keys().copied().collect();
for id in &ids {
s.problems.remove(id);
}
let mk = |value: u8, claimed_by: Option<PlayerId>| ProblemState {
suit: Suit::Repair,
value,
face_up: true,
denied: false,
claimed_by,
protected_this_round: false,
};
s.problems.insert(1, mk(4, Some(seats[0])));
s.problems.insert(2, mk(4, Some(seats[1])));
s.problems.insert(3, mk(1, None));
s.players.get_mut(&seats[0]).expect("a").stress = 5;
s.players.get_mut(&seats[1]).expect("b").stress = 4;
let events = s.end_round_events();
let Some(GroundEvent::GameEnded { outcome }) = events.last() else {
panic!("round 5 did not end the game");
};
assert!(outcome.group_success, "the fixture must qualify");
let pre = s.score();
assert_ne!(
outcome.winners, pre.winners,
"the outcome ignores the final round's pressure — scored from `self`. \
pre={:?} post={:?}",
pre.winners, outcome.winners
);
}
/// **`rules_delta.yaml`'s `unchanged:` list is ground-game's claim /// **`rules_delta.yaml`'s `unchanged:` list is ground-game's claim
/// about their own experiment, and it is checkable.** /// about their own experiment, and it is checkable.**
/// ///

View file

@ -4,7 +4,11 @@ The tier-L review CB-WP-0038 owed (InnerLoop Step 2). One round: challenge,
then response. Run 2026-08-08 by a separate agent against then response. Run 2026-08-08 by a separate agent against
CB-WP-0038/CB-EV-0030 and CB-WP-0039/CB-EV-0031. CB-WP-0038/CB-EV-0030 and CB-WP-0039/CB-EV-0031.
> **Verdict: not approvable as submitted.** Thirteen challenges, five > **Verdict: not approvable as submitted. All thirteen are now closed**
> see the response under each. **Re-review is owed** before any of this
> travels: the corrections were made by the author of the errors.
>
> **Original verdict:** Thirteen challenges, five
> rated FATAL. **Every FATAL is conceded.** Nothing from either evidence > rated FATAL. **Every FATAL is conceded.** Nothing from either evidence
> file had reached `ground-game`, which is the only reason this is a > file had reached `ground-game`, which is the only reason this is a
> correction rather than a retraction. > correction rather than a retraction.
@ -82,7 +86,7 @@ Stress is ever added. ATTACK is the sole inbound pressure.
| 6 | `baseline_is_bit_for_bit_what_it_was` compared two identically-constructed states — inert against its own threat; `#[serde(skip)]` on `variant` left 57/57 green | **conceded.** Replaced by `the_variant_reaches_the_hash_and_baseline_is_not_a_change`, which asserts baseline and H1 hash **differently**. The reviewer's M6 now goes red | | 6 | `baseline_is_bit_for_bit_what_it_was` compared two identically-constructed states — inert against its own threat; `#[serde(skip)]` on `variant` left 57/57 green | **conceded.** Replaced by `the_variant_reaches_the_hash_and_baseline_is_not_a_change`, which asserts baseline and H1 hash **differently**. The reviewer's M6 now goes red |
| 7 | the `unchanged:` test checked **3 of 7** entries; making SOLVE illegal under H1 left it green | **conceded.** Now compares `legal_commands` per seat (catches M9), checks relation slots at the **boundary** rather than on an empty seat, and asserts the DARVO arm is at 5 (catches M7). Both verified red | | 7 | the `unchanged:` test checked **3 of 7** entries; making SOLVE illegal under H1 left it green | **conceded.** Now compares `legal_commands` per seat (catches M9), checks relation slots at the **boundary** rather than on an empty seat, and asserts the DARVO arm is at 5 (catches M7). Both verified red |
| 8 | "criteria met" rests on a forced move — `reactive` ranks ATTACK at 10 and picks it only when the gate leaves nothing else | **conceded as a limitation, recorded, not fixed.** It is true that the instrument cannot show a null result once H1-A reaches Stress 4. That is a real weakness of the measurement and is now stated in CB-EV-0031 §4 | | 8 | "criteria met" rests on a forced move — `reactive` ranks ATTACK at 10 and picks it only when the gate leaves nothing else | **conceded as a limitation, recorded, not fixed.** It is true that the instrument cannot show a null result once H1-A reaches Stress 4. That is a real weakness of the measurement and is now stated in CB-EV-0031 §4 |
| 9 | three claimed properties had no failing test: H1-A's ordering, H1-B on the DARVO extra Attack, H1-B on an OU-cancelled Attack | **two fixed** — `h1a_pressure_arms_darvo_in_the_same_round_end` and `h1b_does_not_soothe_an_ou_cancelled_attack`, both mutation-verified. **The DARVO extra-Attack path remains untested** and is carried as open | | 9 | three claimed properties had no failing test: H1-A's ordering, H1-B on the DARVO extra Attack, H1-B on an OU-cancelled Attack | **all three fixed and mutation-verified**: `h1a_pressure_arms_darvo_in_the_same_round_end`, `h1b_does_not_soothe_an_ou_cancelled_attack`, `h1b_soothes_the_darvo_stage_attack_too` |
## The rest ## The rest
@ -90,14 +94,21 @@ Stress is ever added. ATTACK is the sole inbound pressure.
here.** Conceded: nothing between the two positions touches the here.** Conceded: nothing between the two positions touches the
attacker's Stress, so the clause cannot be checked in this kernel. The attacker's Stress, so the clause cannot be checked in this kernel. The
honest statement replaces the claim that it was got right. honest statement replaces the claim that it was got right.
- **11 — `regulation.rs` still skips setup failures silently.** Conceded; - **11 — `regulation.rs` still skips setup failures silently.** Conceded
the credit CB-EV-0030 §3 took was half-earned. The `play` path was and **fixed**: counted, and a short cell now fails an assertion rather
instrumented, the `setup` path was not. than printing a number a reader must notice.
- **13 — round-5 DARVO arms are counted but can never act**, and - **13 — round-5 arms, and scoring from `self`.** Both **fixed**, and the
`end_round_events` scores from `self` rather than `work`, so round-5 H1-A second was a real defect rather than a reporting one: `score` reads
Stress is invisible to the CommonProblem tiebreak. **Accepted as a real Stress for the GR-E03/GR-E04 tiebreaks, so the final round's pressure
defect in the other two modes**, which CB-EV-0030 reports on. Carried was invisible to the two modes CB-EV-0030 reports on. Inert arms are now
open. reported separately — **29 of 363 at 2p, none above** — which matches the
reviewer's independent figure and leaves criterion 1 met.
**Fixing it produced one more wrong-subject error**, caught before it
was reported: the first inert-arm metric tested `g.rounds >= 5`, a
property of the *game* rather than the *event*, so it marked every arm
in every completed game inert and briefly read as "criterion 1 fails
after all".
- **12 — reproduction and sample robustness: no problem found.** Every - **12 — reproduction and sample robustness: no problem found.** Every
number reproduced; no conclusion was seed-specific. **The failures were number reproduced; no conclusion was seed-specific. **The failures were
of construction and interpretation, not sampling.** of construction and interpretation, not sampling.**