Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .machine_readable/6a2/STATE.a2ml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@

@state(version="2.0"):
phase: "implementation"
next_action: "Layer-10 cross-handler named residues: residue-binding grammar syntax (let undo = reversible {…}; reverse undo) carried through agent state — Harvard-guarded grammar change, own rung; then continue parser gap fill (types, imports, locales, choreographies)"
last_action: "Phase-2 echo-residue landed: residue is now Linear<Echo<T>> (affine capability, linear consumption — double-reverse rejected, un-reversed residue not an error); Idris2 EchoResidueLinear.idr (reverseLinear (1 e), ResidueCell Holding/Spent, idris2 --check clean, zero believe_me); 3 new typechecker tests (883 oo7-core passing); spec §11b.4/§11.4 + CHANGELOG + integration doc updated in lockstep. estate-standardization-20260607 reconciled into main (PR #40 merged). Prior: Layer 10 phase-1 (PR #34), CI gates greened (PR #38), 6a2/ecosystem refresh (PR #39)"
updated: 2026-06-14T02:00:00Z
next_action: "Layer-10 rung 3b: cross-handler residues through agent state — residue cell in agent state + evaluator runtime Holding/Spent (ResidueCell, takeForReverse:Maybe) + EchoResidueLinear bridge lemma; then continue parser gap fill (types, imports, locales, choreographies)"
last_action: "Phase-3 rung-3a landed: NAMED residues within a body — new syntax `reversible as <name> {…}` / `reverse <name>` (anonymous forms unchanged). Additive AST ReversibleAs/ReverseNamed; grammar.pest+grammar.ebnf; typechecker named_residues map (Holding/Spent, static mirror of ResidueCell) with per-function/handler isolation; eval/codegen/formatter/dual_ast/metainterpreter/CFG/oracle threaded. Affine/linear discipline: double-reverse rejected, un-reversed ok, no cross-body leak. 2 parser + 5 typechecker tests (890 oo7-core passing; fmt clean, clippy -D warnings 0). Spec §11b.5 + CHANGELOG + integration doc in lockstep. Prior: phase-2 Linear<Echo<T>> (PR #41 merged), phase-1 (PR #34), CI gates (PR #38), 6a2 (PR #39), estate reconcile (PR #40)"
updated: 2026-06-15T17:00:00Z

@blockers:
- id: proof-debt
Expand Down
2 changes: 2 additions & 0 deletions .machine_readable/session-log.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,5 @@


