Skip to content

proof: #192 phase 3 — proven term-DAG encoder and folding/hashing pass; the solver runs them (TR-061) - #222

Merged
avrabe merged 1 commit into
mainfrom
proof/192-phase3
Oct 1, 2026
Merged

avrabe merged 1 commit into
mainfrom
proof/192-phase3

Conversation

@avrabe

@avrabe avrabe commented Oct 1, 2026

Copy link
Copy Markdown
Contributor

Phase 3 of #192. The solver now lowers every query through a proven term-DAG encoder and a proven folding/hashing pass, and one theorem covers the whole chain from the term DAG to an accepted LRAT certificate.

What changes

  • blast_kernel.rs (Aeneas fragment) adds:
    • DagNode, covering the closed term.rs fragment;
    • encode, which calls the proven rules per node;
    • compact, which reproduces Aig::and's folding and operand normalisation and shares gates via checked hints.
  • dag.rs (new, untrusted): a hash-consed DagBuilder from canonicalised assertions, plus strash_hints.
  • solver.rs now runs encode → compact → map_word → tseitin, all kernel code. The phase-2 bridge, cnf.rs and aig.rs are now only used by tests.

New theorems

They live in BlasterFrame, BlasterCompact, BlasterDag and BlasterCapstone, and all four capstones are pinned in AxiomCheck.lean.

  • encode_sound: every root's output literal simulates to the DAG's BitVec/Bool meaning, under every assignment.
  • compact_sound: compaction preserves every literal's value, for any hints. A wrong hint can only cost sharing.
  • dag_refuted (and dag_refuted_raw): if kernel.check_steps accepts a proof for the CNF that encode → compact → map_word → tseitin produces from a DAG, then no assignment makes all roots true.

Output is unchanged

  • ordeal check --format json is byte-identical to the published v0.25.0 binary on all 24 queries. I re-checked this independently.
  • All four cnf_gap_digest CNF digests match the phase-2 record, on corpora of up to 34 million clauses (agent-reported).

Re-verified independently

  • Regenerated models: 0 axioms.
  • lake build: 1724 jobs, 0 sorry.
  • The axiom gate passes, with all 4 new capstones pinned.
  • cargo test --workspace after a forced rebuild: 244 passed, debug and release.
  • Z3 differential: 12 passed.
  • I read the lower_with wiring; it has exactly the shape dag_refuted covers.

Negative controls (agent-run): each one-line mutation in the kernel, with the model regenerated, fails the Lean build.

  • an Add arm that calls blast_sub;
  • a dropped x&!x=0 fold;
  • map_lit dropping negation.

Cost

Lowering is 1.1–1.55× slower on the bench queries, and 1.85× on the oracle corpus total. The reasons: a whole-query raw arena, two extra passes, and the builder's maps. Lowering is a small share of a solve, and mitigations are in docs/design/query-cnf-gap.md.

What is still trusted, stated honestly

  • dag.rs: the translation from term to DAG.
  • DagWF: an assumed precondition that the builder meets by construction.
  • canon, lowering, the sliver and the SMT-LIB/Verus front ends.

Phase 4, v0.27.0, closes the DAG part. The certificate will carry the DAG, and ordeal-lrat will check dag_wf and re-encode it (check_query). That is the option (b) end state.

rivet: TR-061, VER-061, VE-051, VV-108. rivet validate passes with 0 warnings.

🤖 Generated with Claude Code

https://claude.ai/code/session_01EBJ6kdJ16E3hnsBbq9Lwf1

…s; the solver runs them (TR-061)

The lowering from the term DAG to the CNF is now proven end to end over
the Aeneas model of blast_kernel.rs, and it is the code the solver runs.

Kernel (crates/ordeal/src/blast_kernel.rs, Aeneas fragment):
- DagNode: the closed term.rs fragment with operands as node indices;
  encode_node / encode walk a topologically ordered DAG calling the
  proven rule for every node (Var takes the next w inputs, Const reads a
  bit table, the boolean connectives are one push_and / push_or).
- compact / compact_and / hint_matches / map_lit / map_word: the shipped
  Aig::and's constant folds and operand normalisation, with gate sharing
  driven by hints the pass checks (a wrong hint costs a duplicate gate,
  never a value).

Lean (sorry-free, axiom-clean, pinned in AxiomCheck.lean):
- BlasterFrame.lean: structural frame lemmas for every rule that lacked
  one, plus the leaf specs of the new helpers.
- BlasterDag.lean: the DAG semantics directly over Lean BitVec (dagSim,
  dagWidths, DagWF, dagBool); encode_node_spec (32 arms gluing each
  rule's frame to its _bitvec capstone); encode_sound.
- BlasterCompact.lean: compact_sound / compact_sound_lit, for any hints.
- BlasterCapstone.lean: dag_refuted (encode + compact + map_word +
  tseitin + an accepted check_steps run ⟹ no input assignment satisfies
  the DAG's roots) and dag_refuted_raw, composed with lrat_check_sound.

Solver (crates/ordeal/src/{dag.rs,solver.rs}): the canonicalized
assertions become a hash-consed term DAG (dag.rs, untrusted glue);
lower_with runs blast_kernel::encode, dag::strash_hints (untrusted; the
old HashMap strash's decisions), blast_kernel::compact and
blast_kernel::tseitin. The phase-2 replay bridge (blast/mod.rs) and
cnf.rs / aig.rs leave the production path and serve the per-family
differentials and the gate-identity tests.

Shipped bytes unchanged: ordeal check --format json is byte-identical
(stdout, stderr, exit code) to the v0.25.0 release binary on all 24
fixtures; cnf_gap_digest prints the four phase-2 digests unchanged over
1211 queries (44.6M clauses); dag::tests pin compact + kernel tseitin
against the Aig::and replay + cnf::tseitin node for node and clause for
clause.

Verification: regenerated models (0 axioms); lake build 1724 jobs, 0
sorry; axiom gate; three negative controls (encoder rule swap, dropped
fold, dropped negation — each fails its proof; restored, touched, clean
rebuild); cargo test --workspace debug and release; nextest 255 passed,
71 results mapped, no dead marker; clippy default and
--features oracle,cert-bundle; fmt; Z3 differential 12 passed;
kani_tiers.sh check; wasm32-wasip2 release build;
check_verification_citations.sh; rivet validate. blast+Tseitin time is
1.1–1.55x on the bench queries and 1.85x on the oracle corpus total
(docs/design/query-cnf-gap.md has the table and the reading).

Implements: TR-061
Verifies: VER-061
Refs: #192

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EBJ6kdJ16E3hnsBbq9Lwf1
@avrabe
avrabe merged commit 3b2e790 into main Oct 1, 2026
19 checks passed
@avrabe
avrabe deleted the proof/192-phase3 branch October 1, 2026 16:48
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