CB-WP-0037 done: T03 classification and T04 evidence
Some checks failed
ci / check (push) Failing after 5s
Some checks failed
ci / check (push) Failing after 5s
Reading Player_Mats.csv and Glossary.csv — which O4 had forbidden declaring about until they were read — found a rule. Player_Mats' choice_rule column IS GR-R03: at Stress 4-5 choose ATTACK or GROUND unless you spend a ready Freedom token. The engine's stress_gated and allowed_under_stress_gate match it exactly, and now have a tripwire. So Ornamentation.md gains §1.3: the unit is a column, not a file. Classifying Player_Mats as ornamentation would have thrown a rule away with the colour swatches. A mixed artifact is normal — a player mat is a rule printed on a decorated card in the box too. O4 is rewritten and re-grounded from provisional to rule accordingly. O5, O6, O7 declared with falsifiers. O7's is not theoretical: back_design_id is unread in four vendored files, and hidden information is what card backs are for. CB-EV-0029 answers T04's question per rule rather than as a count — yes, every checkable clause — and states the reading that result does NOT support: it shows GroundRules.md was a faithful secondary source for the clauses with behaviour to check, not that the engine is correct. 10 of 19 files vendored. Nine still unread, and Rules_Text.csv is the one that matters: every clause checked here was checked against our own transcription of it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
87414d7c1d
commit
627992bc85
10 changed files with 497 additions and 12 deletions
|
|
@ -75,6 +75,8 @@ const TOKENS_CSV: &str = include_str!("../../../editions/ground-darvo-r0/Tokens.
|
|||
const DARVO_CSV: &str = include_str!("../../../editions/ground-darvo-r0/DARVO.csv");
|
||||
const RELATIONS_CSV: &str = include_str!("../../../editions/ground-darvo-r0/Relations.csv");
|
||||
const SCENARIOS_CSV: &str = include_str!("../../../editions/ground-darvo-r0/Scenarios.csv");
|
||||
const PLAYER_MATS_CSV: &str = include_str!("../../../editions/ground-darvo-r0/Player_Mats.csv");
|
||||
const GLOSSARY_CSV: &str = include_str!("../../../editions/ground-darvo-r0/Glossary.csv");
|
||||
|
||||
/// A vendored CSV, parsed into rows addressable by column name.
|
||||
///
|
||||
|
|
@ -502,6 +504,42 @@ pub fn scenarios() -> Result<Vec<ScenarioText>, String> {
|
|||
Ok(out)
|
||||
}
|
||||
|
||||
/// The stress gate, printed on every player mat (CB-WP-0037 T03).
|
||||
///
|
||||
/// **A mat is mostly ornamentation with one rule on it.** Symbol, colour
|
||||
/// and title decorate; `choice_rule` is GR-R03. All six seats print the
|
||||
/// same rule, so this returns it once and checks they agree.
|
||||
pub fn choice_rule() -> Result<String, String> {
|
||||
let t = Table::parse(PLAYER_MATS_CSV, "Player_Mats.csv")?;
|
||||
let mut seen: Option<String> = None;
|
||||
for row in &t.rows {
|
||||
let rule = t.get(row, "choice_rule")?.to_string();
|
||||
match &seen {
|
||||
None => seen = Some(rule),
|
||||
Some(first) if *first == rule => {}
|
||||
Some(first) => {
|
||||
return Err(format!(
|
||||
"player mats disagree on the stress gate: {first:?} vs {rule:?}"
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
seen.ok_or_else(|| "Player_Mats.csv has no rows".to_string())
|
||||
}
|
||||
|
||||
/// The game's own words for its own terms (CB-WP-0037 T03).
|
||||
pub fn glossary() -> Result<Vec<(String, String)>, String> {
|
||||
let t = Table::parse(GLOSSARY_CSV, "Glossary.csv")?;
|
||||
let mut out = Vec::new();
|
||||
for row in &t.rows {
|
||||
out.push((
|
||||
t.get(row, "term")?.to_string(),
|
||||
t.get(row, "definition")?.to_string(),
|
||||
));
|
||||
}
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
/// One relation side as the edition states it (CB-WP-0037 T02).
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RelationText {
|
||||
|
|
@ -667,6 +705,8 @@ mod card_text_tests {
|
|||
let _ = darvo_stages();
|
||||
let _ = relations();
|
||||
let _ = scenarios();
|
||||
let _ = choice_rule();
|
||||
let _ = glossary();
|
||||
|
||||
let files = [
|
||||
("Problems.csv", CSV),
|
||||
|
|
@ -677,6 +717,8 @@ mod card_text_tests {
|
|||
("DARVO.csv", DARVO_CSV),
|
||||
("Relations.csv", RELATIONS_CSV),
|
||||
("Scenarios.csv", SCENARIOS_CSV),
|
||||
("Player_Mats.csv", PLAYER_MATS_CSV),
|
||||
("Glossary.csv", GLOSSARY_CSV),
|
||||
];
|
||||
let mut report = String::new();
|
||||
let mut total_unread = 0usize;
|
||||
|
|
@ -708,6 +750,52 @@ mod card_text_tests {
|
|||
println!("{report}");
|
||||
}
|
||||
|
||||
/// **The stress gate is printed on the mats** (CB-WP-0037 T03).
|
||||
///
|
||||
/// `Player_Mats.csv` looked like pure ornamentation — a symbol, a
|
||||
/// colour, a title per seat — and one of its columns is GR-R03:
|
||||
/// *"At Stress 0-3 choose any action. At Stress 4-5 choose ATTACK or
|
||||
/// GROUND unless you spend a ready Freedom token."*
|
||||
///
|
||||
/// **This is why the classification unit is a column, not a file.**
|
||||
/// Declaring the mats ornamental would have discarded a rule the
|
||||
/// engine implements, alongside the colour swatches it sits next to.
|
||||
///
|
||||
/// A tripwire, like T02's: the engine's `stress_gated` and
|
||||
/// `allowed_under_stress_gate` were written from `GroundRules.md`,
|
||||
/// and this pins the edition sentence they answer to.
|
||||
#[test]
|
||||
fn the_mats_still_print_the_stress_gate_the_engine_enforces() {
|
||||
let rule = choice_rule().expect("Player_Mats.csv");
|
||||
// `stress_gated`: stress >= 4, unless Freedom lifted the gate.
|
||||
assert!(
|
||||
rule.contains("At Stress 4\u{2013}5") || rule.contains("At Stress 4-5"),
|
||||
"the gate's threshold moved; `stress_gated` uses >= 4: {rule:?}"
|
||||
);
|
||||
// `allowed_under_stress_gate`: ATTACK and GROUND, and only those.
|
||||
assert!(
|
||||
rule.contains("ATTACK or GROUND"),
|
||||
"the gate's admitted actions changed: {rule:?}"
|
||||
);
|
||||
assert!(
|
||||
rule.contains("ready Freedom token"),
|
||||
"the escape hatch changed; the engine spends Freedom: {rule:?}"
|
||||
);
|
||||
|
||||
// GR-L01's two slots are restated in the glossary, and
|
||||
// `has_free_slot` is written against that number.
|
||||
let g = glossary().expect("Glossary.csv");
|
||||
let slot = g
|
||||
.iter()
|
||||
.find(|(term, _)| term == "Relation slot")
|
||||
.map(|(_, d)| d.clone())
|
||||
.expect("Relation slot is defined");
|
||||
assert!(
|
||||
slot.contains("two"),
|
||||
"the glossary no longer says two relation slots: {slot:?}"
|
||||
);
|
||||
}
|
||||
|
||||
/// **F25** — the engine hardcodes numbers the edition states.
|
||||
///
|
||||
/// `GroundState::threshold` is a `match` returning 5/7/9;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue