0043 — ◊4.5b: scoped-seam for nested-wrapping-handler resumption (the lr_sound moat scope)
-
Status: Accepted
-
Summary: ◊4.5b's resume-through-a-wrap edge is excluded by a scoped seam (the
NoWrapMissprimitive is landed); the cheap typed-CrelKclose (Architecture D) was build-probed NO-GO (noKrelS⇒HasStackbridge — the LR is one-way), so the ADR-0026 tested-descent seam is the verified-final answer for this edge. -
Depends-on: 0041, 0039, 0026, 0025, 0023
-
Status: Accepted — and the seam is now the verified-FINAL answer for this edge: the cheap typed-
CrelKclose (Architecture D) was build-probed and is NO-GO (2026-06-24; see "Probe result" below). The only remaining close is the heavy index-everything reshape (rabbit-hole, 4–7 sessions + a frozen-statement break), not worth one tested-descent edge. -
Layer: C+ (LR metatheory / proof architecture)
-
Depends on / amends: 0041 (the
▷subsystem ◊4.5b lives in), 0039 (the ◊4/◊4.5 split), [0026] (the verified-core / tested-superset descent), [0025] (deep resumptive handlers), [0023] (handler dispatch)
Context
◊4.5b's resumptive logical relation is one obligation from a fully axiom-clean lr_sound:
krelS_splitAt_decomp's handleF-MISS case — a handler dispatch whose captured continuation,
up to the catching handler, contains a non-catching handler (the "nested-wrapping" / "wrap-MISS"
edge). Everything else is closed: throws/state/txn equivalence at the catching frame, and resumption
through a captured continuation (krelS_append, the Biernacki §5.4 Lemma-2 config-append, build-proven).
Two fully-general closes were build-confirmed DEAD before this decision:
- Pinned-index reshape (re-index
KrelSby a determined answer type):KrelS-answer-determinism is FALSE — theletFclause existentially quantifies the continuation typeB, so two derivations over the same stacks pick different answers. Recorded as a rabbit-hole in task #10. - No-strip / circular: building the goal
KrelSatDᵢdirectly needs the reinstalled handler's own resume conjunct — exactly what is being proven;krelS_splitAt_decomplacks that interface.
Decision
The nested-wrapping-handler-resumption edge is excluded by a SCOPED SEAM, not closed. The
relation-level primitive NoWrapMiss is landed; the sorryAx-zero close (which requires a TYPED
CrelK) is build-pinned and deferred to a dedicated kernel session.
What landed (relation level — 2b4479b, whole-tree green)
Bang/Core/Semantics.lean gains a standalone predicate:
NoWrapMiss : EvalCtx → Label → OpId → Prop
| [], _, _ => True
| (handleF h :: K), ℓ, op => handlesOp h ℓ op = true ∨ splitAt K ℓ op = none
| (_ :: K), ℓ, op => NoWrapMiss K ℓ op
NoWrapMiss K ℓ op says the dispatch of (ℓ, op) reaches its catcher without passing through a
non-catching handler (the captured continuation up to the catcher is handler-free). ¬ NoWrapMiss
is exactly the splitAt-wrap-MISS edge. The kernel, KrelS, and the whole relation stay pristine
at e755afa — NoWrapMiss touches nothing else.
Covered / excluded
- COVERED (sound + proven): all observation contexts including legitimate handler stacking —
every dispatched op caught by its nearest enclosing handler (single-level handling; state-over-
throws and any focus-installed handler nesting where each op hits its nearest handler; resumption
through a handler-free captured continuation, via
krelS_append). - EXCLUDED (the narrow seam): resumption where the captured continuation up to the catching
handler contains a non-catching handler — i.e. a dispatched op is caught by a handler that is
not its nearest enclosing one (it "passes through" a shallower non-catching handler). This is
the single
krelS_splitAt_decompMISS sorry (Bang/Meta/BinaryLR.lean), the ADR-0026 tested-descent boundary: the catching-frame equivalence is fully verified; the pass-through edge is the documented descent.
Why sorryAx-zero needs a TYPED CrelK (the deferred close)
To make the MISS obligation vacuous, the biorthogonal closure CrelK must range only over stacks
that handle the focus's ops at the nearest handler. Every simple stack-scope predicate on the
runtime stack K₁ walls (build-and-reasoning-confirmed, this session), at one root cause: the
fundamental theorem's handle-arm pushes the focus's own handler (handle h M runs M over
handleF h :: K₁), which violates any runtime-stack scope:
- row-indexed
NoWrapMissRow K ε: walls atcrelK_ret'sletF(rowe → φchange; noφ ≤ ewithout typing); - row-agnostic "∀ ops
NoWrapMiss": walls atcrelK_ret'shandleF(passinghandleF hon aretexposesh's masked ops); - fully-
HandlerFree K₁: walls at the handle-arm (HandlerFree K₁ ⊬ HandlerFree (handleF h :: K₁)).
Distinguishing the focus's legitimately-pushed handler from a context wrap requires the focus
structure — a CrelK re-indexed by typing (HasCTy/HasStack), threaded through the whole mutual
block and every frozen Crel consumer. That is the pinned-index-reshape order of magnitude and is
deferred together with it as the "nested-wrap resumption" kernel project (see paths/archive/PATH-cap45-finish.md).
Rejected alternatives
- Pinned-index
KrelSreshape — DEAD (answer-determinism FALSE; build-confirmed). HandlerFree-restriction ON THEKrelShandleF clause (forbid a handler's tail from holding a handler) — OVER-FORBIDS: it bans legitimate handler stacking (state-over-throws is valid + tested; the reinstall lemmas buildhandleF h :: KwithKa handler stack), so it breakskrelS_refl. The wrap-MISS edge is narrower than "no nesting," so it cannot live as aKrelSrestriction.- Scope
lr_sound'sctxApproxalone — INSUFFICIENT: the sorry is upstream increlK_fund(= lr_fundamental), which provesCrelKfor ALL stacks; its handler/uparms carry the obligation regardless of howlr_soundlater instantiates it. - Bare
sorry— rejected: the seam is STRUCTURAL (NoWrapMiss+ the documented descent), so the limitation is explicit, not papered.
Consequences
- The kernel and
KrelSstay pristine (e755afa);NoWrapMissis the durable relation-level artifact. lr_sound/lr_fundamentalretain the single documentedkrelS_splitAt_decompMISS sorry — the honest moat scope, the verified domain being everything except pass-through resumption.The path to sorryAx-zero is fully specified→ PROBED, NO-GO (see below). The seam is final for this edge.
Probe result (2026-06-24) — Architecture D (cheap typed-CrelK) is NO-GO
A 5-agent design panel recommended Architecture D (literature-canonical typed CrelK that proves the
MISS rather than vacating it; scope as a PREMISE not an index, so the frozen statements survive;
~3–4 sessions): use HasStack's answer-index to recover the junction answer type the MISS sorry says
KrelS lacks. A bounded GO/NO-GO build probe (branch typed-crelk-probe @ ffac1b0,
Bang/Meta/BinaryLR.lean ~1466–1597) split the bet and the build cleanly arbitrated it:
- Answer-projection half WORKS —
hasStack_append_handleF_splitis PROVEN,#print axioms=[propext].HasStackdoes carry the bottom junction answerDᵢinvariantly down the left stack. The panel was right here. - Strip half WALLS (the killer) —
krelS_strip_handleFcarriessorryAx. The genuine structural wall is theletF/letFrecursion: the strip's IH demands the recursiveKrelSat a returner hole, butKrelS.letFyields a tail at an arbitrary existential intermediateBthatHasStacktyping of the LEFT stack does not pin onto theKrelSindex — there is noKrelS ⇒ HasStackbridge (the logical relation is one-way: typing ⇒ related, never the reverse), and even ifBwere pinned it need not be a returner.
So HasStack fixes the answer-projection (bottom) but the strip's recursion needs the intermediate
KrelS hole typed — which the one-way LR cannot supply. Architecture D only RELOCATES the leak (E's panel
finding "KrelS.letF existential B leaks" is correct at the build level and survives full left-stack typing).
Consequence: the only path to sorryAx-zero is typing KrelS's intermediate holes — i.e. re-indexing the
whole mutual block (Architecture A / heavy-D), which the panel scored as 4–7 sessions with a forced
frozen-statement break. Not worth it for a single tested-descent edge. The ADR-0026 scoped seam is the
verified-final answer. Durable evidence: typed-crelk-probe @ ffac1b0 (both lemmas committed, the wall
documented inline at the sorry).
Literature sweep (2026-06-25) — no indexed technique avoids the typed-relation / Iris / semantics-change cost
A 6-angle sweep of the indexed references (references/papers/) mined the SOTA + canonical handler-LR
literature for any technique that exposes the intermediate continuation answer type (or dissolves the
wrap-MISS) within our hard constraints — untyped executable oracle (#1), calculated VM (#4), Lean-not-Iris
(#3), frozen statements. Conclusion: no viable technique was missed; the literature CONFIRMS the seam.
- blaze (POPL'26, relational handler-LR SOTA) — dissolves, but its move is a syntactic side-condition
(
neutral(ls,K) ≜ ℒ(K)∩ls=∅, §4.1.2) that excludes the conflicting-handler prefix — which IS our landedNoWrapMiss. SOTA corroboration of the discipline, zero new machinery. Its model is Iris-built; closing the strip wholesale = an Iris port (off-limits). The README's "▷ eliminable via greatest fixpoint" is the paper's speculative future-work (§7 l.1417–1420), not a delivered Nat-step construction. λ-blaze is untyped and §4.4 explicitly "cannot state contextual refinement because it depends on types" — so it offers nothing to pin our existential intermediateB. - Biernacki "Handle with Care" (POPL'18) / Benton–Hur / Pitts — solves, and confirms the diagnosis: the
canonical continuation relation is hole-type-indexed from the start (Fig.7,
K⟦τ/ε⟧,C⟦τ1/ε1⤳τ2/ε2⟧), so the intermediate type is never existential. Our untypedKrelSis the deliberate deviation. The fix is "do what Biernacki does" = the declined 4–7-session reshape + frozen-statement break, plus a new invariant-#2 tension (hisEN↪Npartial-map count wants a multiset; our rows are sets). - Lexa / lexical-tunneled dispatch (Ma OOPSLA'24; Zhang POPL'19 tunneling) — dissolves by making the
MISS unrepresentable (lexical op→handler resolution removes the deep search past a non-matching handler),
the only untyped candidate. But build-check shows the cost is understated:
splitAt/dispatchis threaded through the calculated machine (CalcVM.lean), so it forces re-running the Bahr–Hutton calculation + re-verifying the CalcReify bridge and overturns ADR-0023/0024's dynamic dispatch (a frozen kernel decision → a new ADR, not a patch). Cost ≈ the declined reshape, to delete one tested edge. - Affect/Hazel (Iris protocols + Löb) — partial: dissolves by replacing the relation with a
protocol-
ΦWP (heavier than the reshape) and is unary, not contextual-equivalence (binary frontier unsolved; its own README routes binary to blaze). - AsmFX "Effect Handlers All the Way Down" (annotated simulation) — partial: type-free, but the
leave-record is a compiler-derived location annotation unavailable to the untyped
Source.step(#1), and it's forward-sim for compiler correctness, notlr_soundcontextual equivalence. - WasmFX tags / Iris-WasmFX (the "metadata through labeling" question) — no-help: a tag is only a key
into a typed declaration table; the answer type must still be populated by something typed at the
handleFpush, which the untyped oracle cannot supply = Architecture C with one indirection. Iris-WasmFX is likewise one-way (typing⇒op-sem). The only portable idea — itsx∉h1*name-matching side-condition — again just corroboratesNoWrapMiss.
Net: every route to exposing the intermediate answer type is (a) a typed relation index (the declined
reshape, and even the canonical form has an inv-#2 tension), (b) an Iris-native mechanism (off-limits), or
(c) a calculated-semantics change (Lexa, cross-cutting + an ADR reversal). The untyped KrelS deviation is
what buys invariants #1/#4; this one edge is its exact, principled price. A durable reconfirm, if ever
wanted, is a ≤1-session stackAnswer : Stack → CTy probe (predicted NO-GO at krelS_letF, the same
answer-determinism-FALSE). Sweep artifact: workflow wf_6a9f7d3f-ab1.
Narrowing probe (2026-06-25) — the edge does NOT shrink by wrap-kind (it is kind-agnostic)
A bounded build-probe tested whether the excluded edge narrows to resumptive-through-resumptive by
closing the throws-wrap sub-case (a throws-wrap aborts zero-shot, discarding the captured Kᵢ, so its
resume conjunct looked trivial). Verdict: NOT NARROWED (clean NO, nothing committed, whole-tree build
GREEN 724 jobs, axioms unchanged). The matrix collapses to wrap-kind only (the MISS conjunct is the
resume clause for the wrap hh₁ itself; the catcher's kind never appears). Throws does discard Kᵢ,
but that only relocates the obligation: the residual goal needs KrelS m (F qᵣ Aᵣ) Dᵢ eₛ Ki' K₂ᵢ while
the only available hypothesis is KrelS n C Dᵢ e Ki' K₂ᵢ at the wrap's opaque hole C — and nothing
forces C = F qᵣ (opArg ℓ op'). This is the SAME "KrelS does not expose a stack's answer type" wall,
surfacing at the wrap-hole C instead of the strip's Dᵢ. state/txn-wraps wall a fortiori (they also keep
Kᵢ). Ledger: the MISS sorry is required for EVERY wrap kind (throws included) — the obligation is
recovery of the wrapping handler's hole answer-type, which KrelS structurally hides, independent of whether
the wrap discards (throws) or keeps (state/txn) the captured prefix. So the "any pass-through" EXCLUDED
wording above is exact; the edge cannot be tightened without the same typed-relation machinery that is NO-GO.
Closure status: the seam is now confirmed from THREE independent angles — the typed-CrelK build probe
(can't recover the intermediate), the literature sweep (no indexed technique avoids the typed/Iris/semantics
cost), and the narrowing probe (can't even shrink the edge by wrap-kind). The question is settled.