[2026-06-14 01:25:37] Session ended (continuation): item-2 estate-standardization reconcile MERGED (PR #40) → main is one reconciled line. Then resumed ORIGINAL WORK = Layer-10 PHASE 2 (residue as a linear undo-capability). (a) Idris2: proofs/idris2/EchoResidueLinear.idr (NEW, %default total, zero believe_me, idris2 --check clean) — reverseLinear consumes (1 e : Echo f y) (Idris2 quantity 1 = "consumed exactly once" proof, mirroring 007's planned Linear<Echo<T>>); reverseLinearCorrect (recovered input maps back to y, intrinsic via the dependent pair); ResidueCell Holding/Spent = the residue carried as agent STATE between handlers; takeForReverse (later handler consumes the cell; Spent→Nothing); holdingReverses/spentDoesNotReverse (cross-handler reversal succeeds iff a residue was retained); cellMode bridges a cell back to the phase-1 Reversibility mode. (b) Rust typechecker.rs: residue stack now carries Linear<Echo<T>> (push_echo_residue wraps Type::Echo in Type::Linear) — the consumed-once discipline is explicit in the carried type; the single linear use is the take_echo_residue pop in a later reverse. +3 typechecker_tests (l10_phase2_residue_type_is_linear_echo / _double_reverse_of_single_residue_is_error / _retained_residue_is_not_an_error) → 883 oo7-core lib tests passing. CI gates verified LOCALLY: cargo check --offline 0, full oo7-core test suite 922 ok 0 fail, fmt --check 0, clippy (CI-equivalent, no --all-targets) -D warnings exit 0. (c) DESIGN DECISION flagged to user (a plus/interesting): the residue is an AFFINE capability consumed LINEARLY — replaying one log twice is rejected (linear use; structural in the stack), but a reversible block need NOT be paired with a reverse (un-reversed residue is NOT an error; reversibility is a capability, usually unused). The opposite (strict must-reverse / LinearNotConsumed) was deliberately REJECTED as semantically wrong + poor agent ergonomics; the 3 tests lock the affine-drop in so it can't be silently tightened. (d) Docs in lockstep: TYPE-SYSTEM-SPEC §11b.4 + OPERATIONAL-SEMANTICS §11.4 (planned→landed), CHANGELOG phase-2 bullet, docs/echo-residue-integration.adoc (phase-2 section + design-decision subsection + "still open" cross-handler rung), 6a2 STATE.a2ml last/next_action + cleared estate-standardization-unmerged blocker. (e) NOTE — canonical-proof-suite MANIFEST.a2ml NOT touched: phase-1 EchoResidue.idr is not a manifest entry either, so EchoResidueLinear.idr stays alongside it (checked by idris2 --check, not the curated S/E/M suite); the proof-suite workflow ignores unlisted .idr files (no CI risk). STILL OPEN (next rung): cross-handler NAMED residues need residue-binding grammar syntax (let undo = reversible {…}; reverse undo) — Harvard-guarded grammar change, kept as its own rung; formal model (ResidueCell) already in place, only surface syntax missing. Phase-2 work pushed to branch claude/echo-residue-phase2-linear → draft PR. Billing blocker may still gate CI (account-owner action).

[2026-06-15 17:39:22] Session continued: Layer-10 PHASE 3 RUNG 3a landed (named residues within a body) on branch claude/echo-residue-phase3-named off main. User chose syntax `reversible as undo {…}` / `reverse undo` (the `as`-binder, agent-ergonomic) and scope "static core first" (within-body, fully static; cross-handler 3b deferred). (a) Grammar: grammar.pest + spec/grammar.ebnf — reversible_block gains optional ("as" ~ ident); new reverse_named = "reverse" ~ ident; Harvard-safe (control rules ref the shared ident token; Harvard guard PASS). (b) AST: ADDITIVE variants ReversibleAs{binding,body} + ReverseNamed{target} — existing Reversible/Irreversible/Reverse untouched, so the 9 exhaustive ControlStmt matches were compiler-enumerated + mirrored (codegen_cranelift/elixir/native, dual_ast, eval, formatter, metainterpreter, semantic_analyser/control_flow, typechecker check_stmt) + oracle check.rs + the two combined typechecker passes (effects, collect_linear_lets). (c) Typechecker: per-body named_residues: HashMap<String,NamedResidueState{Holding(Type)|Spent}> — the static mirror of ResidueCell; bind_named_residue (reversible as → Holding(Linear<Echo<T>>)); take_named_residue (reverse → Holding→Spent, else Err); per-function + per-handler mem::take isolation (no cross-body leak). Affine/linear: double reverse <name> rejected (Spent), un-reversed bound name NOT an error, reverse of unknown/spent name = L10_REVERSE_WITHOUT_RESIDUE. (d) Parser: build_reversible_block detects optional ident → ReversibleAs vs Reversible; build_reverse_named. (e) Tests: 2 parser (reversible_as_binds_named_residue, reverse_named_parses) + 5 typechecker (named-reverse-ok, reverse-unknown-errs, double-reverse-errs, unreversed-ok-affine, no-cross-function-leak) → 890 oo7-core lib tests pass; full workspace cargo test 0 failures; cargo fmt --check clean; cargo clippy --offline -D warnings exit 0 (CI-equivalent). (f) Docs in lockstep: TYPE-SYSTEM-SPEC §11b.5 (new), docs/echo-residue-integration.adoc (phase-3 section + rung-3b still-open), CHANGELOG, 6a2 STATE. NO new Idris needed — ResidueCell/reverseLinear already model rung 3a. STILL OPEN rung 3b: cross-handler residues via agent state — irreducibly partly RUNTIME (no static knowledge whether the earlier handler fired; Idris takeForReverse returns Maybe), so it adds a residue cell in agent state + evaluator Holding/Spent + bridge lemma. Pushed to claude/echo-residue-phase3-named → draft PR. Billing may still gate CI (account-owner action); verified locally.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ All notable changes to this project will be documented in this file.
### Added
- **Layer 10 — Reversibility (Echo residue): echo-types integrated into the type system.** `reversible`/`irreversible`/`reverse` are no longer checked identically: `Type::Echo<T>` residues are tracked per body (`reversible` retains one, `irreversible` discards it, `reverse` consumes one), and a `reverse` with no residue is `ReverseWithoutResidue` — enforcing OPERATIONAL-SEMANTICS §11.3, previously unenforced. Grounded in echo-types' keystone `A ≃ Σ B (Echo f)` and mechanised in `proofs/idris2/EchoResidue.idr` (`encodeDecode`, `reverseAfterIrreversibleIllTyped`, `collapseHasNoSection`; `%default total`, zero `believe_me`). Surfaced to agents via `agent_api` code `L10_REVERSE_WITHOUT_RESIDUE` (+`mark_reversible`/`retain_echo` remediations). 4 new typechecker tests. Spec: TYPE-SYSTEM-SPEC §"Layer 10", OPERATIONAL-SEMANTICS §11.4; design note `docs/echo-residue-integration.adoc`.
- **Layer 10 phase 2 — the residue is a linear undo-capability.** The checker's residue stack now carries `Linear<Echo<T>>` (was a bare `Echo<T>`), making the consumed-once discipline explicit in the type. Discipline: *affine capability, linear consumption* — a given reversal log is consumed at most once (a double `reverse` of one residue is rejected) yet a `reversible` block need not be paired with a `reverse` (an un-reversed residue is **not** an error; reversibility is a capability, usually unused). Mechanised in `proofs/idris2/EchoResidueLinear.idr` (`reverseLinear` consumes `(1 e : Echo f y)`; `ResidueCell` Holding/Spent = the residue as agent state; `holdingReverses`/`spentDoesNotReverse`; `%default total`, zero `believe_me`, `idris2 --check` clean). 3 new typechecker tests (883 `oo7-core` lib tests passing). Remaining rung: cross-handler *named* residues (residue-binding grammar syntax, Harvard-guarded — kept separate). Spec/docs updated in lockstep.
- **Layer 10 phase 3 (rung 3a) — named residues within a body.** New surface syntax `reversible as <name> { … }` binds the echo residue to a name; `reverse <name>` replays it (anonymous `reversible {…}`/`reverse {…}` unchanged). The named residue is tracked per body as a `Holding(Linear<Echo<T>>)` cell that `reverse` transitions to `Spent` — the static mirror of `ResidueCell` (Holding/Spent) in `EchoResidueLinear.idr`. Same affine/linear discipline: double `reverse <name>` is rejected (cell already `Spent`); a never-replayed binding is **not** an error; named residues are scoped per body (no cross-body leak). Additive AST variants `ReversibleAs`/`ReverseNamed` (existing variants untouched); grammar (`grammar.pest` + `spec/grammar.ebnf`), parser, typechecker (`named_residues` map + per-function/handler isolation), and the eval/codegen/formatter/dual-ast/metainterpreter/CFG/oracle pipeline all threaded. 2 parser + 5 typechecker tests (890 `oo7-core` lib tests passing; fmt clean, clippy `-D warnings` exit 0). Remaining rung 3b: cross-handler residues through agent state (irreducibly partly runtime — `takeForReverse : Maybe`). Spec: TYPE-SYSTEM-SPEC §11b.5; docs `docs/echo-residue-integration.adoc`.
- **752 tests** (up from 207 at 0.5.0). CRG-C achieved 2026-04-04 for `oo7-core`.
- **31 multi-language backends** via `mk2_bridge::create_backend_registry()`. Real dispatch to `elixir`, `idris2`, `gleam`, `rescript`, `nickel`, `guile`, `psql`, etc. Tier-5 coprocessor backends (CUDA/Vulkan/Metal/OpenCL/FPGA/TPU/DSP) do phase-1 device discovery with documented "kernel launch is future work" status.
- **Metainterpreter** (`metainterpreter.rs`, ~3,075 LOC): reify/reflect/step/replay, four modes, 40 inline tests, 18 benches.
Expand Down
13 changes: 13 additions & 0 deletions crates/oo7-core/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,19 @@ pub enum ControlStmt {
Irreversible(Vec<ControlStmt>),
/// `reverse { ... }` — executes the reverse of a previous reversible block
Reverse(Vec<ControlStmt>),
/// `reversible as undo { ... }` — a reversible block that BINDS its echo
/// residue to a name (`undo`), so a later `reverse undo` can replay it.
/// L10 phase 3 (rung 3a): the named residue is a `Linear<Echo<T>>` tracked
/// per-body; it is an affine capability consumed linearly (replay at most
/// once; never replaying is not an error).
ReversibleAs {
binding: String,
body: Vec<ControlStmt>,
},
/// `reverse undo` — replays the named echo residue `undo` bound by an
/// earlier `reversible as undo { ... }`. Consumes the residue: a second
/// `reverse undo` is the L10 reverse-without-residue error.
ReverseNamed { target: String },
/// `enter discourse name { ... }` — execute within a discourse's interpretation rules.
/// Branch strategy and evidence weights change within the block.
EnterDiscourse {
Expand Down
10 changes: 10 additions & 0 deletions crates/oo7-core/src/codegen_cranelift.rs
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,16 @@ pub fn gen_body(
ControlStmt::Reverse(body) => {
last = gen_body(body, builder, var_map, next_var, ptr_type);
}
ControlStmt::ReversibleAs { body, .. } => {
// A named reversible block compiles its body directly; the
// residue binding is a type-level (L10) concern.
last = gen_body(body, builder, var_map, next_var, ptr_type);
}
ControlStmt::ReverseNamed { .. } => {
// `reverse <name>` replays a named residue — a runtime concern
// (rung 3b); nothing to emit at rung 3a.
last = builder.ins().iconst(cranelift_codegen::ir::types::I64, 0);
}
ControlStmt::EnterDiscourse { body, .. } => {
// Discourse is a runtime semantic concern — compile the body.
last = gen_body(body, builder, var_map, next_var, ptr_type);
Expand Down
12 changes: 12 additions & 0 deletions crates/oo7-core/src/codegen_elixir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -819,6 +819,18 @@ pub fn gen_control_stmt(stmt: &ControlStmt, ctx: &GenContext, indent: usize) ->
out.push_str(&gen_stmts(body, ctx, indent));
out
}
ControlStmt::ReversibleAs { binding, body } => {
let mut out = format!("{}# reversible as {}\n{}try do\n", ind, binding, ind);
out.push_str(&gen_stmts(body, ctx, indent + 1));
out.push_str(&format!(
"\n{}rescue\n{} e -> {{:error, e}}\n{}end",
ind, ind, ind
));
out
}
ControlStmt::ReverseNamed { target } => {
format!("{}# reverse {}", ind, target)
}
ControlStmt::EnterDiscourse { discourse, body } => {
// Discourse context — emit a comment and execute the body.
// Runtime discourse semantics are a future extension.
Expand Down
10 changes: 10 additions & 0 deletions crates/oo7-core/src/codegen_native.rs
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,16 @@ fn gen_stmt_zig(stmt: &ControlStmt, depth: usize) -> String {
}
out
}
ControlStmt::ReversibleAs { binding, body } => {
let mut out = format!("// reversible as {}\n", binding);
for s in body {
out.push_str(&format!("{}{};\n", indent, gen_stmt_zig(s, depth)));
}
out
}
ControlStmt::ReverseNamed { target } => {
format!("// reverse {}\n", target)
}
ControlStmt::EnterDiscourse { discourse, body } => {
let mut out = format!("// enter discourse {}\n", discourse);
for s in body {
Expand Down
6 changes: 5 additions & 1 deletion crates/oo7-core/src/dual_ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -978,12 +978,16 @@ fn lower_control_stmt(
ControlStmt::Continue => control.alloc(ControlNode::Continue),
ControlStmt::Reversible(stmts)
| ControlStmt::Irreversible(stmts)
| ControlStmt::Reverse(stmts) => {
| ControlStmt::Reverse(stmts)
| ControlStmt::ReversibleAs { body: stmts, .. } => {
for s in stmts {
lower_control_stmt(s, control, data);
}
control.alloc(ControlNode::Var("reversible-block".to_string()))
}
ControlStmt::ReverseNamed { .. } => {
control.alloc(ControlNode::Var("reverse-named".to_string()))
}
ControlStmt::EnterDiscourse { discourse, body } => {
let body_ids: Vec<ControlNodeId> = body
.iter()
Expand Down
8 changes: 7 additions & 1 deletion crates/oo7-core/src/eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1926,12 +1926,18 @@ impl Evaluator {
// handled by the type checker.
ControlStmt::Reversible(body)
| ControlStmt::Irreversible(body)
| ControlStmt::Reverse(body) => {
| ControlStmt::Reverse(body)
| ControlStmt::ReversibleAs { body, .. } => {
env.push_scope();
let r = self.eval_stmts(body, env);
env.pop_scope();
r
}
ControlStmt::ReverseNamed { .. } => {
// Rung 3a: `reverse <name>` is statically checked; runtime
// replay of a named residue is the cross-handler rung (3b).
RtValue::Unit
}

ControlStmt::EnterDiscourse { discourse, body } => {
// Enter a discourse context — swap the branch strategy to the
Expand Down
9 changes: 9 additions & 0 deletions crates/oo7-core/src/formatter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -771,6 +771,15 @@ fn format_stmt(stmt: &ControlStmt, depth: usize) -> String {
out.push_str(&format!("{}}}", indent));
out
}
ControlStmt::ReversibleAs { binding, body } => {
let mut out = format!("reversible as {} {{\n", binding);
for s in body {
out.push_str(&format!("{}{}\n", inner, format_stmt(s, depth + 1)));
}
out.push_str(&format!("{}}}", indent));
out
}
ControlStmt::ReverseNamed { target } => format!("reverse {}", target),
ControlStmt::EnterDiscourse { discourse, body } => {
let mut out = format!("enter discourse {} {{\n", discourse);
for s in body {
Expand Down
8 changes: 7 additions & 1 deletion crates/oo7-core/src/grammar.pest
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ control_stmt = {
| return_stmt
| reversible_block
| irreversible_block
| reverse_named
| reverse_block
| enter_discourse_stmt
| control_expr ~ ";"?
Expand Down Expand Up @@ -645,10 +646,15 @@ enum_variant = { upper_ident ~ ("(" ~ typed_fields ~ ")")? }
// Reversibility Blocks
// ============================================================

reversible_block = { "reversible" ~ "{" ~ control_stmt* ~ "}" }
// `reversible { ... }` is anonymous; `reversible as <name> { ... }` BINDS the
// echo residue to <name> so a later `reverse <name>` can replay it (L10 phase 3).
reversible_block = { "reversible" ~ ("as" ~ ident)? ~ "{" ~ control_stmt* ~ "}" }

reverse_block = { "reverse" ~ "{" ~ control_stmt* ~ "}" }

// `reverse <name>` replays the named residue bound by `reversible as <name>`.
reverse_named = { "reverse" ~ ident }

irreversible_block = { "irreversible" ~ "{" ~ control_stmt* ~ "}" }

// ============================================================
Expand Down
14 changes: 14 additions & 0 deletions crates/oo7-core/src/metainterpreter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -782,6 +782,20 @@ pub fn reify_control_stmt(stmt: &ControlStmt) -> RtValue {
vec![("body".to_string(), RtValue::List(stmts))],
)
}
ControlStmt::ReversibleAs { binding, body } => {
let stmts: Vec<RtValue> = body.iter().map(reify_control_stmt).collect();
meta_record(
"ControlStmt::ReversibleAs",
vec![
("binding".to_string(), RtValue::String(binding.clone())),
("body".to_string(), RtValue::List(stmts)),
],
)
}
ControlStmt::ReverseNamed { target } => meta_record(
"ControlStmt::ReverseNamed",
vec![("target".to_string(), RtValue::String(target.clone()))],
),
ControlStmt::EnterDiscourse { discourse, body } => {
let stmts: Vec<RtValue> = body.iter().map(reify_control_stmt).collect();
meta_record(
Expand Down
Loading
Loading