From f91798cd6e7df9a25a58ca09d81318b1ab4a403a Mon Sep 17 00:00:00 2001 From: Stephen Waits Date: Mon, 26 Oct 2026 19:12:07 -0600 Subject: [PATCH] fix(bookspec): the schema refuses a key only its query may name (P13) `accepted` and `refused` are a command's (and `refused` a period's): the schema now refuses either on a query that does not take it, as the loader already did, instead of letting a malformed example reach the runner. The no-op table walk in the same branch goes with it. --- bookspec/checker/src/schema.rs | 35 ++++++++++++-------------------- bookspec/checker/tests/schema.rs | 2 +- 2 files changed, 14 insertions(+), 23 deletions(-) diff --git a/bookspec/checker/src/schema.rs b/bookspec/checker/src/schema.rs index b0e36e1..29d3936 100644 --- a/bookspec/checker/src/schema.rs +++ b/bookspec/checker/src/schema.rs @@ -1321,27 +1321,7 @@ impl Example { } } else { match (&x.values, &x.refused) { - (Some(v), None) if !v.is_empty() => { - if let Values::Figures(f) = v { - for (k, val) in f { - if !matches!( - q, - "vendor_1099" - | "party_part" - | "party_tin_last4" - | "asset_basis" - | "register_row" - | "project" - ) && !k.is_empty() - { - // Figures may be dates, names or - // amounts; a format's text is a list, - // not a figure table. - let _ = val; - } - } - } - } + (Some(v), None) if !v.is_empty() => {} (None, Some(r)) => { if q != "period" { return Err(what( @@ -1842,7 +1822,7 @@ fn check_document( /// A key only the queries that ask for it may name. fn only(x: &Expect, e: &impl Fn(String) -> SchemaError) -> Result<(), SchemaError> { let q = x.query.as_str(); - let checks: [(&str, bool, &[&str]); 12] = [ + let checks: [(&str, bool, &[&str]); 14] = [ ("entry", x.entry.is_some(), &["entry", "party_part"]), ("event", x.event.is_some(), &["run"]), ( @@ -1872,6 +1852,17 @@ fn only(x: &Expect, e: &impl Fn(String) -> SchemaError) -> Result<(), SchemaErro ("name", x.name.is_some(), &["rename_account"]), ("category", x.category.is_some(), &["set_tax_category"]), ("account", x.account.is_some(), &["add_account"]), + ("accepted", x.accepted.is_some(), COMMANDS), + ( + "refused", + x.refused.is_some(), + &[ + "rename_account", + "add_account", + "set_tax_category", + "period", + ], + ), ]; for (key, given, queries) in checks { if given && !queries.contains(&q) { diff --git a/bookspec/checker/tests/schema.rs b/bookspec/checker/tests/schema.rs index 08f6b4d..9309b50 100644 --- a/bookspec/checker/tests/schema.rs +++ b/bookspec/checker/tests/schema.rs @@ -212,7 +212,7 @@ as_of = "2026-01-02" refused = "end_before_start""#, ); let e = Example::from_toml(&text).unwrap_err(); - assert!(e.message.contains("only a period may be refused"), "{e}"); + assert!(e.message.contains("refused is for"), "{e}"); } /// A command is accepted or refused, never both, and shows no values.