Repository navigation
verify: Replay obligation archives into Lean projects, bounded modules included - #67
Merged
Merged
Conversation
…the toolchain once.
…eft out, also when it comes first.
…ugh a rejected module.
… module that redeclares a name.
… in the architecture.
…the prelude on its own.
…they apply to Specs.
…hen a User lemma uses sorry.
… again only when what it imports changed.
…moved proof's imports.
…ppverify_auto in the architecture.
…e a goal's assumptions come from.
…alizing a module.
…om in the architecture.
This was referenced Oct 24, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #66 (LS3, on #65, #62, and #63), whose commits show here until they merge; merge after #66. The runs quoted below as on
main(with LS3) are on #66's branch.An obligation archive reached Lean only as the unchecked scratch-pad:
--obligation-inrejected--lean-project,--lean-certify, and automation, and every Lean path rejected a bounded (BMC) module. Archives also dropped what a project needs: spec measures (so every replayed spec was opaque, LS3) and where each assumption of a goal comes from (so a replayed readable goal named no hypothesis, and a proof written for the source did not build). Onmain(with LS3), forsuite/Inputs/lean_replay.cpp:Now the replayed project has the goals,
Specs.lean, and proof files of a source run (diff -rempty), the proof oftri_nonnegby induction written for the source certifies the archive's goal, and a bounded module states its bound and aggregates as BMC does.Design
Decided for 0.2 (LS6): archive replay and BMC provenance in Lean.
obligationStatementHashand their group (function name and a hash of its identity), both archived, so the same obligation has the same goal name and proof file from source or archive. What was missing was the producer path and two pieces of data.VerifierintoLeanProject(initialize, write modules and the spec trial, finalize with moves and quarantine, automation, certification), which collects warnings instead of pushing diagnostics. Source verification andverify::replayLeanProjectboth drive it; there is no second implementation. The move is verbatim apart from the warnings and the automation count, and the 12lean_*.testpass unchanged on it.Proved obligations ... [backend=lean](statusVerifiedin replay, JSONproved-obligations), neverCertified, which would claim the dependency fixpoint. Automation, moving and keeping proofs,--lean-prune-stale, and--jobswork as in source mode;--lean-fallbackstays source-only.cppverify.obligation/3, reads v1 and v2):Decreases, validated like its definition (integer terms over its parameters, every call resolved, every variable in scope), never hashed: a measure changes no meaning (Lean checks termination itself; an induction descends by a well-founded relation whatever the measure);LogicExpr::Premiseon eachOr(where an assumption comes from), which names a readable goal's hypothesis, never hashed./- bound: N loop iterations, by unrolling: ... -/), andLeanProjectGoal::Unwindingmarks the unwinding goals. Every goal certified, unwinding included, isProved obligations ... [backend=lean, bound=N]; every goal but some unwinding goal certified isBoundedSafe(bmc.incomplete-bound). Lean proves and never refutes, so a LeanBoundedSafesays the unwinding is not certified, not that it fails; whatBoundedSafeclaims, that no execution within the bound fails, is exactly what the safety goals state. Unresolving it instead would leave Lean no bounded verdict for the modules BMC exists for, whose unwinding fails. Goal names stay statement names: an identical statement is the same theorem at any bound.Found while writing it: a spec whose measure applies another spec (
decreases(size(n))) was never even a candidate for a Lean definition, since its module had droppedsize. With this PR it is tried;cppverify_decreasingdoes not unfoldsize, so Lean still rejects it (noted as open in the LS3 design note).Tests
suite/lean_replay.test, onInputs/lean_replay.cpp(tri,tri_nonneg,size/down,inc) andInputs/lean_replay_loops.cpp(sum_small,count_up):diff -rofGoals/,Specs.lean, andProofs/empty;tridefined,sizekept fordown's measure;inc's readable goal namesh_pre_1;tri_nonnegcertifies the replay:Proved obligationsfor every module; JSONlean_automatic;mutate_obligation_archive.py schema-v2):triopaque, noh_pre;Proved obligations: sum_small [backend=lean, bound=2]andlean_replay_loops.cpp:19:3: BoundedSafe: count_up (every goal is certified but the unwinding: ...) [backend=lean, bound=3] [reason=bmc.incomplete-bound];Stale/with its warning, and one that brings the goal back takes the proof back, its warning a JSON record in a JSON run (as source runs print warnings);Updated:
obligation_archive.test(version 3 accepted, 4 rejected; a v2 record replays; a measure with a free variable is rejected),obligation_ir.cpp(schema name),Inputs/mutate_obligation_archive.py(schema 3: measures and premises;schema-v2,measure-free-variable).Mutants, each killed (13 of 13): measures not archived; premises not archived; measures not read; schema 2 read with measures; measure callees not kept; measures not validated; no bound with the goals; unwinding goals not marked; bounded safety not reported; replay never certified; replay counts no automatic proof; bounded modules solved under Lean; project warnings dropped.
Docs
--obligation-in's Lean projects; schema v3; what hashes omit.Checked
lean_replay.testfails on LS3 (replay into a project is an error there).VerifyTests: 62 passed, 1 skipped (the parity test, which needs archives).--diagnostics-format=json, one job each): 0 files with different results, 0 with a time change (1295 s, 1285 s).git clang-formatclean.