Skip to content

test(grammar): bounded-exhaustive parser vs grammar.pest verifier (#643 PR 3) - #652

Merged
adityamukho merged 1 commit into
v3from
feat/643-verifier
Oct 20, 2026
Merged

adityamukho merged 1 commit into
v3from
feat/643-verifier

Conversation

@adityamukho

Copy link
Copy Markdown
Collaborator

PR 3 of #643 (plan docs/superpowers/plans/2026-10-20-643-grammar-verifier.md, steps 6–13): the verifier. Part of #643; does not close it.

What

src/query/datalog/parser/verifier.rs, #[cfg(all(test, not(target_arch = "wasm32")))], pest-derived from tests/grammar/grammar.pest. For every generated input: pest rejects ⇒ parser rejects; pest accepts ⇒ parser accepts or rejects with a SEMANTIC code.

Deviations from the plan (need approval)

  1. The grammar was too loose in three more places, fixed in grammar.pest instead of listed as drift (like plan deviation 1). Without these, 155k of 187k structural failures were pest's fault:
    • rule_invocation matched not, not-join, or, or-join as rule names, so (not 1) was a "rule call" to pest. Now !reserved_head; inside an or, (and …) is never a rule call.
    • Literal keywords (":find", ":order-by", …) had no end-of-word check, so (:order-by?x) was :order-by ?x to pest and the unknown option :order-by?x to the parser (PRS-039). Each is now an atomic kw_* rule with !word_cont. The plan put this with the empty-:find fix; it showed up now, so it is here.
  2. Causes, not overlapping predicates. Each failure is put down to its first cause in text order (lexical_cause, structural_cause), so an input matches at most one entry and the "exactly one" rule holds by construction; unmatched failures and stale entries still fail. The structural causes read the parser's own EDN tree of the input, not the filler tokens: in the glued variant, tokens merge (:find?x is one keyword to the parser).
  3. Entries differ from the plan's expected list. New: UnterminatedString, EmptyQuery, EmptyWhere, ResumedSection, AggregateHead (k=4). Merged: rule-head-args is RuleHead. Dropped: udf-var-head (needs 5 tokens, beyond the scheduled bound; listed in Parser accepts inputs the grammar rejects (empty sections, unknown keywords, rule/call heads, lexical edge cases) #651).
  4. SEMANTIC is smaller than the plan expected. With the grammar fixes, PRS-051, PRS-093 and INT-016 are now syntax (pest rejects too). The others the plan expected (PRS-023, 027, 031/032/034, 057, 064, 065, 082, INT-018) are raised by no generated input at k ≤ 4, so they have no generated witness and are left out (the rule in step 10).
  5. Reports: the failure message groups unknown failures by reason (clause and code), with the first of each, plus the first 20.

Timing (step 12)

Debug cargo test, 16-thread machine, load ~7 from another session (not idle, so approximate). Levels run on scoped threads (lexical by length × first-character range, structural one thread per template), merged in input order.

Run Inputs Wall CPU
lexical 1.07M 5 s 35 s
structural k=3 (default) 555K 15 s 1.6 min
structural k=4 7.59M 3.4 min 22.5 min
structural k=5 (estimated, ~178 µs/input) 194M – ~9.6 h

Default stays k=3 (≈35 s on a 4-core runner); the scheduled job (PR 5) runs k=4. k=5 does not fit 30 minutes.

Review

Codex: one finding (unknown valid-time keys counted as FactArity), declined — the parser rejects an unknown key with PRS-088 both with and without trailing elements, so pest and parser agree; only a valid map followed by extra elements is FactArity.

Tests

1650 tests (1640 passing, 10 ignored): 4 new. grammar_conformance passes with the two arity files moved to invalid/syntax/. MINIGRAF_GRAMMAR_BOUND=0..4 all pass.

🤖 Generated with Claude Code

https://claude.ai/code/session_019kY61Y11gcRD91Y6b7jbGT

src/query/datalog/parser/verifier.rs (test-only, not wasm32) checks every
1-3 character string through parse_edn and every balanced filler of up to
MINIGRAF_GRAMMAR_BOUND (default 3) of 32 tokens in 15 command templates
through parse_datalog_command against grammar.pest: pest rejects => parser
rejects; pest accepts => parser accepts or raises a SEMANTIC code (each
with a witness). Today's drift is KNOWN_DRIFT, one entry per cause, each
failure put down to its first cause in text order (#649, #650, #651).

grammar.pest: exact fact and retract_fact, edn_value_only, reserved list
heads are never rule names, literal keywords end at a word boundary. The
two arity corpus files move to invalid/syntax/.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019kY61Y11gcRD91Y6b7jbGT
@codecov

codecov Bot commented Oct 20, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@adityamukho
adityamukho merged commit 3e0f152 into v3 Oct 20, 2026
25 checks passed
@adityamukho
adityamukho deleted the feat/643-verifier branch October 20, 2026 12:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant