Classify bugFinding goals with the mode-aware predicates at minimal check level - #1448
Classify bugFinding goals with the mode-aware predicates at minimal check level#1448repowazdogz-droid wants to merge 1 commit into
bugFinding goals with the mode-aware predicates at minimal check level#1448Conversation
…evel At `--check-level minimal` the non-deductive branch of `VCOutcome.label` and `VCOutcome.emoji` matched on `satisfiabilityProperty` alone, and that match had no case that could report a goal as anything other than `satisfiable`, `fail` or `unknown`. `bugFinding` runs the satisfiability check only, so every goal of a correct program came out `satisfiable` and was then counted as a failure by the CLI. Classify with `bugFindingSuccess`/`bugFindingFailure` instead, for `bugFinding` only. `bugFindingAssumingCompleteSpec` runs both checks and treats any counterexample as an error, which those predicates do not express, so its labels are left unchanged. Add coverage for the minimal-level labels in every mode; `label` and `emoji` were previously exercised only at `.full .deductive`. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
9c6800c to
946b0f7
Compare
|
Checking in on this one. The branch is behind The change is 17 lines in No rush from my side. If there is anything you would like changed before it gets a look, say so and I will pick it up. |
|
Thanks so much for this PR (and also for the related one on Strata-CLI!). Quick note that the documentation job in the CI is failing. Could you please fix that? |
|
I just posted a comment on strata-org/Strata-CLI#7 that when resolved will probably also influence this PR. Thanks a lot. |
|
Thanks for taking a look. On the documentation job: the failing targets are Current This branch is 39 commits behind |
Classify
bugFindinggoals with the mode-aware predicates atminimalcheck levelRepository:
strata-org/StrataBranch:
fix/bugfinding-reportingBase commit:
a61d47e5643820dc08a7d119d3226df48d20926bRelated change in
strata-org/Strata-CLI#7, branchfix/bugfinding-reporting. The two share a root cause and sit at different call sites, and neither depends on the other.Below
--check-level full,bugFindingruns the satisfiability check and not the validity check (verifySingleEnv,Verifier.lean:1788-1798onmain, the| .bugFinding, _ => (true, false)arm).validityPropertyis thereforeunknownon every goal in that mode, and a predicate that reads validity misclassifies all of them. This PR changesVCOutcome.labelandemoji, which is the per-goal line. #7 changesverifyCommandinStrataMainLib.lean, which is the aggregate counts and the summary line.Either can land first. #7 does not call anything this PR adds, and the two predicates it does call,
VCResult.isBugFindingSuccessandisBugFindingFailure, were onmainbefore either PR opened. Building the CLI branch against upstream Stratamainateabf62d5f, which does not contain this PR, produces the same counts as building it with this PR applied.What holds is weaker than a dependency: neither PR on its own changes the whole of the reported behaviour. This one changes the labels while the summary still counts every goal as failed, and #7 changes the counts while the per-goal labels stay as they are. That is review context, not an ordering constraint.
What I ran
Two Core programs, one correct and one with a check/update race, verified with the
strataCLI built fromStrata-CLIat5441d7dagainst this repository.charge_cap.core.stchargeskagainst a meter capped at 100 and assertsmeter <= 100, with a second procedure that calls the charge twice and asserts the cap still holds.charge_cap_toctou.core.streads the meter into a local, lets a second cap-respecting charge land, then applies the update on the basis of the stale local.Observed, before the change
The same program, same commit, at
--check-level full:Expected: no errors.
docs/VerificationModes.md:11statesand the table at
docs/VerificationModes.md:22-32givespassin the BugFinding column for both rows this program's goals land on,sat/unsatat line 24 andunknown/unsatat line 31. The program has no definite bug, and the same binary says so at a different check level.The buggy program produced the same output shape:
A correct program and a program with a real cap violation are indistinguishable at the default check level in the mode whose purpose is to separate them.
Root cause
Strata/Languages/Core/Verifier.lean:1072-1076, inVCOutcome.label:and the same shape at
Verifier.lean:1108-1112inVCOutcome.emoji. The branch has no case that reports a goal as passing.bugFindingreaches it with the satisfiability result only, because of the check selection atVerifier.lean:1795-1798:| .bugFindingAssumingCompleteSpec, _ => (true, true) | .deductive, _ => if obligation.property.passWhenUnreachable then (false, true) else (true, false) | .bugFinding, _ => (true, false)VCOutcome.bugFindingSuccessandbugFindingFailureatVerifier.lean:1022-1028already encode the correct classification and were unreferenced from the labelling path.Fix
Add a
bugFindingcase to both functions that uses those predicates:The label is
no definite bugrather thanpass. Atminimallevel in this mode only the satisfiability check has run, so asatresult rules out a definite bug but does not establish that the assertion holds. Calling itpasswould claim more than the single query supports.bugFindingAssumingCompleteSpeckeeps its existing branch untouched. It runs both checks and treats any counterexample as an error, whichbugFindingSuccessdoes not express: applying the bug-finding predicates to that mode turns a reported violation into a reported pass. I hit exactly that while writing this patch, with a first version that matched on| _ =>instead of.bugFinding, and it silently converted the TOCTOU failure into✅ passwith exit 0.Result
Deductive mode is byte-identical before and after, on both programs:
All 7 goals passedwith exit 0 for the correct one, andfor the racy one.
bugFindingAssumingCompleteSpecis also unchanged on both, including exit 2 on the racy program.Tests
StrataTest/Languages/Core/VCOutcomeTests.leanexercisedlabelandemojionly at.full .deductive, so the branch this PR changes had no coverage. Added#guards for theminimallabels and emoji in all three modes, including two that pin thebugFindingAssumingCompleteSpecanddeductivelabels so a future change cannot quietly repeat the mistake described above.lake buildandlake testboth pass on the patched tree, 533 jobs andAll 2 test file(s) passed, on macOS 15.7.3 arm64 with Lean 4.29.1, cvc5 1.3.4 and z3 4.15.2. The 12[addPathCondition] Label clash detectedwarnings in the Laurel end-to-end tests are present in an unpatched build of the same commit at the same count.Strata/Transform/CoreSpecification.lean:398already specifiespassfor.bugFindingas∀ r ∈ results, VCResult.isBugFindingSuccess r = Bool.true, so this change moves the reporting path towards that specification rather than away from it. It is a field of adef, not a theorem, so nothing was proved about it either way.One thing to confirm before merging
This makes plain
bugFindingquieter. An assertion that can be violated on some path but not all, thesat/satrow, is anotein the BugFinding column ofdocs/VerificationModes.md:26, andStrataTest/Languages/Core/VCOutcomeTests.lean:145already assertsso the SARIF path has always treated it that way. After this change the console and the exit code agree with SARIF, which means my racy program is reported as
no definite bugwith exit 0 under--check-mode bugFinding, and is caught bydeductiveand bybugFindingAssumingCompleteSpecwith exit 2. That follows the documented semantics, but it is a visible behaviour change for anyone currently reading a non-zero exit frombugFindingas a signal, so it is worth an explicit decision rather than my inference from the table.A second consequence worth naming: in
bugFindingthe pass and fail counts no longer sum to the goal total, because a goal that is neither a definite bug nor a proven pass is counted in neither. The threeunknowngoals in the output above are that case. That is a CLI concern rather than one for this PR, and Strata-CLI #7 now adds a third count so the summary accounts for every goal.Companion PR: strata-org/Strata-CLI#7