4e08a9b485
Integration review, cross-branch against #108. My asymmetry argument was right -- a &str dispatch can only have GRAMMAR_INVARIANT, a Rule dispatch can have a compile error -- and I then applied it to the two &str sites and NOT to the Rule site where the stronger technique was available. build_primary kept its unlabelled `else`. Demonstrated, not argued. With `pct_literal = { "#" ~ identifier }` first in `primary`: the tree built clean, all 85 crate tests passed including my three new 492x guards, and parse_formula("X = #Revenue") returned Ref("Revenue") -- the `#` discarded, the formula silently wrong. The injection must be NON-ATOMIC: an atomic rule is caught by accident in first_inner's own GRAMMAR_INVARIANT and would have reported the code safe. Sweeping for the shape found three more in the same file, two genuinely silent: build_formula's if-chain-in-a-loop dropped an unhandled part (its comment said "Rule::EOI and any silent rules are ignored"; EOI is now an ARM, so ignoring is a decision), filter_value_to_string returned unprocessed text, and build_unary was caught only incidentally downstream. All four now match over Rule with an or-pattern over the rules that cannot appear, so ANY new rule in formula.pest is a build failure at all four until someone decides what it means. Verified by injecting three more probe rules: every site names all three. The greppable invariant: `== Rule::` now appears nowhere in parser.rs. each_primary_alternative_builds_its_own_expr is the anti-clamp guard -- a mechanical if/else-to-match conversion can transpose two arms and still compile, since the compiler checks that every rule is NAMED, never that it is named against the right body. Proved by swapping the string and pipe_quoted arms: it fails and nothing else in the suite does. Also corrects context/code/formula-and-io.md, which still called the final `else` arms "unlabelled-but-safe" on the grounds that COUNT was the only remaining agg_func and >= the only remaining cmp_op. Two of those three clauses were made false by my own earlier commit. Each was true OF THE GRAMMAR AS IT STOOD -- a snapshot silently re-read as an invariant, which is the whole defect in one sentence. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH