Skip to content

Remove looping asWord-eq-false lemma and expose --equation-max-local-steps#2863

Merged
ehildenb merged 9 commits into
masterfrom
asword-eq-false-loop-fix
Jun 15, 2026
Merged

Remove looping asWord-eq-false lemma and expose --equation-max-local-steps#2863
ehildenb merged 9 commits into
masterfrom
asword-eq-false-loop-fix

Conversation

@ehildenb

@ehildenb ehildenb commented Jun 14, 2026

Copy link
Copy Markdown
Member

The haskell backend now supports recursive local simplification behind a budget flag (see runtimeverification/haskell-backend#4153), and the asWord-eq-false simplification added in #2859 loops in the Kore simplifier on a term shape that arises in CSE proofs. This branch exposes the backend flag through the prover and removes the looping lemma, with a regression test guarding against its reintroduction.

Changes:

  • kevm prove + the pytest proof harness gain --equation-max-local-steps, threaded through to the kore-rpc-booster / booster-dev servers and defaulting to 20 (the backend's recursive local-simplification budget; backend default = restart-only). Non-booster servers skip the flag with a warning.
  • Removed asWord-eq-false from lemmas/evm-int-simplification.k. When both operands of the ==Int are #asWord terms it rewrites the equality into its own requires with the operands swapped — still #asWord-on-the-left — so it re-matches and recurses without bound in the Kore simplifier (the root cause of the CSE-proof timeouts, kontrol Fix documentation for #range and codeblocks #1153). The antisymmetric <Int/<=Int siblings are loop-safe and stay.
  • Added tests/specs/functional/asword-eq-false-loop-spec.k, a functional regression test (auto-collected by the functional suite) whose claims time out if the looping rule is reintroduced and discharge once it is gone.

Validation:

  • make -C kevm-pyk check and make -C kevm-pyk test-unit pass.
  • test_prove_functional[functional/asword-eq-false-loop-spec.k] passes (~103 s); confirmed the same spec does not terminate against the pre-removal lemma, and that the loop reproduces even with --equation-max-local-steps 20.
  • I've confirmed that this allows Kontrol CSE proofs to complete. There still may be some performance regression with them, but not as massive if so.

ehildenb and others added 7 commits June 14, 2026 18:25
…on-max-local-steps to booster servers

Exposes the haskell-backend's new recursive-simplification budget
(equation evaluation applied in place at rewritten subterms, hb #4153;
backend default 0 = restart-only) through kevm prove and the pytest
harness:

  - cli.py: ProveOptions.equation_max_local_steps + kevm prove flag.
  - __main__.py: appends the flag to the resolved kore-rpc-booster /
    booster-dev command; rejects non-booster servers explicitly.
  - conftest.py / test_prove.py: pytest --equation-max-local-steps option
    threaded through all prove suites.

(cherry picked from commit e6597556e913f1a6340fcb7f959a84422976a772)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ion-max-local-steps to 20

Turn the booster recursive-simplification budget on by default (20) for
kevm prove and all pytest prove suites, instead of deferring to the
backend's restart-only default of 0:

  - cli.py / conftest.py: default 20; option type narrows to int.
  - __main__.py: with the budget now always set, a non-booster server
    skips the flag with a warning instead of raising.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…op_harness.py: asWord-eq-false loop regression test

Adds a functional regression test that guards against reintroducing the non-terminating
`asWord-eq-false` simplification (evm-semantics #2859 / kontrol #1153): three claims that
evaluate `#asWord ==Int #asWord` known-unequal from the path condition. With the looping rule
present each claim's simplification does not terminate and the proof times out; with the rule
gone they discharge. Collected by the functional suite (`functional/*-spec.k`) against the
shared VERIFICATION definition. `scripts/asword_loop_harness.py` runs such loop specs standalone
under a per-claim timeout (LOOP / PASS / FAILED) for local triage, since a non-terminating RPC
request produces no per-request log bundle.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…se simplification

`asWord-eq-false` (added in #2859) loops in the Kore simplifier when both operands of the
`==Int` are `#asWord` terms: applying it rewrites the equality into its own `requires` with the
operands swapped (still `#asWord`-on-the-left), so it re-matches and recurses without bound. This
was the root cause of the CSE-proof timeouts (kontrol #1153). Removing the rule ends the loop; the
`<Int`/`<=Int` siblings are antisymmetric and stay. Regression test:
tests/specs/functional/asword-eq-false-loop-spec.k.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The asWord-eq-false regression is guarded by the functional spec alone
(tests/specs/functional/asword-eq-false-loop-spec.k); the standalone triage harness is not
needed in this branch.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e relocated eq-false-lt CSE loop

Captures the second CSE non-termination layer (evm-semantics #2859 / kontrol #1153) that remains
after asWord-eq-false is removed: eq-false-lt × AccountCellMap definedness, a Kore constraint-simplifier
fixpoint failure on undetermined account-id comparisons. Kept under loops/ (not collected by the
functional suite) because it is UNVERIFIED and, per the change request, does not reproduce in a fresh
single proof — the spin only arises on a long-lived server once constraints accumulate.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…CSE Kore non-termination)

eq-false-lt (`A ==Int B => false requires A <Int B [simplification, concrete(B)]`, added in #2859)
is the rule that drives the CSE Kore-simplifier non-termination that removing asWord-eq-false only
relocated to (kontrol #1153). During the Kore definedness check of `#Ceil(<accounts> AccountCellMap)`,
the account-distinctness predicates `ACCT_ID ==Int <concrete address> => false` invite this rule,
whose side condition `A <Int B` is undetermined for a range-bounded symbolic account id vs a large
concrete address, spawning a ~500ms SMT round-trip per attempt that the constraint simplifier repeats
without reaching a fixpoint. Confirmed via per-request logs to be the sole rule driving those SMT calls
(removing it took the rule-driven SMT count from 45 to 0 on the exemplar). Disabled for now; re-introduce
once Booster performs definedness without falling back to the Kore simplifier.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ehildenb and others added 2 commits June 15, 2026 14:25
…xemplar for CI collection

Move the eq-false-lt
loop exemplar out of the non-collected loops/ subdir into tests/specs/functional/
so the functional test harness picks it up via spec_files('functional', '*-spec.k').

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… to close asWord-unif-03/04 without asWord-eq-false

Removing the looping asWord-eq-false lemma un-masked a coverage gap: the lemmas-spec
asWord-unif-03/04 claims (#2604) decompose an out-of-range #asWord(B) ==Int CONST via
asWord-eq-num into CONST <Int #powByteLen(N), which must reduce to false. #powByteLen is
[no-evaluators] and #2859 added only the true-direction powByteLen-lt-concrete rule,
leaving the false direction to asWord-eq-false. Add the mutually-exclusive, loop-safe
false-direction companion so the concrete comparison is total, plus a focused regression
claim alongside the existing true-direction test.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@ehildenb ehildenb marked this pull request as ready for review June 15, 2026 16:16
@ehildenb ehildenb merged commit 38893bd into master Jun 15, 2026
12 checks passed
@ehildenb ehildenb deleted the asword-eq-false-loop-fix branch June 15, 2026 16:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants