give a construct its after-crossing face, and let constructs compose

§6 records 62 persist-after-mutate sites, 10 auth-per-route, and
index-after-append that failed at 9 of 9 — every one an obligation at a
crossing that decayed into "remember to do this afterwards." An obligation a
human must remember is not an obligation, and the 9-of-9 figure is what that
costs.

    @decorator("injects_at_exit", "persist_now")
    fn durable() {}

The body moves into a static helper and the visible fn becomes a wrapper, so
EARLY RETURNS pass through the exit injection. Emitting it only before the
fall-through return would have silently missed every early return — the exact
failure class this seam exists to remove. Fns with no exit construct emit
byte-identically to before.

Three independent constructs now compose on one fn, none known to the compiler:

    el_val_t mutate(el_val_t k) {
      { el_val_t __g = my_auth(EL_STR("mutate"), EL_STR("authenticate")); if (__g) return __g; }
      engram_boundary_beat(EL_STR("mutate"), EL_STR("manager"));
      el_val_t __r = __el_body_mutate(k);
      persist_now(EL_STR("mutate"), EL_STR("durable"), __r);
      return __r;
    }

Guard, then entry, then body, then exit. §5.2 asked whether `hold` is one
construct or two; the implementation answers one construct with two faces,
selected by declared kind rather than by two mechanisms.

Verified: existing output byte-identical, compiler self-hosts byte-identically,
early returns pass through the exit, ordering holds under composition. 98/98
native compiler tests pass.
This commit is contained in:
bigmerge
2026-08-17 07:56:28 -05:00
parent 60737b0305
commit 4f7568b07f
2 changed files with 182 additions and 46 deletions
+33
View File
@@ -842,3 +842,36 @@ test "undeclared-guard-emits-nothing" {
let out: String = compile_capture(src)
assert !str_contains(out, "if (__g)"), "an undeclared construct guards nothing"
}
// Declared constructs: exit injection and composition
test "declared-exit-wraps-body-so-early-returns-pass-through" {
let src: String = "@decorator(\"injects_at_exit\", \"persist_now\")\nfn durable() {}\n@durable\nfn mutate(k: String) -> Int { if str_eq(k, \"bad\") { return 0 } return 1 }"
let out: String = compile_capture(src)
assert str_contains(out, "static el_val_t __el_body_mutate"), "body moves into a helper"
assert str_contains(out, "persist_now(EL_STR(\"mutate\")"), "exit injection runs"
assert str_contains(out, "return __r;"), "the wrapper returns the body's result"
}
test "declared-exit-receives-the-result" {
let src: String = "@decorator(\"injects_at_exit\", \"persist_now\")\nfn durable() {}\n@durable\nfn f() -> Int { return 1 }"
let out: String = compile_capture(src)
assert str_contains(out, "__r);"), "the exit target is handed what the fn returned"
}
test "no-exit-construct-emits-no-wrapper" {
let src: String = "@manager\nfn f() -> Int { return 1 }"
let out: String = compile_capture(src)
assert !str_contains(out, "__el_body_"), "fns without an exit construct are unwrapped, byte for byte as before"
}
test "constructs-compose-guard-entry-exit" {
let src: String = "@decorator(\"guards_at_entry\", \"my_auth\")\nfn authenticate() {}\n@decorator(\"injects_at_exit\", \"persist_now\")\nfn durable() {}\n@authenticate\n@durable\n@manager\nfn op() -> Int { return 1 }"
let out: String = compile_capture(src)
let g: Int = str_index_of(out, "my_auth(")
let b: Int = str_index_of(out, "engram_boundary_beat(EL_STR(\"op\")")
let x: Int = str_index_of(out, "persist_now(")
assert g < b, "guard before entry injection"
assert b < x, "entry injection before exit injection"
assert x >= 0, "three independent constructs compose on one fn"
}