CB-REV-0003: round 3, and three of four FATAL came from round 2's fixes
Some checks failed
ci / check (push) Failing after 3s
Some checks failed
ci / check (push) Failing after 3s
The pattern is now measured over three rounds: 5 fatal, then 3 (2 from the previous round's corrections), then 4 (3 from them). The corrections are not getting safer. FATAL 1: round 2's short-cell assertion went into regulation.rs only. attack-value.rs — which produced every number in CB-EV-0030's DARVO table — still just warned, and the gate registered to close the finding claimed the property for both. FATAL 2, the sharpest of the three rounds: counting games proves they STARTED. Stopping the engine after one round gives 200 games, all-zero columns and exit 0 — byte for byte the signature CB-EV-0030 says the instrumentation distinguishes from a real result. Both harnesses now require every counted game to have reached an outcome over five rounds. FATAL 3: round 2's `.csv` filter was applied to all three loops, so catalog.yaml and rules_delta.yaml — whose missing digests were round 1's finding — were recorded and then never compared, and never checked against upstream at all. Only the parser loop filters now. FATAL 4: five of six tiebreak comparators had no coverage. GR-E04's tiebreak never executes in any scenario. All four are now covered and mutation-verified; the Blame key needed compensating claims to be reachable at all, since Blame also lowers the coalition score. SERIOUS: "peak held" computed the same number as "peak assigned" for every possible input — the real gap was that START_STRESS was an unchecked constant, now read off the dealt state; cadence="none" was a pure loophole, removed; sibling discovery swapped a hand-written list for hand-written globs and missed metadata.json and VARIANT.md, both named in the package's own changed_files — now walked, and it found them immediately; and "~72,000 games" was unsourced, make panels runs 17,600. Also separated two kinds of number that were presented alike: seats×games is invariant, 363 and 29 vary 7.1%-11.5% across samples. Round 4 owed. The conclusion is not that the work is nearly right — it is that author-made corrections to measurement work should be assumed defective until a fresh reader has attacked them. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
feb68027f9
commit
c4a8a227c0
9 changed files with 386 additions and 57 deletions
|
|
@ -2427,6 +2427,108 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
/// **Every tiebreak comparator, both modes** (CB-REV-0003 #4).
|
||||
///
|
||||
/// The strengthened oracle covered **1 of 6**: GR-E03's Stress
|
||||
/// key. Reversing GR-E03's *Bond* key, or **either** of GR-E04's
|
||||
/// two keys, left all 179 tests and all 26 scenarios green —
|
||||
/// GR-E04's tiebreak had no coverage at all, because the only
|
||||
/// GR-E04 scenario sets `group_success: false`, so the winners
|
||||
/// branch returns empty and the comparator never runs.
|
||||
///
|
||||
/// Each case is built so exactly one key decides, and the
|
||||
/// expected winner is named — asserting "the set changed" is what
|
||||
/// let a reversed comparator pass in the first place.
|
||||
#[test]
|
||||
fn every_tiebreak_key_decides_the_way_the_rules_say() {
|
||||
let board = |mode: ScoringMode| {
|
||||
let mut s = setup(4, Variant::Baseline, 5);
|
||||
s.mode = mode;
|
||||
let seats: Vec<PlayerId> = s.players.keys().copied().collect();
|
||||
let ids: Vec<u32> = s.problems.keys().copied().collect();
|
||||
for id in &ids {
|
||||
s.problems.remove(id);
|
||||
}
|
||||
(s, seats)
|
||||
};
|
||||
let mk = |value: u8, claimed_by: Option<PlayerId>| ProblemState {
|
||||
suit: Suit::Repair,
|
||||
value,
|
||||
face_up: true,
|
||||
denied: false,
|
||||
claimed_by,
|
||||
protected_this_round: false,
|
||||
};
|
||||
|
||||
// GR-E03 key 2, Stress: equal claims, lower Stress wins.
|
||||
let (mut s, seats) = board(ScoringMode::CommonProblem);
|
||||
s.problems.insert(1, mk(4, Some(seats[0])));
|
||||
s.problems.insert(2, mk(4, Some(seats[1])));
|
||||
s.players.get_mut(&seats[0]).expect("a").stress = 5;
|
||||
s.players.get_mut(&seats[1]).expect("b").stress = 1;
|
||||
assert_eq!(
|
||||
s.score().winners,
|
||||
vec![seats[1]],
|
||||
"GR-E03: lower Stress must win the tiebreak"
|
||||
);
|
||||
|
||||
// GR-E03 key 3, Bonds: equal claims AND equal Stress, more
|
||||
// Bonds wins.
|
||||
s.players.get_mut(&seats[0]).expect("a").stress = 1;
|
||||
s.relations
|
||||
.insert(Pair::new(seats[0], seats[2]), Relation::Bond);
|
||||
assert_eq!(
|
||||
s.score().winners,
|
||||
vec![seats[0]],
|
||||
"GR-E03: with claims and Stress level, more Bonds must win"
|
||||
);
|
||||
|
||||
// GR-E04 key 2, combined Stress: two coalitions of equal
|
||||
// score, the calmer one wins.
|
||||
let (mut s, seats) = board(ScoringMode::BondedCoalitions);
|
||||
s.problems.insert(1, mk(4, Some(seats[0])));
|
||||
s.problems.insert(2, mk(4, Some(seats[2])));
|
||||
s.relations
|
||||
.insert(Pair::new(seats[0], seats[1]), Relation::Bond);
|
||||
s.relations
|
||||
.insert(Pair::new(seats[2], seats[3]), Relation::Bond);
|
||||
for seat in &seats {
|
||||
s.players.get_mut(seat).expect("p").stress = 1;
|
||||
}
|
||||
s.players.get_mut(&seats[0]).expect("p").stress = 5;
|
||||
let won = s.score().winners;
|
||||
assert!(
|
||||
won.contains(&seats[2]) && !won.contains(&seats[0]),
|
||||
"GR-E04: the coalition with lower combined Stress must win, got {won:?}"
|
||||
);
|
||||
|
||||
// GR-E04 key 3, Blame — and reaching it takes care, which is
|
||||
// the point. A coalition's score is `sum(claimed - blame)`, so
|
||||
// a Blame token lowers the score too and key 1 decides first.
|
||||
// The key is only reachable when the claims COMPENSATE: 5
|
||||
// claimed with one Blame ties 4 claimed with none.
|
||||
s.players.get_mut(&seats[0]).expect("p").stress = 1;
|
||||
s.problems.insert(1, mk(5, Some(seats[0])));
|
||||
s.problems.insert(2, mk(4, Some(seats[2])));
|
||||
s.players.get_mut(&seats[0]).expect("p").blame_from = vec![seats[3]];
|
||||
let scored = s.score();
|
||||
assert_eq!(
|
||||
scored.coalitions.len(),
|
||||
2,
|
||||
"the fixture needs two coalitions to compare"
|
||||
);
|
||||
assert_eq!(
|
||||
scored.coalitions[0].score, scored.coalitions[1].score,
|
||||
"the Blame key is unreachable unless the scores tie: {:?}",
|
||||
scored.coalitions
|
||||
);
|
||||
let won = scored.winners;
|
||||
assert!(
|
||||
won.contains(&seats[2]) && !won.contains(&seats[0]),
|
||||
"GR-E04: with score and Stress level, fewer Blame must win, got {won:?}"
|
||||
);
|
||||
}
|
||||
|
||||
/// **`rules_delta.yaml`'s `unchanged:` list is ground-game's claim
|
||||
/// about their own experiment, and it is checkable.**
|
||||
///
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue