From 35b07bade29fcd93a663a2f538b43c31f07e28cb Mon Sep 17 00:00:00 2001 From: bigmerge Date: Mon, 17 Aug 2026 08:37:47 -0500 Subject: [PATCH 1/4] EXPERIMENT: resolve the crossing at execution, not at emission MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit HYPOTHESIS (Will's): a compiler whose one compiled mechanism is extending the LANGUAGE — not the compiler — can compose without recompilation. ISHIKAWA — why does a construct require a recompile today? method codegen inlines the target call into the body machine the binary has no table to consult material the declaration lives in source, read at compile time measurement nothing observes what applied at runtime root cause the crossing is resolved at EMISSION, not at EXECUTION CHANGE: codegen emits one unconditional indirection per fn. Which constructs apply is read from a table that can be written AFTER the binary exists; targets resolve through dlsym against the running image. PREDICTIONS AND RESULTS P1 a construct declared after the build applies TRUE P2 an unlinked target is skipped, not fatal TRUE P3 emitting on every fn is measurably slower FALSE — 0.37s -> 0.36s with 267 indirections and no bindings. Free unused. P4 the compiler still self-hosts TRUE (see note) DEMONSTRATED: an El program with NO decorator in its source, already compiled and linked, picked up a construct declared afterwards: $ /tmp/seamrun -> 7 $ echo 'work audited entry audit_entry' > constructs.txt $ EL_CONSTRUCTS=constructs.txt /tmp/seamrun AUDIT: work applied by audited 7 P4 note: my first fixpoint test was wrong, not the code. I compared gen1 to gen2, which must differ whenever codegen's output changes. gen2 == gen3, 267 seam sites, stable. MEASURED COST, and the root cause was not where I looked 0 bindings 0.36s vs 0.37s baseline free 2 bindings, dlsym per call 2.45s 6.6x 2 bindings, resolved once 0.69s 3.5x recovered The table scan was never the cost. dlsym walks the dynamic symbol table on every call. Resolve once and cache — which is the smallest form of what salience does for memory: what is hot stays resolved. The 0.69s residual is audit_entry's own printf on two of the compiler's hottest functions, not seam overhead. CONSEQUENCE: the five compile-time declaration kinds on iteration-1 are a compile-time specialisation of something that resolves at runtime. They are not wrong, but they are not the mechanism — the mechanism is one indirection, and a kind is data. --- lang/el-compiler/src/codegen.el | 4 ++ lang/runtime/el_runtime.c | 75 +++++++++++++++++++++++++++++++++ lang/runtime/el_runtime.h | 3 +- 3 files changed, 81 insertions(+), 1 deletion(-) diff --git a/lang/el-compiler/src/codegen.el b/lang/el-compiler/src/codegen.el index 68bf3db..2eac94a 100644 --- a/lang/el-compiler/src/codegen.el +++ b/lang/el-compiler/src/codegen.el @@ -3205,6 +3205,10 @@ fn fn_has_decorator(stmt: Map, name: String) -> Bool { // applies both); injection is topmost-wins, matching the VBD role convention, // because a role is singular and a refusal is not. fn cg_entry_seam(stmt: Map, fn_name: String) -> Void { + // RUNTIME SEAM: codegen cannot know which constructs will be bound to this + // fn after the binary exists, so the indirection is unconditional. What + // applies is resolved at execution against a table written later. + emit_line(" el_seam_run(EL_STR(" + c_str_lit(fn_name) + "), 0, 0);") let gdl = stmt["decorators"] let n_gdl: Int = native_list_len(gdl) let gi = 0 diff --git a/lang/runtime/el_runtime.c b/lang/runtime/el_runtime.c index 021f3f9..cad6cba 100644 --- a/lang/runtime/el_runtime.c +++ b/lang/runtime/el_runtime.c @@ -17016,6 +17016,81 @@ void dharma_emit(el_val_t event_type, el_val_t payload) { * dharma_emit generally — its payloads are hand-concatenated at 39 call sites * with no escaping, and a value containing a quote silently corrupts the * event. Fixing that is a separate change; this one does not add to it. */ +/* ── Runtime construct seam ─────────────────────────────────────────────── + * The crossing is resolved at EXECUTION, not at emission. Codegen emits one + * indirection per function; which constructs apply is read from a table that + * can be written AFTER the binary exists. + * + * This is the whole hypothesis under test: a compiler whose one compiled + * mechanism is language extension can compose without recompilation. If a + * construct declared after the build applies to a running program, the five + * compile-time declaration kinds were the wrong shape. + * + * Table format, one binding per line: + * entry|exit + * + * Targets are resolved with dlsym against the running image, so composition is + * bounded by the LINKED SYMBOL SET -- a construct naming a symbol nobody + * linked is skipped, not fatal. That bound is the honest limit on "endless". */ +#define EL_SEAM_MAX 256 +#define EL_PHASE_ENTRY 0 +#define EL_PHASE_EXIT 1 + +typedef struct { char* fn; char* construct; int phase; char* target; + void* resolved; int resolve_tried; } ElSeamBinding; +static ElSeamBinding _el_seam[EL_SEAM_MAX]; +static int _el_seam_n = 0; +static int _el_seam_loaded = 0; + +static void el_seam_load(void) { + if (_el_seam_loaded) return; + _el_seam_loaded = 1; + const char* p = getenv("EL_CONSTRUCTS"); + if (!p || !*p) return; + FILE* f = fopen(p, "r"); + if (!f) return; + char line[512]; + while (fgets(line, sizeof line, f) && _el_seam_n < EL_SEAM_MAX) { + char fn[128], con[128], ph[32], tgt[128]; + if (sscanf(line, "%127s %127s %31s %127s", fn, con, ph, tgt) == 4) { + if (fn[0] == '#') continue; + _el_seam[_el_seam_n].fn = el_strdup(fn); + _el_seam[_el_seam_n].construct = el_strdup(con); + _el_seam[_el_seam_n].phase = (strcmp(ph, "exit") == 0) ? EL_PHASE_EXIT : EL_PHASE_ENTRY; + _el_seam[_el_seam_n].target = el_strdup(tgt); + _el_seam_n++; + } + } + fclose(f); +} + +el_val_t el_seam_run(el_val_t fn_v, el_val_t phase_v, el_val_t result) { + if (!_el_seam_loaded) el_seam_load(); + if (_el_seam_n == 0) return result; /* the common path: no bindings */ + const char* fn = EL_CSTR(fn_v); + if (!fn) return result; + int phase = (int)phase_v; + el_val_t last = result; + for (int i = 0; i < _el_seam_n; i++) { + if (_el_seam[i].phase != phase) continue; + if (strcmp(_el_seam[i].fn, fn) != 0) continue; + /* Resolve ONCE. dlsym walks the dynamic symbol table on every call, and + * measured at 6.6x on a hot path with two bindings -- the table scan was + * never the cost. What is hot must stay resolved; this is the smallest + * form of the same thing salience does for memory. */ + if (!_el_seam[i].resolve_tried) { + _el_seam[i].resolved = dlsym(RTLD_DEFAULT, _el_seam[i].target); + _el_seam[i].resolve_tried = 1; + } + void* sym = _el_seam[i].resolved; + if (!sym) continue; /* unlinked target: skipped, not fatal */ + el_val_t (*fp)(el_val_t, el_val_t, el_val_t) = + (el_val_t (*)(el_val_t, el_val_t, el_val_t))sym; + last = fp(fn_v, el_wrap_str(el_strdup(_el_seam[i].construct)), last); + } + return last; +} + el_val_t engram_boundary_beat(el_val_t op_name, el_val_t construct) { _eg_aff_boundary_ops++; engram_chrono_tick(); diff --git a/lang/runtime/el_runtime.h b/lang/runtime/el_runtime.h index b3e0c9d..854a044 100644 --- a/lang/runtime/el_runtime.h +++ b/lang/runtime/el_runtime.h @@ -887,7 +887,8 @@ el_val_t engram_age_field(el_val_t delta_ms); el_val_t engram_age_field_catchup(void); el_val_t engram_chrono_persist_tick(void); el_val_t engram_chrono_tick(void); -el_val_t engram_boundary_beat(el_val_t op_name, el_val_t construct); /* API-reshape decorator-seam auto-emit; construct = the decorator that caused the beat */ +el_val_t engram_boundary_beat(el_val_t op_name, el_val_t construct); +el_val_t el_seam_run(el_val_t fn_name, el_val_t phase, el_val_t result); /* runtime construct seam */ /* API-reshape decorator-seam auto-emit; construct = the decorator that caused the beat */ el_val_t engram_self_anchor_capture(void); el_val_t engram_self_drift_json(void); el_val_t engram_neighbors_json(el_val_t node_id, el_val_t max_depth, el_val_t direction); From 886626a64e4c64b46d8382d95ab1d0ff7b739fe9 Mon Sep 17 00:00:00 2001 From: bigmerge Date: Mon, 17 Aug 2026 08:40:10 -0500 Subject: [PATCH 2/4] seam refusal + control tests: a runtime binding can short-circuit Prediction 3 was FALSE. I expected refusal to be impossible through the seam because the entry indirection discarded its return. One line: { el_val_t __s = el_seam_run(EL_STR(f), 0, 0); if (__s) return __s; } work() returns 7; bound to a refusing construct AFTER the build it returns 42. So three of the five compile-time kinds are runtime-bindable: entry injection, exit injection, and refusal. wraps_body needs invocation control and prohibits_outside is compile-time by nature. 104/104 native compiler tests pass. --- lang/el-compiler/src/codegen.el | 2 +- lang/tests/native/test_compiler.el | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/lang/el-compiler/src/codegen.el b/lang/el-compiler/src/codegen.el index 2eac94a..5fd5761 100644 --- a/lang/el-compiler/src/codegen.el +++ b/lang/el-compiler/src/codegen.el @@ -3208,7 +3208,7 @@ fn cg_entry_seam(stmt: Map, fn_name: String) -> Void { // RUNTIME SEAM: codegen cannot know which constructs will be bound to this // fn after the binary exists, so the indirection is unconditional. What // applies is resolved at execution against a table written later. - emit_line(" el_seam_run(EL_STR(" + c_str_lit(fn_name) + "), 0, 0);") + emit_line(" { el_val_t __s = el_seam_run(EL_STR(" + c_str_lit(fn_name) + "), 0, 0); if (__s) return __s; }") let gdl = stmt["decorators"] let n_gdl: Int = native_list_len(gdl) let gi = 0 diff --git a/lang/tests/native/test_compiler.el b/lang/tests/native/test_compiler.el index ed4ee1b..03988ec 100644 --- a/lang/tests/native/test_compiler.el +++ b/lang/tests/native/test_compiler.el @@ -903,3 +903,24 @@ test "seeded-vbd-prohibition-still-enforced" { let out: String = compile_capture(src) assert str_contains(out, "may only be called from an @manager fn"), "the compiled-in core prohibition survives being declared rather than branched" } + +// ── Runtime seam ───────────────────────────────────────────────────────────── +// +// CONTROL for the finding that a crossing can be resolved at execution rather +// than at emission. Codegen emits one unconditional indirection per fn; which +// constructs apply is read from a table written after the binary exists. + +test "seam-indirection-emitted-on-every-fn" { + let src: String = "fn a() -> Int { return 1 }\nfn b() -> Int { return 2 }" + let out: String = compile_capture(src) + assert str_contains(out, "el_seam_run(EL_STR(\"a\"), 0, 0);"), "fn a carries the indirection" + assert str_contains(out, "el_seam_run(EL_STR(\"b\"), 0, 0);"), "fn b carries the indirection" +} + +test "seam-emitted-without-any-decorator" { + // The point of the seam: source need not mention a construct at all. + let src: String = "fn undecorated() -> Int { return 1 }" + let out: String = compile_capture(src) + assert str_contains(out, "el_seam_run"), "an undecorated fn is still bindable at runtime" + assert !str_contains(out, "engram_boundary_beat"), "and nothing is inlined for it" +} From 28d19da7f1b6b43394302c82ef58446deeebc9d3 Mon Sep 17 00:00:00 2001 From: bigmerge Date: Mon, 17 Aug 2026 08:43:57 -0500 Subject: [PATCH 3/4] strip the compile-time machinery the seam replaces PREDICTION: codegen.el drops below 4661, its size before any of these passes. RESULT: FALSE. 5157 -> 5096. Still +435 over baseline. injects_at_entry collapsed into the seam removed guards_at_entry collapsed into the seam removed injects_at_exit needs the body-helper wrapper STRUCTURAL wraps_body needs the closure + wrapper structural prohibits_outside a #error cannot be emitted at runtime The wrapper is not a consequence of compile-time resolution. Early returns must be routed through something no matter when the target is resolved, so exit injection was never going to collapse. I predicted it would because I had conflated "resolved late" with "emitted less". What did collapse is entry injection and refusal -- 61 lines of compiler replaced by one refusable indirection, with the capability now bindable after the binary exists. 8 tests fail, and they are exactly the 8 controls for compile-time entry injection and guards. No unrelated breakage: the controls reported precisely what moved. They assert emission of something that now happens at runtime, so they need rewriting as integration tests -- which the framework does not currently support, because runtime binding needs a built binary and an environment, not compile_capture. Verified after the strip: fixpoint gen2==gen3, observation and refusal both work through the seam with the compiler knowing nothing about either. --- lang/el-compiler/src/codegen.el | 69 ++------------------------------- 1 file changed, 4 insertions(+), 65 deletions(-) diff --git a/lang/el-compiler/src/codegen.el b/lang/el-compiler/src/codegen.el index 5fd5761..8f71d36 100644 --- a/lang/el-compiler/src/codegen.el +++ b/lang/el-compiler/src/codegen.el @@ -3205,38 +3205,11 @@ fn fn_has_decorator(stmt: Map, name: String) -> Bool { // applies both); injection is topmost-wins, matching the VBD role convention, // because a role is singular and a refusal is not. fn cg_entry_seam(stmt: Map, fn_name: String) -> Void { - // RUNTIME SEAM: codegen cannot know which constructs will be bound to this - // fn after the binary exists, so the indirection is unconditional. What - // applies is resolved at execution against a table written later. + // The crossing is resolved at EXECUTION. One refusable indirection replaces + // the compile-time guard loop and injection loop: which constructs apply, + // and whether any of them refuses, is read from a table written after the + // binary exists. emit_line(" { el_val_t __s = el_seam_run(EL_STR(" + c_str_lit(fn_name) + "), 0, 0); if (__s) return __s; }") - let gdl = stmt["decorators"] - let n_gdl: Int = native_list_len(gdl) - let gi = 0 - while gi < n_gdl { - let gd = native_list_get(gdl, gi) - let gdn: String = gd["name"] - let g_target: String = decorator_guard(gdn) - if !str_eq(g_target, "") { - emit_line(" { el_val_t __g = " + g_target + "(EL_STR(" + c_str_lit(fn_name) + "), EL_STR(" + c_str_lit(gdn) + ")); if (__g) return __g; }") - } - let gi = gi + 1 - } - let idl = stmt["decorators"] - let n_idl: Int = native_list_len(idl) - let di = 0 - let did_inject: Bool = false - while di < n_idl { - if !did_inject { - let dd = native_list_get(idl, di) - let ddn: String = dd["name"] - let inj_target: String = decorator_injection(ddn) - if !str_eq(inj_target, "") { - emit_line(" " + inj_target + "(EL_STR(" + c_str_lit(fn_name) + "), EL_STR(" + c_str_lit(ddn) + "));") - let did_inject = true - } - } - let di = di + 1 - } } // cg_exit_target / cg_exit_construct — the first construct on this fn that @@ -4310,13 +4283,7 @@ fn program_has_routes(recs: [Map]) -> Bool { // inside this boundary" is a query over program structure and there is nothing // yet to ask. -fn declare_decorator(name: String, injects: String) -> Void { - state_set("__dec_inject_" + name, injects) -} -fn decorator_injection(name: String) -> String { - state_get("__dec_inject_" + name) -} // A GUARD is an injection that may refuse. The declared target is called at // entry with the same (fn, construct) pair; a non-zero return short-circuits @@ -4333,13 +4300,7 @@ fn decorator_injection(name: String) -> String { // nothing — fourteen applications that read as protection and emitted no // instruction. The compiler still knows nothing about authentication: the // program points the construct at its own function. -fn declare_guard(name: String, guards: String) -> Void { - state_set("__dec_guard_" + name, guards) -} -fn decorator_guard(name: String) -> String { - state_get("__dec_guard_" + name) -} // An EXIT injection runs after the fn returns and receives the result: // target(, , ) @@ -4419,14 +4380,8 @@ fn prohibiting_constructs() -> String { // the streaming backend discards per-fn ASTs and there is no whole-program AST // to walk. fn scan_declared_decorators(tokens: [Any]) -> Void { - declare_decorator("manager", "engram_boundary_beat") - declare_decorator("accessor", "engram_boundary_beat") declare_prohibition("manager", "dharma_emit,dharma_field") let total: Int = native_list_len(tokens) / 2 - let has_pending: Bool = false - let pending_target: String = "" - let has_pending_g: Bool = false - let pending_guard: String = "" let has_pending_x: Bool = false let pending_exit: String = "" let has_pending_w: Bool = false @@ -4471,14 +4426,6 @@ fn scan_declared_decorators(tokens: [Any]) -> Void { if str_eq(dname, "decorator") { if native_list_len(args) >= 2 { let dkind: String = native_list_get(args, 0) - if str_eq(dkind, "injects_at_entry") { - let has_pending = true - let pending_target = native_list_get(args, 1) - } - if str_eq(dkind, "guards_at_entry") { - let has_pending_g = true - let pending_guard = native_list_get(args, 1) - } if str_eq(dkind, "injects_at_exit") { let has_pending_x = true let pending_exit = native_list_get(args, 1) @@ -4497,14 +4444,6 @@ fn scan_declared_decorators(tokens: [Any]) -> Void { } else { if str_eq(k, "Fn") { let fname: String = tok_value(tokens, pos + 1) - if has_pending { - declare_decorator(fname, pending_target) - let has_pending = false - } - if has_pending_g { - declare_guard(fname, pending_guard) - let has_pending_g = false - } if has_pending_x { declare_exit(fname, pending_exit) let has_pending_x = false From 8bbb750c2cefc2dc070f6c5ff598e82483df9bcf Mon Sep 17 00:00:00 2001 From: bigmerge Date: Mon, 17 Aug 2026 08:48:57 -0500 Subject: [PATCH 4/4] control the claim that cannot be unit tested The seam's whole claim is that a construct declared AFTER a binary exists applies to that already-built program. compile_capture only sees emitted text, so it structurally cannot check this: it needs a built binary, a linked target, and an environment. Verified by hand until now, which is the standing problem this session has been about. tests/integration/seam_binding.sh builds a probe from El source containing no construct at all, links a target that El never references, and asserts: ok unbound program is unaffected ok a construct declared AFTER the build applies ok a construct declared after the build can REFUSE ok an unlinked target is skipped, not fatal ok a binding for a different fn does not fire ok two constructs compose on one crossing 6 assertions, 6 passed, 0 failed The eight controls that failed after the strip were replaced, not repaired. They asserted compile-time emission of capability that moved to runtime; contorting them would have kept an assertion whose subject no longer exists. Three took their place, asserting the emitted shape, and the behaviour they used to cover is now the integration harness's job -- which is the honest division, since the shape and the behaviour are no longer the same fact. 99/99 native compiler tests pass. Fixpoint holds. --- lang/tests/integration/seam_binding.sh | 85 ++++++++++++++++++++++++++ lang/tests/native/test_compiler.el | 84 +++++++++---------------- 2 files changed, 113 insertions(+), 56 deletions(-) create mode 100755 lang/tests/integration/seam_binding.sh diff --git a/lang/tests/integration/seam_binding.sh b/lang/tests/integration/seam_binding.sh new file mode 100755 index 0000000..27bf13b --- /dev/null +++ b/lang/tests/integration/seam_binding.sh @@ -0,0 +1,85 @@ +#!/usr/bin/env bash +# seam_binding.sh — integration control for the runtime construct seam. +# +# The seam's whole claim is that a construct declared AFTER a binary exists +# applies to that already-built program. That cannot be checked by +# compile_capture, which only sees emitted text: it needs a built binary, a +# linked target, and an environment. Hence a harness rather than a unit test. +# +# usage: seam_binding.sh [lang-dir] +# exit 0 = all assertions held; non-zero = number of failures +set -uo pipefail +ELC="${1:?usage: seam_binding.sh [lang-dir]}" +LANG_DIR="${2:-$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)}" +WORK="$(mktemp -d)"; trap 'rm -rf "$WORK"' EXIT +FAILS=0 + +ok() { printf ' ok %s\n' "$1"; } +fail() { printf ' FAIL %s\n expected: %s\n actual: %s\n' "$1" "$2" "$3"; FAILS=$((FAILS+1)); } +check(){ [ "$2" = "$3" ] && ok "$1" || fail "$1" "$2" "$3"; } + +SRCS=$("$LANG_DIR/../scripts/el-runtime-sources.sh" "$LANG_DIR/runtime") +CFLAGS="-std=c11 -O2 -rdynamic -I $LANG_DIR/runtime" +for d in /opt/homebrew/opt/openssl@3 /usr/local/opt/openssl@3; do + [ -d "$d" ] && CFLAGS="$CFLAGS -I $d/include" && LDFLAGS="-L $d/lib" +done +LDFLAGS="${LDFLAGS:-} -lcurl -lssl -lcrypto -lpthread -lm" + +# A construct target that is LINKED but never referenced from El source. +cat > "$WORK/targets.c" <<'EOF' +#include +#include +typedef int64_t el_val_t; +el_val_t observe(el_val_t fn, el_val_t con, el_val_t r){ + printf("SEEN %s/%s\n", (const char*)(intptr_t)fn, (const char*)(intptr_t)con); + return r; /* zero = do not refuse */ +} +el_val_t refuse(el_val_t fn, el_val_t con, el_val_t r){ + (void)fn; (void)con; (void)r; return 42; /* non-zero = short-circuit */ +} +EOF + +# A program with NO construct anywhere in its source. +cat > "$WORK/prog.el" <<'EOF' +fn work() -> Int { + return 7 +} + +fn main() { + println(int_to_str(work())) +} +EOF + +"$ELC" "$WORK/prog.el" > "$WORK/prog.c" 2>/dev/null +cc $CFLAGS -o "$WORK/prog" "$WORK/prog.c" "$WORK/targets.c" $SRCS $LDFLAGS 2>/dev/null \ + || { echo " FAIL probe did not build"; exit 1; } + +check "unbound program is unaffected" \ + "7" "$(cd "$WORK" && ./prog 2>&1)" + +printf 'work audited entry observe\n' > "$WORK/observe.txt" +check "a construct declared AFTER the build applies" \ + "SEEN work/audited +7" "$(cd "$WORK" && EL_CONSTRUCTS=observe.txt ./prog 2>&1)" + +printf 'work denied entry refuse\n' > "$WORK/refuse.txt" +check "a construct declared after the build can REFUSE" \ + "42" "$(cd "$WORK" && EL_CONSTRUCTS=refuse.txt ./prog 2>&1)" + +printf 'work ghost entry no_such_symbol_anywhere\n' > "$WORK/ghost.txt" +check "an unlinked target is skipped, not fatal" \ + "7" "$(cd "$WORK" && EL_CONSTRUCTS=ghost.txt ./prog 2>&1)" + +printf 'other_fn x entry refuse\n' > "$WORK/other.txt" +check "a binding for a different fn does not fire" \ + "7" "$(cd "$WORK" && EL_CONSTRUCTS=other.txt ./prog 2>&1)" + +printf 'work a entry observe\nwork b entry observe\n' > "$WORK/two.txt" +check "two constructs compose on one crossing" \ + "SEEN work/a +SEEN work/b +7" "$(cd "$WORK" && EL_CONSTRUCTS=two.txt ./prog 2>&1)" + +echo +echo " 6 assertions, $((6-FAILS)) passed, $FAILS failed" +exit $FAILS diff --git a/lang/tests/native/test_compiler.el b/lang/tests/native/test_compiler.el index 03988ec..7ce68af 100644 --- a/lang/tests/native/test_compiler.el +++ b/lang/tests/native/test_compiler.el @@ -735,19 +735,7 @@ test "compiler-stdint-include" { // be measured and "is this decorator earning its keep" stays an argument // instead of a query. -test "decorator-manager-beat-carries-construct" { - let src: String = "@manager\nfn f() -> Int { return 1 }" - let out: String = compile_capture(src) - assert str_contains(out, "engram_boundary_beat"), "@manager injects the beat" - assert str_contains(out, "EL_STR(\"manager\")"), "beat carries the construct that caused it" -} -test "decorator-accessor-beat-carries-construct" { - let src: String = "@accessor\nfn f() -> Int { return 1 }" - let out: String = compile_capture(src) - assert str_contains(out, "engram_boundary_beat"), "@accessor injects the beat" - assert str_contains(out, "EL_STR(\"accessor\")"), "beat carries the construct that caused it" -} test "decorator-undecorated-fn-has-no-beat" { let src: String = "fn f() -> Int { return 1 }" @@ -778,12 +766,6 @@ test "decorator-authenticate-compiles-to-nothing" { // A construct declares its own meaning and codegen reads it. Adding a // construct is a declaration in the program; it does not touch the compiler. -test "declared-construct-injects-without-compiler-knowledge" { - let src: String = "@decorator(\"injects_at_entry\", \"engram_boundary_beat\")\nfn audited() {}\n@audited\nfn risky() -> Int { return 7 }" - let out: String = compile_capture(src) - assert str_contains(out, "engram_boundary_beat(EL_STR(\"risky\")"), "a program-declared construct injects" - assert str_contains(out, "EL_STR(\"audited\")"), "the beat is attributed to the declared construct" -} test "declared-construct-name-unknown-to-codegen" { // The name is arbitrary. Nothing in the compiler mentions it. @@ -798,13 +780,6 @@ test "undeclared-construct-still-injects-nothing" { assert !str_contains(out, "engram_boundary_beat"), "an undeclared construct injects nothing" } -test "builtin-constructs-still-inject" { - // manager/accessor are the compiled-in core, seeded not branched. - let src: String = "@manager\nfn m() -> Int { return 1 }\n@accessor\nfn a() -> Int { return 2 }" - let out: String = compile_capture(src) - assert str_contains(out, "EL_STR(\"manager\")"), "seeded manager still injects" - assert str_contains(out, "EL_STR(\"accessor\")"), "seeded accessor still injects" -} // ── Declared constructs: guards ────────────────────────────────────────────── // @@ -813,29 +788,8 @@ test "builtin-constructs-still-inject" { // needed and never had — fourteen applications that read as protection and // emitted no instruction. -test "declared-guard-emits-refusable-check" { - let src: String = "@decorator(\"guards_at_entry\", \"my_auth\")\nfn authenticate() {}\n@authenticate\nfn handler() -> Int { return 7 }" - let out: String = compile_capture(src) - assert str_contains(out, "my_auth(EL_STR(\"handler\")"), "the guard is called at entry" - assert str_contains(out, "if (__g) return __g;"), "a non-zero guard result short-circuits the fn" -} -test "declared-guards-stack-in-order" { - let src: String = "@decorator(\"guards_at_entry\", \"my_auth\")\nfn authenticate() {}\n@decorator(\"guards_at_entry\", \"my_roles\")\nfn authorize() {}\n@authenticate\n@authorize\nfn handler() -> Int { return 7 }" - let out: String = compile_capture(src) - assert str_contains(out, "my_auth("), "first guard runs" - assert str_contains(out, "my_roles("), "second guard runs — every guard applies, not just the topmost" -} -test "guard-precedes-injection" { - // A refused call must not report a boundary crossing. - let src: String = "@decorator(\"guards_at_entry\", \"my_auth\")\nfn authenticate() {}\n@authenticate\n@manager\nfn handler() -> Int { return 7 }" - 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(\"handler\")") - assert g < b, "the guard is emitted before the beat" - assert g >= 0, "guard present" -} test "undeclared-guard-emits-nothing" { let src: String = "@not_a_declared_guard\nfn handler() -> Int { return 7 }" @@ -865,16 +819,6 @@ test "no-exit-construct-emits-no-wrapper" { 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" -} // ── Declared constructs: wraps and prohibitions ────────────────────────────── @@ -924,3 +868,31 @@ test "seam-emitted-without-any-decorator" { assert str_contains(out, "el_seam_run"), "an undecorated fn is still bindable at runtime" assert !str_contains(out, "engram_boundary_beat"), "and nothing is inlined for it" } + + +// ── Runtime seam: what replaced the compile-time entry mechanism ───────────── +// +// Entry injection and refusal moved from emission to execution. These assert +// the emitted shape; the BEHAVIOUR — that a construct declared after the build +// applies, refuses, composes, and that an unlinked target is skipped — is +// covered by tests/integration/seam_binding.sh, which needs a built binary and +// an environment and therefore cannot be a compile_capture test. + +test "seam-replaces-inlined-entry-injection" { + let src: String = "@manager\nfn m() -> Int { return 1 }" + let out: String = compile_capture(src) + assert str_contains(out, "el_seam_run(EL_STR(\"m\")"), "the crossing goes through the seam" + assert !str_contains(out, "engram_boundary_beat(EL_STR(\"m\")"), "nothing is inlined at the crossing any more" +} + +test "seam-entry-is-refusable" { + let src: String = "fn f() -> Int { return 1 }" + let out: String = compile_capture(src) + assert str_contains(out, "if (__s) return __s;"), "a bound construct can short-circuit the fn" +} + +test "seam-is-emitted-for-undecorated-fns" { + let src: String = "fn plain() -> Int { return 1 }" + let out: String = compile_capture(src) + assert str_contains(out, "el_seam_run(EL_STR(\"plain\")"), "any fn is bindable later, decorated or not" +}