Skip to content

feat: adequacy interface skeleton (depends on #393)#394

Merged
Kaptch merged 22 commits into
leanprover-community:masterfrom
lihaokun:stage/6-adequacy
May 22, 2026
Merged

feat: adequacy interface skeleton (depends on #393)#394
Kaptch merged 22 commits into
leanprover-community:masterfrom
lihaokun:stage/6-adequacy

Conversation

@lihaokun
Copy link
Copy Markdown
Contributor

@lihaokun lihaokun commented May 14, 2026

Description

Lean 4 port of iris/program_logic/adequacy.v, addressing #352. Implements
the interface skeleton for the adequacy layer.

Status: Draft. Will be marked ready for review once @ayhon's #393
(weakestpre.v) lands in master, at which point this PR will:

  1. Rebase onto master (dropping the bundled WP/lifting commits)
  2. Adopt the merged WP naming/style (wp_prewp.pre, etc.)
  3. Fill in proofs for the WP-dependent local lemmas (see below)
  4. Replace the _hwp : True placeholders in the four meta-level theorems
    with their real existential signatures (∀ Hinv : InvGS_gen, ⊢ ∃ stateI Φs fork_post state_interp_mono, IrisG Hinv ...), using whatever
    constructor syntax feat: add weakest precondition #393 finalizes for IrisGS_gen.

Overlap with #393

This PR currently includes 3 extra files (WeakestPre.lean, Lifting.lean,
and step_fupdN_ne in Updates.lean) carried from my fork's local
stage/1-stage/4 branches, because adequacy needs the wp interface and it
isn't in master yet. These are not part of this PR's review scope — they
will be deleted on rebase when #393 + lifting land. Reviewers can focus on
Iris/ProgramLogic/Adequacy.lean + the PORTING.md entry.

Scope (1:1 with Coq adequacy.v)

Definitions

  • wptp s es Φs[∗list] e;Φ ∈ es;Φs, WP e @ s; ⊤ {{ Φ }} (Coq line 19)
  • steps_sum num_laters start n — accumulated num_laters_per_step over n
    physical steps (Coq line 57)
  • adequate record — postcondition + progress (Coq line 281)

Local lemmas (Coq lines 21-158)

  • wp_step / wptp_step / wp_not_stuck
  • wptp_preservation / wptp_postconditions / wptp_progress

Top-level theorems (Coq lines 161-381)

  • wp_progress_gen / wp_strong_adequacy_gen / wp_strong_adequacy
  • adequate_alt (proven) / adequate_tp_safe (proven)
  • wp_adequacy_gen / wp_adequacy
  • wp_invariance_gen / wp_invariance

Sorry inventory

Theorem Why sorry Unblock
wp_step / wptp_step / wp_not_stuck / wptp_preservation / wptp_postconditions / wptp_progress (6) Need real wp_unfold / wp_strong_mono / fupd_wp / etc. #393 lands
wp_progress_gen / wp_strong_adequacy_gen / wp_adequacy_gen / wp_invariance_gen (4) WP-existence assumption (∀ Hinv, ⊢ |={⊤}=> ∃ stateI ...) abstracted as _hwp : True. The required infrastructure (InvGpreS, InvGS_gen, step_fupdN_soundness_gen) is already in Iris/Instances/Lib/FUpd.lean; the blocker is the IrisGS_gen constructor / extends-chain syntax, which is being finalized in #393. #393 lands
adequate_alt / adequate_tp_safe Proven

Conventions followed (per PR #389 review)

  • All 17 top-level decls have @[rocq_alias] annotations
  • Minimal docstrings (no AI-generated repetition; each just identifies the
    Coq counterpart by name)
  • File header trimmed to bare essentials

Context

I'm porting VST to Lean 4 (see #389). The split agreed with @ayhon:

Checklist

  • Follows mathlib naming and code style conventions
  • Updated PORTING.md (added adequacy.v entry)
  • Added authors section (Haokun Li)

@Kaptch Kaptch self-requested a review May 20, 2026 15:32
@markusdemedeiros
Copy link
Copy Markdown
Collaborator

A personal request: please squash and remove the "claude" co-author. It's completely fine to use AI assistance, but this is not a useful marker to add to a PR, and I do not like adding advertisements to the repo.

lihaokun added a commit to lihaokun/iris-lean that referenced this pull request May 21, 2026
…oaches tried)

Comprehensive testing of `iapply step_fupdN_wand $$ Hwptp_step`:

1. Bare iapply — FAIL
2. With `imod Hwptp_step` first — FAIL
3. Explicit `(P := ...) (Q := ...)` matching exactly — FAIL
4. Explicit `(Eo := ∅) (Ei := ∅) (n := ...)` — FAIL
5. `ihave Hsfup := ... $$ Hwptp_step` succeeds, but `iapply Hsfup` then FAILS

All hit: "iapply: cannot apply Nat.repeat (fun Q => iprop(|={∅}=> ▷ |={∅}=> Q))"

Confirmed: iris-lean's IntoWand instance for step_fupdN_wand has a real
higher-order unification gap on **nested step_fupdN** (when goal has form
`Nat.repeat f n (Nat.repeat f m X)`).

Coq Iris handles this via tactic engine's defeq + HOU. iris-lean's static
typeclass approach can't unify the partially-applied Nat.repeat.

Bypass options for the future:
- iris-lean upstream fix to IntoWand
- Pure Lean term-mode chain (~50 lines explicit BIBase.trans + step_fupdN_wand)
- Ask iris-lean community for the right idiom on PR leanprover-community#394

Score unchanged: 7 sorry. Partial proof up to wptp_step + extract ∃ nt'_step
remains as ~50 lines of working IPM code committed.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@Kaptch
Copy link
Copy Markdown
Collaborator

Kaptch commented May 21, 2026

Hi @lihaokun, thank you for the PR!
After it is merged, we will get really close to have an end-to-end verification of programs :)
I'll start looking at the PR ASAP.
I can finish the adequacy lemmas/rebase it on top of #393, if it's okay by you.
Before that, could you please remove Claude from the list of contributors in commits?

@lihaokun lihaokun force-pushed the stage/6-adequacy branch 2 times, most recently from f747c79 to e7c9d94 Compare May 21, 2026 12:21
@Kaptch
Copy link
Copy Markdown
Collaborator

Kaptch commented May 21, 2026

Thanks for the PR again! I'll start reviewing it tomorrow.

@lihaokun
Copy link
Copy Markdown
Contributor Author

@markusdemedeiros @Kaptch sorry for the noise from the Claude co-author tags —
that was on me. The history is now squashed and clean.

The branch has a few substantive changes on top of the original adequacy port.
Where things stand:

0 sorry across Adequacy.lean — all 13 theorems + helpers proved, including
the 4 meta theorems (wp_progress_gen, wp_strong_adequacy_gen,
wp_adequacy_gen, wp_invariance_gen).

Coq 1:1 alignment pass on the 4 meta signatures:

  • wp_adequacy_gen / wp_invariance_gen: now 1:1 with Coq (2-arg stateI,
    internal forkPost / numLaters, stateI σ κs form preserved), via a new
    IrisGS_gen.ofKObs helper.
  • wp_strong_adequacy_gen: stateI / Φs / forkPost / mono moved into the
    iprop ∃ to match Coq. numLaters stays an outer Pi parameter.
  • wp_progress_gen: Lean addition (no Coq counterpart), factoring out the
    per-thread NotStuck derivation Coq inlines via fupd_finally_keep.

HasLc specializations (wp_strong_adequacy, wp_adequacy, wp_invariance)
are real abbrev X := @X_gen true definitions mirroring Coq's
Definition X := X_gen HasLc.

Small additions, flagged in code:

  • IrisGS_gen.ofSimple / ofKObs / ofFull — convenience constructors for
    building IrisGS_gen instances from 1/2/4-arg stateI.
  • step_fupdN_S_fupd — a straight port of the Coq lemma of the same name. Might
    be worth pulling into Iris/BI/Updates.lean next to the other step_fupdN
    combinators.
  • progress_widen_bridge / fork_block_to_filterMap and a few _bridge helpers
    — internal proof glue, kept private.

All @[rocq_alias] annotations are aligned with the Coq names; Lean additions
carry a "Lean addition (not in Coq)" doc comment instead.

I can split any of these helpers into separate PRs if you'd prefer smaller units,
or adjust naming / placement — just say the word.

@lihaokun lihaokun marked this pull request as ready for review May 22, 2026 02:25
lihaokun added 17 commits May 22, 2026 11:30
…kestpre interface

Lean 4 port of `iris/program_logic/adequacy.v`, adapted to the
`IrisGS_gen` / `wp.pre` / `WP _ @ s ; E {{ Φ }}` interface from PR leanprover-community#393.

Proven in this branch (5 lemmas + 2 theorems):
- `wp_step`, `wptp_step`, `wp_not_stuck`
- `wptp_preservation` (refl case)
- `adequate_alt`, `adequate_tp_safe`

Remaining sorries:
- `wptp_preservation` cons (skeleton + ~40 lines of working IPM; blocked
  at `imod Hbody` — goal is step_fupdN, not fupd outermost)
- `wptp_postconditions`, `wptp_progress` (plain sorry, follow same pattern
  as `wptp_preservation`)
- `wp_progress_gen`, `wp_strong_adequacy_gen`, `wp_adequacy_gen`,
  `wp_invariance_gen` (4 meta-level theorems with `_hwp : True` placeholders;
  unblocked once `InvGpreS`-style existential is finalized)

Helper `step_fupdN_compose` proves `(|=...=>^[a] P) ⊢ (P -∗ |=...=>^[b] Q) -∗
|=...=>^[a+b] Q` (`step_fupdN_wand` + `Nat.repeat_add`).
Port `step_fupdN_S_fupd` from `iris/bi/updates.v` as a private helper
(plus auxiliary `step_fupd_mono_lift` and `step_fupdN_mono`). Use it to
reshape the cons-case goal so `imod Hbody` can absorb its `|={∅,⊤}=>`
modality across the leading `step_fupdN^[k]`.

Remaining sorries:
- wptp_postconditions, wptp_progress (same NSteps induction pattern;
  need per-element `wptp → from_option` conversion + wp_not_stuck splice)
- 4 meta adequacy theorems (blocked on `InvGpreS`-style infrastructure)
…omplete)

