0058 — The CrelK Canonical wall is a frozen-signature artifact; route 1 (carry the real counter) deletes it
- Status: Accepted
- Summary: The binary-LR Canonical wall (task #33) — closing
crelK_fund's ret case, hencelr_fundamental/lr_sound, needsCanonical(dense ids) for arbitraryKrelS-related observation stacks — is a frozen-signature ARTIFACT, not a fundamental difficulty.CrelKobserves configs at the DERIVED counterhandlerCount Kbecause the frozenCrelK/KrelSsignatures cannot carry the real gensym counterg(the code says so verbatim: "CrelK/KrelS signatures are frozen, so the counter is DERIVED, not a param", LR ~:1445-1447, inc5-lr-reindex).Canonical,Val.CapsBelow, andrun_bump_convergesexist solely to validate that the faked counter matches the real ids (density) and to bridge the+1shift when a pop makes them disagree. A machine-checked GC-simulation relation (CtxRel/SegRel, Lean 4.31, axiom-clean — keys handler identity by a bare reference with no counter) proves the identity-keyed target closes axiom-free for both HANDLE (append-onlyΞ,ctxRel_monoaxiom-free) and RESUME (read-disjointnessh ∉ rs, not arithmetic;resume_preservespropext-only). DECISION: route 1 — un-freezeCrelK/KrelSto carry the real counterg(or the read-set), which makes the observed config the actual config, the pop shift the actualg → g+1, and deletesCanonical/CapsBelow/run_bumpentirely (no faked counter to reconcile). A frozenCrel/Spec.leansignature change, scheduled for inc-6 (the binary LR is the contextual-equivalence / compiler-correctness path;type_safetygoes through the diagonal and is unaffected). Route 2 (prove the stacks Canonical) fights the artifact; route 1 deletes it. - Refines: 0055, 0054
- Depends-on: 0016, 0050, 0052, 0055
- See-also: 0044, 0057
Status
Accepted (2026-06-26). Operator-ratified during the Lexa / Wasm-3.0-backend design session, on the strength
of a machine-checked reference relation (below). Implementation scheduled for inc-6 (the binary LR is
the compiler-correctness deliverable, not the soundness one — type_safety/NonEscape close via the
diagonal, ADR-0056/0057, independently of this).
IMPLEMENTED (2026-06-29). Route 1 landed: CrelK/KrelS carry the real counter g quantified
internally (→ external Crel byte-identical, Spec.lean frozen-safe); Canonical/CapsBelow/run_bump
DELETED; the two wall-halves proven axiom-clean (pop_route1 counter-bridge, perform_escape_vacuous
defined-escape vacuity). Bang.LR green+sorry-free (7aa5ee1) → Bang.Compat green (89c8c08). The
ONE residual is the lr_sound adequacy reshape (the labelling-vs-closure seam, Q22 / task #72) — NOT the
Canonical wall, which this ADR closed.
Context
The wall (task #33)
Closing crelK_fund's ret case — and therefore the frozen lr_fundamental/lr_sound (contextual
equivalence) — requires Canonical K₁ K₂ (each handleF's id is dense, < handlerCount) for arbitrary
KrelS-related observation stacks. Build-confirmed (e909e73, CanonicalWallProbe): the obligation is
neither derivable (route 3 — krelS_handleF carries no n < handlerCount bound; B-occ is orthogonal to
id-density) nor removable (route 4 — the guarded crelK_ret's Canonical is load-bearing at the
handleF-pop +1 bridge via run_bump_converges). So it appeared to need a frozen-Crel change (route 1)
or a hard reachability lemma (route 2), and was deferred.
The root cause, read from the code (the artifact)
CrelK (LR ~:1442) observes the config at a derived counter:
CrelK n C ε c₁ c₂ = ∀ D K₁ K₂, KrelS n C D ε K₁ K₂ →
CoApproxC_le n (handlerCount K₁, K₁, c₁) (handlerCount K₂, K₂, c₂)and the comment is explicit: "the canonical fresh counter for a stack K is handlerCount K … CrelK/KrelS
signatures are frozen, so the counter is DERIVED, not a param." The config's real counter is the
gensym g (ADR-0055); the LR cannot carry it (frozen signature), so it fakes one from the stack structure
(handlerCount K). Consequently:
Canonical(LR ~:1164,Frame.CapsBelow (handlerCount …)) is the obligation that the faked counter equals the real ids — i.e. the stack is dense.run_bump_converges(LR ~:963) bridges the+1shift when ahandleFpop makes the faked counter (handlerCount K' + 1) and the recursion's observation (handlerCount K') disagree.Val.CapsBelow 0is the value-side half of the same density bookkeeping.
All three exist only to reconcile a counter the frozen signature forced the LR to fabricate. The count
is otherwise never external — it is always written handlerCount K₁ adjacent to K₁, so it is always
reconstructible from the structure; handlerCount is NOT load-bearing for the step index (n, separate) or
the crelK_ret induction (on K₁'s structure).
The reference: a machine-checked identity-keyed relation
The Lexa-comparison / Wasm-3.0-backend design (2026-06-26) produced a machine-checked simulation
relation for a GC-frame abstract machine (Lean 4.31, standalone, axiom-clean — grep-confirmed zero sorry,
no sorryAx). It keys a handler instance by a bare GC reference, not a counter:
| hdl : H r = some (Node.handler parent op henv) → Ξ L = some r → … → CtxRel … (some r)and proves the structural lemmas that are the exact analogues of our obligations:
| GC-machine lemma | axioms | our artifact it dissolves |
|---|---|---|
ctxRel_mono (relation survives Ξ extension) | none | the append-only property (no offset reinterpretation) |
handle_preserves (HANDLE = append Ξ[L↦h]) | propext | the "did the handler land where the counter says" step |
resume_preserves (the delim.parent := cur splice) | propext | the pop/resume bridge — via read-disjointness h ∉ rs, no arithmetic |
The decisive refinement (build-corrected, not guessed): the splice's side-condition is read-disjointness
(h ∉ rs, the refs the relation dereferences as nodes), not reachability (h is reachable — it is the
segment's bottom target). There is no next^m, no segment-length counting anywhere. The identity-keyed
relation is fully in the easy, append-only, arithmetic-free regime.
Decision
Route 1: un-freeze CrelK/KrelS to carry the real gensym counter g (minimal encoding) or the
read-set (structural encoding, matching the GC-machine reference). The observed config becomes the
actual config ((g, K, c), not (handlerCount K, K, c)); the pop shift becomes the actual g → g+1;
and Canonical, Val.CapsBelow, and run_bump_converges all delete — there is no faked counter to
reconcile, so there is nothing for them to validate. The guarded crelK_ret's hcan/hvcf premises
vanish and its ret case closes.
The route-1 re-key needs one invariant — the freshly-minted id is disjoint from the live stack (the real-
g analogue of the GC-machine's h ∉ rs). We already have it: WellCounted / splitAtId_fresh
(ADR-0055). So the read-disjointness the GC-machine assumes and our freshness lemma are the same fact in two
encodings. NOTE: the sharper re-keying criterion (from the machine-checked invariant lemma) is carry the
read-set as a NoDup list — the density obligations become nodup_split-shaped membership facts
(h ∉ prefix), not counts; so route 1 is mechanical iff handlerCount is reconstructible as the length of a
NoDup read-set the relation already carries (it is — handlerCount K is written adjacent to K).
EPISTEMIC STATUS (build-confirmable, NOT yet proven). The CtxRel/SegRel reference relation is
machine-checked axiom-clean for a clean-slate machine; that our crelK_ret re-keys onto it — that
handlerCount is load-bearing for nothing the read-set can't reconstruct (in particular not the step index
or the crelK_ret induction) — is a code-read conclusion, not a #print axioms result. The code
documents the artifact (the "DERIVED, not a param" comment is dispositive about why the counter is faked),
and that is the right basis for the decision — but it is a different epistemic status than the
machine-checked target. The deletion COMPILING is the proof. So: here is the artifact we believe
deletes, pending the re-key actually compiling (inc-6). The decision is sound; the verification is the
implementation.
This clause is OPEN — tracked by task #33 (route-1 re-key) → inc-6 (task #15). It resolves to PROVEN only when the re-key compiles. Do not cite route 1 as "verified" until then — this ADR is the decision, not the proof; the proof is a green build, and the hedge in this paragraph is on the survey/prose rung until then. (Full structural form: the re-key landing in inc-6 with
Canonicaldeleted and the tree green.)
Consequences
- Frozen-statement change.
CrelK/KrelS(theCreltargetlr_sound/lr_fundamentalconsume, inSpec.lean) gain the real counter / read-set. This is a frozen acceptance-criterion change → this ADR +STATEMENT_CHANGE_OKat implementation. - Deletes:
Canonical+Canonical.capsBelow(LR), theCapsBelowdensity premises oncrelK_ret/crelK_fund,run_bump_convergesand itsrun_renameplumbing where it served only the fake counter, and thehcan/hvcfarguments threaded through the Compat consumers. Net LR/Compat LOC is expected negative. - Banked work carries over. inc-5 Units 1+2 (the
splitAtIddecomp + the KrelS layer,285338a) are stack-structural and identity-keyed already; verify they survive the counter re-key (expected: yes — they never consumedhandlerCountexcept as the adjacent observation slot). - Decided on the merits, not deferred. Route 2 (prove
lr_sound's instantiation stacks Canonical — hard,krelS_reflneeds its own density story) establishes density for the fake counter; route 1 removes the fake counter. The machine-checked relation is the argument that route 1's target is clean. - Scope boundary. This is the binary LR (contextual equivalence, the inc-6 compiler-correctness
path).
type_safety/soundness goes through the diagonal (NonEscape, ADR-0056/0057) and is unaffected — this ADR does not touch it. - Forward link. The same GC-machine reference is the codegen design for inc-6's CalcVM→target lowering (handler = stable reference, raise/resume = one swap). A separate ADR will revise ADR-0016's target (Wasm 3.0 + grade-directed pluggable backend) — this ADR is only the relation decision. That revision is conditional on a check that the grades track resumption multiplicity (0×/1×-tail/1×-arbitrary), not just value/computation multiplicity (ADR-0025); if they do not, the abort/tail/general routing is a goal, not a result.
Alternatives considered (rejected)
- Route 2 — a Canonical-reachability lemma. Prove the stacks
lr_soundactually instantiatesCrelKat are always Canonical. Fights the artifact (validates the fake counter); hard, sincekrelS_refl(Spec ~:192) instantiates at the observation context via its own density-free path. Strictly harder than route 1 for no benefit. - Routes 3 + 4 — derive
CanonicalfromKrelS, or drop the guard as over-strong. Both build-refuted (e909e73):KrelScarries no density bound, and the guard is load-bearing at the pop bridge. - Keep
handlerCount(status quo). The wall stands;lr_soundcannot close. Rejected.