feat(L10): phase 2 — echo residue as a linear undo-capability#41
Merged
Conversation
hyperpolymath
marked this pull request as ready for review
June 14, 2026 01:36
Layer 10's reversal residue becomes a first-class linear value. The
checker's residue stack now carries `Linear<Echo<T>>` (was a bare
`Echo<T>`): `push_echo_residue` wraps the residue in `Type::Linear`, so
the consumed-once discipline is explicit in the carried type and the
single linear use is discharged by the matching `take_echo_residue` pop
in a later `reverse`.
Discipline: affine capability, linear consumption. A given reversal log
is consumed at most once — a double `reverse` of one residue is rejected
(the linear use, structural in the stack) — while a `reversible` block
need not be paired with a `reverse` at all (an un-reversed residue is NOT
an error; reversibility is a capability, usually unused). The opposite,
strict must-reverse linearity, is deliberately rejected as semantically
wrong and poor agent ergonomics; three new tests lock the affine drop in
so it cannot be silently tightened.
Formal model: proofs/idris2/EchoResidueLinear.idr (%default total, zero
believe_me, idris2 --check clean) — reverseLinear consumes (1 e : Echo f
y); reverseLinearCorrect (recovered input maps back to y, intrinsic);
ResidueCell Holding/Spent carries the residue as agent state between
handlers; takeForReverse (Spent -> Nothing); holdingReverses /
spentDoesNotReverse; cellMode bridges back to the phase-1 mode.
Still open (own rung): cross-handler NAMED residues need residue-binding
grammar syntax (let undo = reversible {...}; reverse undo); the formal
model (ResidueCell) is in place, only Harvard-guarded surface syntax is
missing.
Tests: 3 new typechecker tests; 883 oo7-core lib tests pass. fmt clean;
clippy (CI-equivalent) -D warnings exit 0. Spec (TYPE-SYSTEM-SPEC §11b.4,
OPERATIONAL-SEMANTICS §11.4), CHANGELOG, docs/echo-residue-integration.adoc
and 6a2 STATE updated in lockstep.
https://claude.ai/code/session_018CaSgNjNURC7ocsyjYh9We
hyperpolymath
force-pushed
the
claude/echo-residue-phase2-linear
branch
from
June 14, 2026 01:36
09d8485 to
9d7bbca
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Phase 2 of the Layer-10 echo-residue work (phase 1 = #34). Makes the
reversal residue a first-class linear value. The checker's residue
stack now carries
Linear<Echo<T>>(was a bareEcho<T>):push_echo_residuewraps the residue in
Type::Linear, so the consumed-once discipline isexplicit in the carried type, and the single linear use is discharged by
the matching
take_echo_residuepop in a laterreverse.The only non-comment code change is that one-line wrap; the rest is the
Idris proof, tests, spec, and docs.
The design decision (worth a look)
A reversal log is an affine capability consumed linearly:
residue exactly once (
reverseLinear's(1 e : Echo f y)). Replaying thesame log twice is rejected: the residue has already been popped, so the
second
reverseisReverseWithoutResidue.reversibleblock need not be paired with areverse. An undo capability that is never exercised is dropped at thebody boundary, not flagged. Reversibility is a capability, usually unused.
The opposite — strict "must-reverse" linearity, where an un-reversed residue
is a
LinearNotConsumederror — is deliberately rejected: it conflateshaving an inverse with applying it, and is poor agent ergonomics. Three
new tests lock the affine drop in so a future change cannot silently tighten
it.
Formal model
proofs/idris2/EchoResidueLinear.idr(%default total, zerobelieve_me,idris2 --checkclean):reverseLinearconsumes(1 e : Echo f y)— Idris2's quantity1isthe "consumed exactly once" proof, mirroring 007's planned
Linear<Echo<T>>;reverseLinearCorrect— recovered input maps back toy(intrinsic);ResidueCell(Holding/Spent) — the residue carried as agent statebetween handler invocations;
takeForReverse— a later handler consumes the cell linearly (Spent → Nothing);holdingReverses/spentDoesNotReverse— cross-handler reversal succeedsiff a residue was retained;
cellMode— bridges a cell back to the phase-1Reversibilitymode.Verified locally
idris2 --check EchoResidueLinear.idr→ exit 0 (and dependencyEchoResidue.idr)cargo test -p oo7-core→ 883 lib tests pass (incl. 3 new L10 phase-2 tests), 0 failcargo fmt -- --check→ 0 diffscargo clippy -- -D warnings(CI-equivalent, no--all-targets) → exit 0.machine_readable/6a2/→ 0 errorsStill open (its own rung)
Cross-handler named residues need residue-binding surface syntax
(
let undo = reversible {…}… laterreverse undo). The formal model(
ResidueCell) is already in place; only the grammar change is missing, andbecause the grammar is Harvard-guarded that is kept as a separate, carefully-
scoped rung. Until then cross-handler reversal is conservatively rejected by
per-body isolation (sound, if incomplete).
Docs updated in lockstep
spec/TYPE-SYSTEM-SPEC.adoc§11b.4,spec/OPERATIONAL-SEMANTICS.adoc§11.4(planned → landed),
CHANGELOG.md,docs/echo-residue-integration.adoc(phase-2 section + design-decision subsection + still-open rung), and 6a2
STATE.a2ml.https://claude.ai/code/session_018CaSgNjNURC7ocsyjYh9We
Generated by Claude Code