Skip to content

Stage-3 REQ-8: reconstruction default-on — the per-clause trust migration (#350) - #91

Merged
maxine-at-forecast merged 3 commits into
mainfrom
feature/5i5F-ZaVf-stage-3-req-8-reconstruction-default-on-the-per-87d3
Jun 26, 2026
Merged

Stage-3 REQ-8: reconstruction default-on — the per-clause trust migration (#350)#91
maxine-at-forecast merged 3 commits into
mainfrom
feature/5i5F-ZaVf-stage-3-req-8-reconstruction-default-on-the-per-87d3

Conversation

@maxine-at-forecast

Copy link
Copy Markdown
Collaborator

Stage-3 REQ-8 — the trust flip. Closes #350. Child of the Stage-3 tree (umbrella xl #342 / gh #80; spec REQ-8 / AC-9). Includes the adversarial-review fix (#357).

What ships — the migration

Where a clause is reconstruction-supported, its trust: migrates solver(z3) → kernel-checked, default-on, same rung (trust-base only, no verdict/level change):

  • Support signal = clause_reconstruction_supported = render_goal.is_ok() (renderability; axiom-cleanliness discharged by REQ-7 AC-8 + the kernel-proven BvModel faithfulness).
  • The split keys on the trust-string marker (not engine name — the bv tag stays bitvector; nlsat is also kernel-grounded).
  • Supported = QF_LIA + the arithmetic/comparison QF_BV subset → kernel-checked, citing BvModel.frmInt_iff_frmBV/tv_equiv_faithful + the named string-emission residual (#356).
  • Unsupported = bitwise/shift/rotate → stay solver(z3); EPR-stratified rel/array (the G2 residual) named not migrated (structurally outside the fragment, F-J).
  • forge audit gains a residual_trust statement aggregating the split (gated on !bv_shadows.is_empty() → v1 audit goldens byte-identical).

AC-9 verified: mix64 is the same-item split — a+b==b+a → kernel-checked, a^b^b==a (bitwise) → solver(z3); the audit names 2 kernel-checked / 2 solver-trusted.

Adversarial review (#357) — one finding, fixed

A pre-flip adversarial pass found the bv route ran no vacuity detection: a @bv clause discharges as req ⇒ clause, so an unsatisfiable req proves it vacuously. The mutation gate masked this only for result-referencing clauses; a param-only clause or a @bv lemma certified L4 + kernel-checked on a vacuous proof. Fixed (d5c3ddf4): req_satisfiable SAT-checks req at the clause width → VacuousPrecondition reject when UNSAT. Regression test bv_vacuity_gate.rs. Every other dimension came back clean (fragment refusal airtight, render ops correct, multiplication axiom-clean, faithfulness kernel-proven, Timeout≠Proved).

Verification (full env)

Full forge suite green (verus + z3 + full Lean spine); clippy -D warnings + rustfmt 1.95.0 clean; v1 goldens byte-identical; make doc-drift exit 0. AC boxes flip at G3 (REQ-9), per stage-3 convention.

maxine-at-forecast and others added 3 commits June 24, 2026 08:27
…tion (#350)

The actual trust flip: where a `@bv` obligation is reconstruction-supported,
its clause `trust:` migrates from solver(z3 QF_BV) to the kernel-checked form,
at the SAME rung (L4) — trust-base-only, no verdict/rung changes. Default-ON
(no flag); builds ON REQ-7 (#349), does not rebuild the exporter or BvModel.

The fragment-support check keys on RENDERABILITY (the reconstruction-supported
set IS what `lean_smt_export` renders without `SmtExportError`):

  * `lean_smt_export::clause_reconstruction_supported(expr, fragment)` =
    `render_goal(obligation).is_ok()` — QF_LIA + arith/cmp QF_BV (`+`/`-`/`*`,
    unsigned cmp, connectives) supported; bitwise/shift/rotate refused. The
    renderable fragment's axiom-cleanliness is discharged once, statically, by
    REQ-7's AC-8 (committed SmtExport.lean + the kernel-checked BvModel
    faithfulness) — not re-run per clause.

  * `engine::bv_kernel_checked_trust_profile()` — the migrated base: the
    lean-smt reconstruction over the bounded-int model + the kernel-checked
    `BvModel.frmInt_iff_frmBV` faithfulness; z3 no longer load-bearing; the
    named pretty-printer residual (#356). `trust_is_kernel_checked` +
    `KERNEL_CHECKED_TRUST_MARKER` key the audit split (nlsat relax counts too).

  * `check::bv_proved_obl` grows a `clause_expr` param (both fn + lemma
    callers); a supported clause -> kernel-checked trust, an unsupported one
    keeps solver(z3), labeled as today (F-J). The engine tag stays `bitvector`
    — only the orthogonal trust axis moves. `mix64` is the AC-9 same-item
    split: `a+b==b+a` migrates, `a^b^b==a` stays solver-trusted.

  * `audit::ResidualTrust` — the residual-trust statement aggregating the
    kernel-checked-vs-solver split, naming the still-solver-trusted clauses +
    the standing F-J fragments (bitwise/shift/rotate + the EPR-stratified
    rel/array residual, named not migrated since the reconstruction fragment
    excludes uninterpreted atoms). Additive (`skip_serializing_if = None`,
    gated on `!bv_shadows.is_empty()`) so the v1 / nlsat goldens stay
    byte-identical.

Tests: 3 unit (fragment-support split, the pure `bv_proved_obl` migration, the
audit aggregation + v1-absent gate) + 2 e2e in bv_lowering (the mix64 cert-level
trust split, the audit residual-trust statement). Full bv_lowering suite (16) +
audit/review/check/nlsat conformance green; doc-drift clean; AC boxes flip at G3
(REQ-9), not here, per stage-3 convention.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…0, #357)

Adversarial review (#357) found: the bv route runs NO vacuity detection. A
`@bv` clause is discharged as `req ⇒ clause`, so an UNSATISFIABLE `req`
proves every clause vacuously — the §10 anti-Goodhart gaming vector the v1
cage rejects as `VacuousPrecondition`. The bv mutation gate masks this only
for RESULT-REFERENCING clauses (every mutant survives → WeakContract); a
param-only `@bv` clause or a `@bv` LEMMA (no body → no mutation) certified L4
— and, post-REQ-8, carried a KERNEL-CHECKED trust label — on a vacuous proof
(the cert even recorded `vacuous_precondition: false`). The bv route newly
permits param-only `ens` clauses (mix64's lemma needs it) and opened a
vacuity path it never guarded; the trust flip stamped it kernel-checked.

Fix: `BitVectorEngine::req_satisfiable` SAT-checks `req` at the clause's own
width (consistent with the discharge's rendering, so never a width artifact);
`bv_fn_cert`/`bv_lemma_cert` reject `VacuousPrecondition` when it is UNSAT
(`None`/undecidable falls through — conservative, never a false rejection).

Regression test forge/tests/bv_vacuity_gate.rs pins both the lemma and the
param-only fn. Satisfiable-req cases unaffected (mix64, real lemmas, nowrap
all still L4). Full forge suite green (verus+z3+full spine); clippy -D
warnings + rustfmt 1.95.0 clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
req_satisfiable (bitvector.rs) + the vacuity gate (check.rs) drift the docs
governing them. Content-sha refresh. Governed REQs unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@maxine-at-forecast
maxine-at-forecast merged commit 8c022a6 into main Jun 26, 2026
10 checks passed
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