Resolution (2026-06-22, ADR-0023): Source.step is now a CK machine over
Config = EvalCtx × Comp (option 2 below — the Frame/EvalCtx infra). up dispatch scans the
frame stack for the nearest catching handler; the throws (zero-shot) case discards the captured
continuation and aborts with the payload. preservation/progress/type_safety re-proven
axiom-clean over it. The state (resumption) case still uses the same scan but must KEEP the
captured continuation and thread the stored state — deferred to Q12 (graded state). Original
deliberation preserved below.
Question (historical): the substitution-based Source.step returned none (stuck) when
handle h (up ℓ op v) didn't match. The "correct" behavior for deep handlers is to
propagate up outward while the inner handler is preserved for the
resumption.
Why it matters: real algebraic-effect programs nest handlers and resume across multiple handler frames. Current Source.step can't model this.
Options:
- Keep substitution-based; accept it can't handle deep resumption. Use a different operational semantics for that.
- Migrate to a CK-machine:
Source.stepoperates onEvalCtx × Comp. TheFrameADT (§1.3) is already defined for this. Handler propagation captures the prefix-context as the resumption. - Add explicit continuation reification (CalcReify-style); Comp.up carries the captured continuation as data.
Recommended: (2) when proofs need deep handlers. The Frame / EvalCtx infrastructure is already there.
Blocked on: nothing. Just session time to migrate.
Revisit signal: writing test programs that demonstrate handler
nesting, or Phase B proofs of compile_forward_sim for multi-handler
programs.