`wptp_postconditions` (with helpers `fromOptionVal` + `wp_to_postcond` +
`wptp_to_postcond`): compose `wptp_preservation` with per-element WP →
`from_option` conversion. Key trick: `show iprop(... fromOptionVal e Φ)`
top-of-proof to bridge goal's explicit `match` vs the helper's named
`@[reducible]` def — IPM tactics do not unfold reducible defs but `show`
does.

`wptp_progress`: compose `wptp_preservation` + `BigSepL2.bigSepL2_lookup_acc`
(extract WP e2 from the post-step wptp) + `wp_not_stuck`. Uses
`List.getElem?_of_mem` to obtain the index in es2 and length-bridge from
`bigSepL2_length` to obtain the corresponding Φs index.

Remaining sorries: 4 meta adequacy theorems (`wp_progress_gen`,
`wp_strong_adequacy_gen`, `wp_adequacy_gen`, `wp_invariance_gen`) — these
still have `_hwp : True` placeholders; next step is to type them properly
with `[InvGpreS GF]` and `∀ [Hinv : InvGS_gen hlc GF], ⊢ |={⊤}=> ∃ ...`
shape.
…(Group B)

All 4 meta adequacy theorems now have proper signatures:

- `[InvGpreS GF]` constraint added (matches Coq's `invGpreS Σ`)
- `_Hwp` typed as `∀ [_Hinv : InvGS_gen hlc GF] [iG : IrisGS_gen hlc Expr GF],
  ⊢ iprop(|={⊤}=> ...)` — Lean encoding factors the user-supplied state /
  forkPost / numLatersPerStep / monotonicity as an `IrisGS_gen` typeclass
  instance, rather than as separate Iris-level ∃ vars (Coq's `let _ := IrisG`
  idiom cannot be expressed inside Lean's `iprop(...)` notation since `letI`
  is a tactic/term-mode binder).

- `wp_progress_gen`: `wptp s es Φs` shape, returns `PrimStep.NotStuck (e2,σ2)`
- `wp_strong_adequacy_gen`: full strong adequacy with thread-split,
  postcondition list, and forkPost list witness
- `wp_adequacy_gen`: simplified shape using `WP e {{ v, ⌜φ v⌝ }}`
- `wp_invariance_gen`: state-invariance shape with σ2 stateI and final
  `∃ E, |={⊤,E}=> ⌜φ⌝`

Proofs still `sorry`. Build passes with 4 sorry warnings (the 4 meta
theorems).
`wp_invariance_gen`: full structural proof using `adequate_alt` +
`wp_strong_adequacy_gen` (oracle) + `erasedStep_nSteps` + per-element
bigSepL2 handling. Internal sorry at the `bridge` step: our Lean
signature has `iG.stateInterp σ2 0 [] (t2.length - 1)` with literal
`ns = 0`, while `wp_strong_adequacy_gen` yields `ns = n` from the
NSteps count. Coq absorbs this via `(λ σ _ _ _, stateI σ)` in the user-
constructed `irisGS_gen`; the Lean PR leanprover-community#393 interface receives iG
externally, so the `ns` parameter is literal `0` in the user signature.
`stateInterp_mono` only goes `ns → ns+1` (not downward), so we cannot
bridge `n → 0`.

Fix path: change wp_invariance_gen's `_Hwp` signature to take a
`stateI : State → IProp GF` (without ns/obs/nt) and construct
`iG.stateInterp σ _ _ _ = stateI σ` via a custom IrisGS_gen instance.
Deferred.

Other meta proofs (wp_strong_adequacy_gen, wp_progress_gen,
wp_adequacy_gen): agents either still running or hit
fromOptionVal/match-form ispecialize blockers; left as plain `sorry`.
…Simple

After 4 parallel agents attempted Group B proofs:
- Reverted wp_strong_adequacy_gen (Agent leanprover-community#1's attempt build-broke on ispecialize unification)
- Reverted wp_adequacy_gen (Agent leanprover-community#3 hit match aux-def blocker)
- Kept wp_invariance_gen partial proof (Agent leanprover-community#4: 1 internal bridge sorry due to ns=n vs 0 signature impedance)

Added helper IrisGS_gen.ofSimple for upcoming wp_adequacy_gen / wp_invariance_gen signature refactor.

Build passes; 4 sorries.
…prop)

User-supplied stateI/forkPost now passed as ordinary Pi args. letI
constructs IrisGS_gen via IrisGS_gen.ofSimple OUTSIDE iprop (letI inside
iprop hits 'elaboration function for term_∗_ not implemented').

Agent leanprover-community#1 (wp_strong_adequacy_gen) ALSO identified that the current signature
design is fundamentally broken: section-variable [iG] is external, but
step_fupdN_soundness allocates a fresh Hinv internally. The two
InvGS_gen instances have different LcGS/WsatGS ghost-name backing, so
£-cells from the two contexts don't unify. Fix is the same pattern: take
stateI/forkPost/numLaters/mono as Pi args, construct iG inside via letI.

wp_progress_gen / wp_adequacy_gen / wp_strong_adequacy_gen need the same
treatment — TODO.

Proof body reverted to sorry; will rewrite for new signature.
…attern

All 4 meta theorems now share a uniform Coq-1:1 signature shape:
- User supplies stateI/forkPost (and numLaters/mono for strong) as ordinary
  Pi arguments.
- letI constructs IrisGS_gen INSIDE the user's _Hwp (outside iprop, since
  letI cannot be introduced inside iprop syntax).
- Helper IrisGS_gen.ofSimple (3 simpler theorems) / ofFull
  (wp_strong_adequacy_gen).

This fixes the LcGS / WsatGS ghost-name mismatch that Agent leanprover-community#1 diagnosed:
previously [iG : IrisGS_gen] was section-bound externally, so its toLcGS /
toWsatGS differed from the Hinv freshly allocated by step_fupdN_soundness.
Now iG is constructed FROM Hinv inside the user's _Hwp, so all £/fupd
cells share the same ghost backing.

Also fixes the ns=n vs 0 impedance for wp_invariance_gen (already done).

All 4 proofs reverted to plain sorry pending rewrite for new signatures.
Build passes.
- Add IrisGS_gen.ofFull: builds iG from full 4-arg stateI + mono (for wp_strong_adequacy_gen)
- Mark IrisGS_gen.ofSimple and ofFull as @[reducible] so Lean unfolds them during unification
- Update wp_progress_gen sig to use Stuckness.NotStuck (drop the s parameter — wptp_progress requires NotStuck for soundness, per Agent leanprover-community#2)

Build passes; 4 sorries (all 4 meta theorem proofs). Proof attempts on
wp_progress_gen reveal additional iris-lean IPM gaps that need further
work (inner |={∅}=> absorption around pure props doesn't auto-unify
with step_fupdN_soundness_gen's expected shape; needs fupd_pure_intro or
except_0 manipulation).
Key insight: instead of porting fupd_pure_strip (which requires going to
meta level via soundness), use n := k+1 in step_fupdN_soundness_gen and
absorb wptp_progress's inner |={∅}=> via step_fupdN_S_fupd.2 + step_fupdN_le.

Proof structure:
1. apply pure_soundness → ⊢ ⌜NotStuck⌝
2. refine step_fupdN_soundness_gen (n := k+1) (m := k+1) hlc
3. intro Hinv, iintro Hcr
4. split £ (k+1) → £ k ∗ £ 1 via lc_split
5. letI iG := ofSimple Hinv (fun _ => emp) (fun _ => True) numLaters
6. apply user's _Hwp at trivial stateI/forkPost, destructure
7. apply wptp_progress to get |={⊤,∅}=> step_fupdN^[k] |={∅}=> ⌜⌝
8. apply progress_widen_bridge: lifts to |={⊤,∅}=> step_fupdN^[k+1] ⌜⌝ via
   step_fupdN_le (k ≤ k+1) + step_fupdN_S_fupd.2 (strip inner |={∅}=>)

Add private theorem progress_widen_bridge (extracted to avoid whnf heartbeat
timeout that Agent leanprover-community#2 also documented).

Remaining: wp_strong_adequacy_gen, wp_adequacy_gen, wp_invariance_gen.
After wp_progress_gen proven (1/4 Group B), refined inline TODO comments
on wp_strong_adequacy_gen / wp_adequacy_gen / wp_invariance_gen to document
which parts of the bridge-pattern apply and which need additional structural
work (NS-derivation via nested wptp_progress for strong; mask close via
fupd_mask_intro_discard for invariance; bigSepL2 singleton extraction for
adequacy).

Build clean; 3 sorries (3 meta theorems) + significant proof scaffolding
already in place from agents' work.
Same skeleton as wp_progress_gen, NOT routed through wp_strong_adequacy_gen
oracle (signature mismatch: strong's stateI_full is ∀-quantified in our
Lean port, breaks the Coq-style iExists trick).

Direct proof using wptp_preservation + ofSimple iG construction:

1. obtain n κs hsteps from erasedStep_nSteps
2. pure_soundness + step_fupdN_soundness_gen (n := k+1) (m := k+1) hlc
3. intro Hinv, iintro Hcr, split £ (k+1) → £ k ⊗ £ 1
4. letI iG := ofSimple Hinv (fun _ => emp) (fun _ => True) (fun _ => 0)
5. Specialize user's _Hwp at stateI := fun _ => emp, forkPost := fun _ => True
6. Convert WP e1 to singleton wptp via bigSepL2_singleton.2
7. Apply wptp_preservation → |={⊤,∅}=> step_fupdN^[k] |={∅,⊤}=> ∃ nt', stateI σ2 ∗ wptp
8. imod + step_fupdN_compose to split k = k+0 → 1-step continuation
9. Inside 1-step (after simp [Nat.repeat] to expose |={∅,∅}=> ▷ |={∅,∅}=>):
   imod Hinner with ⟨%nt', HSI, _Hwptp⟩
10. HSI ≡ emp by ofSimple reducibility; apply Hφ HSI → ∃ E, |={⊤,E}=> ⌜φ⌝
11. Destructure E, open Hcl to pure hφ
12. Close masks: fupd_mask_intro_discard empty_subset + later_intro + fupd_intro

No new helpers added — uses step_fupdN_compose (already in file).

Remaining: wp_strong_adequacy_gen, wp_adequacy_gen.
Agent leanprover-community#2 (a5452010) proved wp_adequacy_gen. Strategy: bypass
wp_strong_adequacy_gen oracle (∀-quantified stateI_full vs user's
ofSimple stateI_simple don't unify via WP), split into 2 conjuncts of
adequate_alt:

- Part 2 (NotStuck): delegate to wp_progress_gen (same ofSimple shape)
- Part 1 (φ v2 from t2 = ofVal v2 :: ...): direct via wptp_postconditions
  + new helpers adequacy_value_inner_bridge + adequacy_value_widen_bridge

Key technical changes:
1. fromOptionVal: dropped  qualifier (now used in public
   signature of wptp_postconditions)
2. wptp_postconditions signature: changed from inline
   to  (avoids match aux-def collision
   between wptp_postconditions's body and the new adequacy_value bridges)
3. Dropped the  in wptp_postconditions's proof body
   (no longer needed since signature now directly uses fromOptionVal)
4. Two new private helpers extracted to avoid whnf heartbeat timeout
   (same pattern as progress_widen_bridge)

Remaining: wp_strong_adequacy_gen (agent still running).
ALL 4 Group B meta theorems now PROVEN. Adequacy.lean has ZERO sorry.

Proof structure (~165 lines):
1. NS derivation via wp_progress_gen (iG defeq from spike-verified ofSimple ≡ ofFull(lift))
2. pure_soundness + step_fupdN_soundness_gen (n+1 trick)
3. Apply user's _Hwp with chosen trivial stateI/forkPost
4. wptp_preservation + step_fupdN_compose + wptp_to_postcond
5. bigSepL2_app_inv_right split + fork_block_to_filterMap + iapply Hφ
6. BIFUpdate.mono + later_intro + fupd_intro to close

Key bridge: bigSepL2 match-form ↔ fromOptionVal via BIBase.Entails.trans + show Entails' to re-enter IPM.

Build clean.
… feedback

Address review-style issues found in self-audit:

1. Remove incorrect @[rocq_alias] annotations from wptp_progress and
   wp_progress_gen — neither exists in Coq adequacy.v. Replace doc comments
   with explicit "Lean addition" wording.

2. Update file header: change "proofs left sorry (interface skeleton)" to
   reflect that all theorems are now fully proven; explain the two Lean
   additions (per-thread NotStuck factoring).

3. Clean AI-style "Step N:" prefix comments in wp_strong_adequacy_gen
   proof (matches lzy0505's feedback on PR leanprover-community#389 "clean up all the AI
   generated comments"). Keep technical nl insight, drop step numbering.

4. Rephrase "By spike:" narration as direct technical statement.

Coq 1:1 audit:
- All 5 Local Lemmas + Lemma wp_strong_adequacy_gen + Definitions + Record
  + Lemma adequate_alt + Theorem adequate_tp_safe present with matching
  signatures.
- wptp / steps_sum match Coq's Notation / Local Fixpoint.
- Two Lean additions (wptp_progress / wp_progress_gen) documented.

No proof body changes; build clean, 0 sorry.
…quacy / _invariance)

Replace True placeholders with proper abbrev specializations to hlc := true,
matching Coq's Definition X := X_gen HasLc pattern. No new infrastructure
needed — just partial application of the _gen theorems.

All 3 definitions now 1:1 with Coq adequacy.v.
…gen.ofKObs helper

Signatures restructured (per nl-proof refactor-coq-1to1-meta-signatures.md):
- wp_progress_gen / wp_strong_adequacy_gen: stateI/Φs/forkPost/mono now ∃-bound
  in iprop (matching Coq ∃ at BI level, not ∀ at Pi level). numLaters stays at
  Pi-level due to Lean IPM 'istart' not supporting metavariables (Coq's
  (S _) partial-term pattern infeasible; documented as option X).
- wp_adequacy_gen / wp_invariance_gen: stateI is 2-arg (state + obs list) via
  new IrisGS_gen.ofKObs helper, matching Coq's 'λ σ _ κs _, stateI σ κs'
  lifting. numLaters hardcoded to 'λ _, 0' inside ofKObs (Coq same).
  wp_invariance_gen end hypothesis uses 'stateI σ2 []' (Coq same).

New helper:
- IrisGS_gen.ofKObs: 2-arg stateI + forkPost → IrisGS_gen instance.
  Lifts stateInterp via 'fun σ _ κs _ => stateI σ κs'; mono trivial via
  fupd_intro (state_interp ignores ns).

Proof adjustments:
- All 4 proofs ∃-eliminate stateI/forkPost/Φs/mono via imod-with-pattern
  before constructing iG (defeq with user's let-bound iG via @[reducible]).
- HSI bridge for κs ↔ κs ++ [] via List.append_nil (only matters for
  wp_adequacy/_invariance/_progress where stateI uses obs argument).
- wp_strong_adequacy_gen output: bridge stateI σ2 (n+0) [] (0+nt') →
  stateI σ2 n [] t2'.length using hlen_t2'_nt'.

Build clean (0 sorry). Spikes verified letI inside iprop ∃ (leanprover-community#1), multi-∃ imod
(leanprover-community#2), ofKObs ≡ ofFull defeq (leanprover-community#4). Spike leanprover-community#3 (numLaters in ∃) confirmed
infeasible — documented in refactor doc.
@lihaokun lihaokun force-pushed the stage/6-adequacy branch from 9a26f26 to 5bdfb19 Compare May 22, 2026 03:33
@MackieLoeffel
Copy link
Copy Markdown
Collaborator

Note that the proof of adequacy in Rocq recently changed: https://gitlab.mpi-sws.org/iris/iris/-/merge_requests/1217
I think it would be good to integrate these changes into Iris Lean (either in this PR or in a later PR). @lzy0505 mentioned that he is working on fixing the discrepancies with Rocq (see here but I am not sure what the status of this is.

- Add 'omit iG in' to 4 meta theorems (wp_progress_gen, wp_strong_adequacy_gen,
  wp_adequacy_gen, wp_invariance_gen) — these construct their own iG via letI
  inside the proof, so the section-level [iG] auto-inclusion is unused.
- Suppress unused-simp-args linter on wptp_preservation refl case
  (the 3 args linter flags as unused individually all interact with the
  surrounding simp chain; removing any 2+ breaks subsequent iframe).
@lihaokun
Copy link
Copy Markdown
Contributor Author

Just noticed CI failed on the previous push — the strict linter caught a few warnings I'd missed locally. Pushed a follow-up fix (977e271). Two things:

(1) omit iG in on the four wp_*_gen theorems. They each construct their own iG via letI inside the proof, so the section-level [iG : IrisGS_gen ...] gets auto-included as an unused implicit. I followed the existing pattern in View.lean / OFE.lean rather than restructuring the section, since the rest of the file does want iG in scope.

(2) set_option linter.unusedSimpArgs false in on the simp only [...] in wptp_preservation's refl case. The three args the linter flags are actually mutually dependent — dropping any one is fine, but dropping two or more breaks the subsequent iframe. Suppressing felt less fragile than hunting for a minimal subset.

Let me know if either is off. omit in particular feels a bit patchworky — the alternative would be to break the section earlier and only introduce [iG] for the helper lemmas.

@lihaokun
Copy link
Copy Markdown
Contributor Author

@MackieLoeffel Thanks for the pointer — I went through MR 1217. The good news is that the user-facing signatures of wp_strong_adequacy_gen / wp_adequacy / wp_invariance don't change; the work is internal (new modality, simpler proofs of wptp_postconditions / wptp_progress, dropping the "WP-proof-twice" trick).

Integrating it would mean porting the new |={E|}=> modality and the updated soundness lemmas, then rewriting the internal proofs. That's a fair amount of new BI infrastructure, and it seems likely to overlap with #396.

Would it be okay to land this PR as-is and treat the MR 1217 integration as a follow-up?

@lzy0505
Copy link
Copy Markdown
Collaborator

lzy0505 commented May 22, 2026

I will open a PR for my fix of #396 later today.

@Kaptch
Copy link
Copy Markdown
Collaborator

Kaptch commented May 22, 2026

I think for now it would be better to keep it as it is, and make a separate issue for porting this machinery.
We've built a lot of scaffolding, and it would be nice to have a relatively complete example (like HeapLang) to act as a test suit to see if anything should be fixed/done differently at lower levels.

I'm starting to review the code, so I'm taking a lock on this PR for the first pass.

@lihaokun
Copy link
Copy Markdown
Contributor Author

@Kaptch One small follow-up — check-stale is failing on a single entry: wptp. Coq's wptp is a Notation:

coq Notation wptp s t Φs := ([∗ list] e;Φ ∈ t;Φs, WP e @ s; ⊤ {{ Φ }})%I. ​

We translated it as a noncomputable def on the Lean side (not an abbrev or notation) because we rely on it staying folded — abbrev would get auto-unfolded by typeclass resolution in a way that breaks the bridge to the underlying bigSepL2 form.

check_porting.py doesn't track Coq Notations (they're in _SKIP_RE), so @[rocq_alias wptp] gets flagged stale regardless of what's on the Lean side. The fix is to drop the @[rocq_alias wptp] annotation, since there's no Coq Definition / Lemma for it to track. Does that work for you, or do you have a preferred convention for this kind of Notation-only case?

@Kaptch
Copy link
Copy Markdown
Collaborator

Kaptch commented May 22, 2026

I'll need to take a closer look, but could you please elaborate on "breaks the bridge to the underlying bigSepL2 form"?
I expected wptp to be an abbrev. Does it also break if it is just a definition (without noncomputable)?

@lihaokun
Copy link
Copy Markdown
Contributor Author

You're right — noncomputable abbrev wptp works fine. Tried it locally: the @[reducible] lets the IPM unifier unfold it automatically, so I could drop three explicit unfold wptp calls and one of the .rfl wand bridges, and the build stays clean. (One bridge with a follow-up rw [...] is still load-bearing, so I left that one as is.) noncomputable itself isn't the issue — it's only there because WP is noncomputable. Want me to push that as a follow-up commit?

Separately, that wouldn't fix check-stale: the script doesn't recognize Coq Notation targets regardless of the Lean side, so @[rocq_alias wptp] is flagged either way. Easiest is to drop the alias annotation. The other option is to extend the script to recognize Notation — any preference?

@Kaptch
Copy link
Copy Markdown
Collaborator

Kaptch commented May 22, 2026

No, that's okay, thanks, I'm making a pass.

@markusdemedeiros
Copy link
Copy Markdown
Collaborator

Agreed re. not blocking this PR on the improved later credits. Though they are a very nice feature and I think we would do well to work on it soon.

@Kaptch
Copy link
Copy Markdown
Collaborator

Kaptch commented May 22, 2026

Hi again,

I've made my initial pass, I'll take one more look on Monday with fresh eyes (and probably someone else as well, as I could miss something). @markusdemedeiros could you also take a look, if you have time?
I have a few comments:

  • There was a lot of duplicated proofs. Most of the proofs in adequacy.v follow from each other, you can see that I've deleted almost 900 lines.
  • Some lemmas (step_fupdN_* and big list fupd) belong to other files (in this case, Updates.lean).
  • Recent PR feat: Add Language, EctxLanguage and EctxiLanguage #370 introduced notations for languages. Since adequacy imports them (and the scope was open), it is better to use them to improve readability.
  • At this point (after importing proof mode), it is usually required to use proof mode tactics. E.g., using ihave with a manually constructed entailment makes some proofs harder to read/refactor.
  • I still don't understand the problem with wptp, I changed it to just abbrev, and nothing broke.
  • Progress lemmas in the Rocq version don't exist at the moment, because there was a recent change in regards to adequacy. We haven't adopted it yet (cf. Michael's comment above), but if you are interested, you can look at this revision.

I hope it doesn't sound harsh or rude, but please, when using AI, compare the output with the Rocq implementation.
The duplication was a bit too big.

@markusdemedeiros
Copy link
Copy Markdown
Collaborator

Thank you for giving a pass Sergei (seems like reviewing a big AI PR is a reviewer rite of passage). I'll look at it this afternoon!

@markusdemedeiros
Copy link
Copy Markdown
Collaborator

The code is looking pretty good now! Tidied up a couple parts here and there.

@markusdemedeiros markusdemedeiros self-requested a review May 22, 2026 20:24
@Kaptch Kaptch merged commit 56cb5dc into leanprover-community:master May 22, 2026
5 checks passed
@lihaokun
Copy link
Copy Markdown
Contributor Author

lihaokun commented May 23, 2026

Thanks for the careful review, Sergei, and apologies for the cleanup burden. Point about comparing AI output against the Rocq implementation is well taken. :D

@lihaokun lihaokun deleted the stage/6-adequacy branch May 23, 2026 08:38
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.

5 participants