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

@ -78,6 +78,15 @@ struct Cell {
atk: u32,
darvo: u32,
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 {
@ -87,6 +96,8 @@ fn sweep(mode: ScoringMode, variant: Variant, players: u8, reactive: bool) -> Ce
atk: 0,
darvo: 0,
peak_stress: 0,
setup_fails: 0,
inert_arms: 0,
};
for seed in 0..200u64 {
let Ok(mut st) = GroundState::setup(
@ -97,6 +108,7 @@ fn sweep(mode: ScoringMode, variant: Variant, players: u8, reactive: bool) -> Ce
},
seed,
) else {
c.setup_fails += 1;
continue;
};
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
// metric answered "highest value ever assigned", the prose said
// "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> =
g.state.players.keys().map(|s| (*s, START_STRESS)).collect();
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 { .. }) {
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 {
held.insert(*player, *stress);
@ -154,6 +179,22 @@ fn sweep(mode: ScoringMode, variant: Variant, players: u8, reactive: bool) -> Ce
}
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
}
@ -169,12 +210,12 @@ fn main() {
] {
println!("{vlabel}");
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] {
let g = sweep(ScoringMode::SharedGround, variant, players, false);
let r = sweep(ScoringMode::SharedGround, variant, players, true);
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.won,
g.atk,
@ -184,7 +225,8 @@ fn main() {
r.won,
r.atk,
r.darvo,
r.peak_stress
r.peak_stress,
r.inert_arms
);
}
println!();