diff --git a/lang/AGENTS.md b/lang/AGENTS.md index ea93660..e7fc484 100644 --- a/lang/AGENTS.md +++ b/lang/AGENTS.md @@ -31,34 +31,46 @@ This is where almost all work belongs. El programs are source files that get com This is the self-contained C OS-boundary layer. It provides the `__`-prefixed primitives that compiled El programs call: libcurl HTTP, pthreads, filesystem I/O, arena allocation, etc. It is **not generated** — it is maintained by hand. -The old `el_runtime.c` has been archived to `el-compiler/runtime/legacy/`. The runtime is now native El (`runtime/*.el`). `el_seed.c` replaces `el_runtime.c` as the sole C compilation dependency. +The runtime is native El (`runtime/*.el`) over a C OS-boundary. **Status (verified 2026-08-15):** the migration to a seed-only boundary is *in progress, not done*. Two files exist: +- `el-compiler/runtime/el_runtime.c` (~516 KB) — **LIVE**. Holds the engram store (`EngramStore engram_global`) plus the `http_*`/`json_*`/`state_*`/`engram_*` impls. It is the authoritative single-file link target for the compiler, and `tools/install.sh` compiles it into `libel.a`. This is where a new C builtin's *implementation* must currently live to be linkable. +- `el-compiler/runtime/el_seed.c` — the intended hand-maintained `__`-prefixed seed (thin wrappers over the above). It is compiled alongside `el_runtime.c` by `tools/install.sh`, but does **not** compile standalone yet (see the build-path caveat under "Rebuilding the Compiler"). +- `el-compiler/runtime/legacy/el_runtime.c` (~419 KB) — **DEAD**. Archived duplicate; no build script references it. -**Only edit `el_seed.c` when you genuinely need OS-level access** (raw sockets, GPU calls, new libcurl features). For everything else, write El. +**Only edit these when you genuinely need OS-level access** (raw sockets, GPU calls, new libcurl features, a new engram store op). For everything else, write El. -When you do add a C builtin: -1. Add the C function to `el_seed.c` -2. Declare it in `el_seed.h` -3. Add it to the `builtin_arity` table in `el-compiler/src/codegen.el` (so the compiler knows the arg count) -4. Rebuild the elc binary (see below) +When you add a C builtin (verbatim-emit recipe — the El name is emitted as the exact C symbol; `builtin_arity` is an arity guard only, not a dispatch table): +1. Implement the C function in `el_runtime.c` (and declare it in `el_runtime.h`). +2. Add a `__`-prefixed thin wrapper in `el_seed.c` and declare it in `el_seed.h`. +3. Add the name to `builtin_arity` in `el-compiler/src/codegen.el` — add **both** the plain and `__`-prefixed spellings. +4. Rebuild the elc binary (see below) and confirm the self-host fixpoint is byte-identical. + +Worked example: the `engram_assert_json` (op_assert seam) and `engram_node_full_in`/`engram_connect_in` (purview write-side) primitives added 2026-08-15 follow exactly this recipe. --- ## Rebuilding the Compiler -After changing any `.el` source in `el-compiler/src/`: +After changing any `.el` source in `el-compiler/src/` (run from the `lang/` dir): ```bash -cd /Users/will/Development/neuron-technologies/foundation/el +# 1. Stage2: current elc compiles the (modified) compiler to C ./dist/platform/elc elc-cli.el > elc-new.c +# 2. Build the new compiler. The C link target is el_runtime.c — it holds the +# engram store + http/json/state impls the compiler output calls. el_runtime.c +# self-hosts elc on its own; el_seed.c is the (aspirational) seed layer and does +# NOT compile standalone under clang (missing prototypes for the el_runtime.c +# symbols it wraps — see caveat below), so link el_runtime.c here. cc -std=c11 -I el-compiler/runtime -lcurl -lpthread \ -o dist/platform/elc-new \ - elc-new.c el-compiler/runtime/el_seed.c -# Verify self-hosting: + elc-new.c el-compiler/runtime/el_runtime.c +# 3. Verify self-hosting FIXPOINT (stage3 == stage2 output, byte-identical): ./dist/platform/elc-new elc-cli.el > elc-verify.c -diff elc-new.c elc-verify.c # should be identical +diff elc-new.c elc-verify.c # must be identical mv dist/platform/elc-new dist/platform/elc ``` +> **Build-path caveat (verified 2026-08-15).** `el_seed.c` is the intended hand-maintained OS-boundary seed, but it does **not** compile standalone under modern clang: it wraps ~16 unprefixed `el_runtime.c` symbols (`http_serve`, `json_*`, `state_*`, `http_response`) without prototypes, and clang treats implicit declarations as errors (C99+). The productionised install (`tools/install.sh`) builds `libel.a` from **both** `el_seed.o` + `el_runtime.o` together, which is why linking succeeds there. To make `el_seed.c` build on its own, add prototypes for those symbols (or `#include "el_runtime.h"`, reconciling the `__http_serve` return-type mismatch first). Until then, `el_runtime.c` is the authoritative single-file link target for the compiler. + After changing `el_seed.c` only (no El source changes), rebuild downstream programs but do NOT need to rebuild the compiler binary itself — the seed is linked at the application level, not the compiler level. --- diff --git a/lang/el-compiler/runtime/el_runtime.c b/lang/el-compiler/runtime/el_runtime.c index af0d945..4738b1b 100644 --- a/lang/el-compiler/runtime/el_runtime.c +++ b/lang/el-compiler/runtime/el_runtime.c @@ -8410,6 +8410,59 @@ el_val_t engram_activate_json(el_val_t query, el_val_t depth) { return el_wrap_str(jb_finish(&b)); } +/* op_assert seam (realizer promotion, bl-53/#57). + * Gathers the grounded ASSERTION ENVELOPE for a subject node — + * { "subject": , "grounding": [ {node,edge,hops}... ] } + * i.e. the self-geometry a realizer renders as faithful first-person text. + * Read-only: realization (geometry->text) stays in the faculty/realizer; + * this native primitive produces its structured input from proven paths + * (engram_emit_node_json + engram_neighbors_json). arity 2 (node_id, depth). */ +el_val_t engram_assert_json(el_val_t node_id, el_val_t depth) { + const char* sid = EL_CSTR(node_id); + JsonBuf b; jb_init(&b); + jb_puts(&b, "{\"subject\":"); + EngramNode* n = (sid && *sid) ? engram_find_node(sid) : NULL; + if (n) engram_emit_node_json(&b, n); else jb_puts(&b, "null"); + jb_puts(&b, ",\"grounding\":"); + el_val_t nb = engram_neighbors_json(node_id, depth, EL_STR("both")); + const char* nbs = EL_CSTR(nb); + jb_puts(&b, (nbs && *nbs) ? nbs : "[]"); + jb_putc(&b, '}'); + return el_wrap_str(jb_finish(&b)); +} + +/* Parametric mutation (purview write-side bounding, keystone 56ecbec6). + * The mutation verbs travel with a TARGET MANIFOLD (purview) instead of the + * implicit global singleton. purview==0 (EL_NULL) is the DEGENERATE/DEFAULT + * case: G = live, behaviour identical to the base op. A non-zero purview is a + * bounded target that the engine cannot yet resolve (multi-manifold store is a + * promotion item), so we REFUSE rather than silently mutate the live set — + * write-side bounding must never leak into G=live. */ +el_val_t engram_node_full_in(el_val_t purview, + el_val_t content, el_val_t node_type, el_val_t label, + el_val_t salience, el_val_t importance, el_val_t confidence, + el_val_t tier, el_val_t tags) { + if (purview == 0) { + return engram_node_full(content, node_type, label, salience, importance, + confidence, tier, tags); + } + fprintf(stderr, "[engram] purview write-side not yet resolvable (G != live); " + "refusing to append to live store (purview=%lld)\n", + (long long)purview); + return EL_STR(""); +} + +void engram_connect_in(el_val_t purview, + el_val_t from_id, el_val_t to_id, el_val_t weight, el_val_t relation) { + if (purview == 0) { + engram_connect(from_id, to_id, weight, relation); + return; + } + fprintf(stderr, "[engram] purview write-side not yet resolvable (G != live); " + "refusing to connect in live store (purview=%lld)\n", + (long long)purview); +} + el_val_t engram_stats_json(void) { EngramStore* g = engram_get(); char buf[128]; diff --git a/lang/el-compiler/runtime/el_runtime.h b/lang/el-compiler/runtime/el_runtime.h index 87348f5..9be3404 100644 --- a/lang/el-compiler/runtime/el_runtime.h +++ b/lang/el-compiler/runtime/el_runtime.h @@ -639,6 +639,14 @@ el_val_t engram_scan_nodes_by_type_json(el_val_t node_type, el_val_t limit, el_ el_val_t engram_neighbors_json(el_val_t node_id, el_val_t max_depth, el_val_t direction); el_val_t engram_activate_json(el_val_t query, el_val_t depth); el_val_t engram_stats_json(void); +/* op_assert seam: grounded assertion envelope {subject,grounding} for the realizer. */ +el_val_t engram_assert_json(el_val_t node_id, el_val_t depth); +/* Parametric mutation (purview write-side): purview==0 => G=live (default), else refuse. */ +el_val_t engram_node_full_in(el_val_t purview, el_val_t content, el_val_t node_type, el_val_t label, + el_val_t salience, el_val_t importance, el_val_t confidence, + el_val_t tier, el_val_t tags); +void engram_connect_in(el_val_t purview, el_val_t from_id, el_val_t to_id, + el_val_t weight, el_val_t relation); el_val_t engram_list_layers_json(void); /* engram_compile_layered_json — produce a prompt-ready text block split * into "[LAYER 0 — STRUCTURAL]" (non-suppressible layers, sacred fire) diff --git a/lang/el-compiler/runtime/el_seed.c b/lang/el-compiler/runtime/el_seed.c index cda893c..8dc678e 100644 --- a/lang/el-compiler/runtime/el_seed.c +++ b/lang/el-compiler/runtime/el_seed.c @@ -1095,6 +1095,15 @@ el_val_t __engram_activate_json(el_val_t query, el_val_t depth) { } el_val_t __engram_stats_json(void) { return engram_stats_json(); } +el_val_t __engram_assert_json(el_val_t node_id, el_val_t depth) { return engram_assert_json(node_id, depth); } +el_val_t __engram_node_full_in(el_val_t purview, el_val_t content, el_val_t node_type, el_val_t label, + el_val_t salience, el_val_t importance, el_val_t confidence, + el_val_t tier, el_val_t tags) { + return engram_node_full_in(purview, content, node_type, label, salience, importance, confidence, tier, tags); +} +void __engram_connect_in(el_val_t purview, el_val_t from_id, el_val_t to_id, el_val_t weight, el_val_t relation) { + engram_connect_in(purview, from_id, to_id, weight, relation); +} el_val_t __engram_list_layers_json(void) { return engram_list_layers_json(); } el_val_t __engram_compile_layered_json(el_val_t intent, el_val_t depth) { diff --git a/lang/el-compiler/runtime/el_seed.h b/lang/el-compiler/runtime/el_seed.h index 7597511..6b6ffd4 100644 --- a/lang/el-compiler/runtime/el_seed.h +++ b/lang/el-compiler/runtime/el_seed.h @@ -233,6 +233,12 @@ el_val_t __engram_scan_nodes_by_type_json(el_val_t node_type, el_val_t limit, e el_val_t __engram_neighbors_json(el_val_t node_id, el_val_t max_depth, el_val_t direction); el_val_t __engram_activate_json(el_val_t query, el_val_t depth); el_val_t __engram_stats_json(void); +el_val_t __engram_assert_json(el_val_t node_id, el_val_t depth); +el_val_t __engram_node_full_in(el_val_t purview, el_val_t content, el_val_t node_type, el_val_t label, + el_val_t salience, el_val_t importance, el_val_t confidence, + el_val_t tier, el_val_t tags); +void __engram_connect_in(el_val_t purview, el_val_t from_id, el_val_t to_id, + el_val_t weight, el_val_t relation); el_val_t __engram_list_layers_json(void); el_val_t __engram_compile_layered_json(el_val_t intent, el_val_t depth); diff --git a/lang/el-compiler/src/codegen.el b/lang/el-compiler/src/codegen.el index a20569a..87bbba4 100644 --- a/lang/el-compiler/src/codegen.el +++ b/lang/el-compiler/src/codegen.el @@ -2579,6 +2579,9 @@ fn builtin_arity(name: String) -> Int { if str_eq(name, "__engram_neighbors_filtered") { return 3 } if str_eq(name, "__engram_activate") { return 2 } if str_eq(name, "__engram_activate_json") { return 2 } + if str_eq(name, "__engram_assert_json") { return 2 } + if str_eq(name, "__engram_node_full_in") { return 9 } + if str_eq(name, "__engram_connect_in") { return 5 } if str_eq(name, "__engram_scan_nodes_json") { return 2 } if str_eq(name, "__generate") { return 1 } // Filesystem @@ -2676,6 +2679,9 @@ fn builtin_arity(name: String) -> Int { if str_eq(name, "engram_neighbors_json") { return 3 } if str_eq(name, "engram_activate_json") { return 2 } if str_eq(name, "engram_stats_json") { return 0 } + if str_eq(name, "engram_assert_json") { return 2 } + if str_eq(name, "engram_node_full_in") { return 9 } + if str_eq(name, "engram_connect_in") { return 5 } // LLM if str_eq(name, "llm_call") { return 2 } if str_eq(name, "llm_call_system") { return 3 }