Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1010185978 |
@@ -371,305 +371,6 @@ fn route_capture_knowledge(method: String, path: String, body: String) -> String
|
|||||||
"{\"ok\":true,\"id\":\"" + id + "\"}"
|
"{\"ok\":true,\"id\":\"" + id + "\"}"
|
||||||
}
|
}
|
||||||
|
|
||||||
// ═══════════════════════════════════════════════════════════════════════════
|
|
||||||
// THE UNIVERSAL ENGRAM OPERATION — reframe_region (native, set-based).
|
|
||||||
//
|
|
||||||
// There is ONE operation on the engram: isolate a discrete sub-manifold (a
|
|
||||||
// REGION) and operate on it AS A WHOLE — a set operation:
|
|
||||||
// isolate (cosine retrieval + adjacency → the SET of nodes)
|
|
||||||
// → supersede the stale region as a set (immutable tombstone; originals kept)
|
|
||||||
// → insert the new manifold as a set (dedup/load-merge path)
|
|
||||||
// → rebind edges by cosine
|
|
||||||
// → verify + one atomic persist.
|
|
||||||
// new = (region superseded) ∪ new_manifold.
|
|
||||||
//
|
|
||||||
// The SINGLE NODE is the DEGENERATE n=1 case of this SAME operation — not a
|
|
||||||
// separate CRUD path:
|
|
||||||
// write(content) = reframe(region=∅, manifold=[1 node]) (route_write)
|
|
||||||
// supersede(id,new) = reframe(region={id}, manifold=[1 node]) (route_supersede)
|
|
||||||
// relate(a,b,rel) = the rebind sub-op in isolation (route_create_edge)
|
|
||||||
// The ONLY anti-pattern is decomposing a region-scale change into a LOOP of
|
|
||||||
// independent top-level per-node updates. Here the region is the unit: one
|
|
||||||
// isolate, one atomic set-replace, one persist, one verify — iterating members
|
|
||||||
// INSIDE the one operation is set construction, not the sin.
|
|
||||||
//
|
|
||||||
// Spec: knowledge e7a03a94 / f999c5ff. Keystones kn-efeb4a5b / kn-5b606390 are
|
|
||||||
// write-protected — never superseded, never inserted-as identity.
|
|
||||||
// ═══════════════════════════════════════════════════════════════════════════
|
|
||||||
|
|
||||||
fn is_keystone(id: String) -> Bool {
|
|
||||||
if str_eq(id, "kn-efeb4a5b-5aff-4759-8a97-7233099be6ee") { return true }
|
|
||||||
if str_eq(id, "kn-5b606390-a52d-4ca2-8e0e-eba141d13440") { return true }
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// membership test in a [String] set
|
|
||||||
fn set_has(ids: [String], id: String) -> Bool {
|
|
||||||
let n: Int = el_list_len(ids)
|
|
||||||
let i: Int = 0
|
|
||||||
while i < n {
|
|
||||||
if str_eq(el_list_get(ids, i), id) { return true }
|
|
||||||
i = i + 1
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── ISOLATE ────────────────────────────────────────────────────────────────
|
|
||||||
// Select the region as a SET: cosine/token retrieval around the vantage
|
|
||||||
// (aperture k), optionally unioned with the 1-hop adjacency of each hit.
|
|
||||||
// Keystones are excluded from the mutable region by construction.
|
|
||||||
fn isolate_region(vantage: String, k: Int, expand: Int) -> [String] {
|
|
||||||
let ids: [String] = el_list_empty()
|
|
||||||
if str_eq(vantage, "") { return ids }
|
|
||||||
// (a) cosine/token retrieval — a clean node array [{"id":..},..]
|
|
||||||
let arr: String = engram_search_json(vantage, k)
|
|
||||||
let n: Int = json_array_len(arr)
|
|
||||||
let i: Int = 0
|
|
||||||
while i < n {
|
|
||||||
let hit: String = json_array_get(arr, i)
|
|
||||||
let id: String = json_get_string(hit, "id")
|
|
||||||
if !str_eq(id, "") {
|
|
||||||
if !is_keystone(id) {
|
|
||||||
if !set_has(ids, id) { ids = el_list_append(ids, id) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
i = i + 1
|
|
||||||
}
|
|
||||||
// (b) adjacency: union the 1-hop neighbourhood of each retrieved node.
|
|
||||||
// Iterate only over the original cosine seeds [0, seeds); neighbours append
|
|
||||||
// past that bound, so this is one hop, not a transitive sweep.
|
|
||||||
if expand > 0 {
|
|
||||||
let seeds: Int = el_list_len(ids)
|
|
||||||
let s: Int = 0
|
|
||||||
while s < seeds {
|
|
||||||
let seed: String = el_list_get(ids, s)
|
|
||||||
let nb: String = engram_neighbors_json(seed, 1, "both")
|
|
||||||
let m: Int = json_array_len(nb)
|
|
||||||
let j: Int = 0
|
|
||||||
while j < m {
|
|
||||||
let elem: String = json_array_get(nb, j)
|
|
||||||
let nodeobj: String = json_get_raw(elem, "node")
|
|
||||||
let nid: String = json_get_string(nodeobj, "id")
|
|
||||||
if !str_eq(nid, "") {
|
|
||||||
if !is_keystone(nid) {
|
|
||||||
if !set_has(ids, nid) { ids = el_list_append(ids, nid) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
j = j + 1
|
|
||||||
}
|
|
||||||
s = s + 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ids
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── SUPERSEDE (set) ────────────────────────────────────────────────────────
|
|
||||||
// Retire the region AS A WHOLE: one region-tombstone marker carries the
|
|
||||||
// provenance (reason + the full superseded id set); every region node is bound
|
|
||||||
// to it with a "superseded_by" edge. Originals are RETAINED — immutable
|
|
||||||
// tombstone, never a hard delete (engram_forget is deliberately NOT used).
|
|
||||||
// Returns the tombstone marker id ("" if the region is empty).
|
|
||||||
fn supersede_set(region: [String], reason: String) -> String {
|
|
||||||
let n: Int = el_list_len(region)
|
|
||||||
if n == 0 { return "" }
|
|
||||||
let csv: String = ""
|
|
||||||
let i0: Int = 0
|
|
||||||
while i0 < n {
|
|
||||||
let sep: String = if i0 == 0 { "" } else { "," }
|
|
||||||
csv = csv + sep + el_list_get(region, i0)
|
|
||||||
i0 = i0 + 1
|
|
||||||
}
|
|
||||||
let content: String = "region-tombstone: " + reason + " | superseded " + int_to_str(n) + " nodes: " + csv
|
|
||||||
let tomb: String = engram_node_full(content, "Tombstone", "region-tombstone", 0.1, 0.1, 1.0, "Episodic", "[\"tombstone\",\"region-supersede\"]")
|
|
||||||
let i: Int = 0
|
|
||||||
while i < n {
|
|
||||||
let rid: String = el_list_get(region, i)
|
|
||||||
engram_connect(rid, tomb, 1.0, "superseded_by")
|
|
||||||
i = i + 1
|
|
||||||
}
|
|
||||||
return tomb
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── INSERT (manifold) ──────────────────────────────────────────────────────
|
|
||||||
// Insert the new manifold as a SET. Inline JSON array of node objects
|
|
||||||
// {content, node_type?, tier?, tags?}. Each becomes a real embedded node
|
|
||||||
// (engram_node_full is the n=1 insert atom); the manifold is the set built from
|
|
||||||
// those atoms, wired with internal "manifold_member" edges so it enters as one
|
|
||||||
// connected sub-graph. Identity node_types (self/values) are demoted to Memory
|
|
||||||
// — identity can never be minted through reframe. Returns the new node ids.
|
|
||||||
fn insert_manifold_json(manifold: String) -> [String] {
|
|
||||||
let out: [String] = el_list_empty()
|
|
||||||
if str_eq(manifold, "") { return out }
|
|
||||||
let n: Int = json_array_len(manifold)
|
|
||||||
if n <= 0 { return out }
|
|
||||||
let i: Int = 0
|
|
||||||
let prev: String = ""
|
|
||||||
while i < n {
|
|
||||||
let obj: String = json_array_get(manifold, i)
|
|
||||||
let content: String = json_get_string(obj, "content")
|
|
||||||
if !str_eq(content, "") {
|
|
||||||
let nt_raw: String = json_get_string(obj, "node_type")
|
|
||||||
let nt: String = if str_eq(nt_raw, "") { "Memory" } else { nt_raw }
|
|
||||||
if str_eq(nt, "self") { nt = "Memory" }
|
|
||||||
if str_eq(nt, "values") { nt = "Memory" }
|
|
||||||
let tier_raw: String = json_get_string(obj, "tier")
|
|
||||||
let tier: String = if str_eq(tier_raw, "") { "Working" } else { tier_raw }
|
|
||||||
let tags_raw: String = json_get_raw(obj, "tags")
|
|
||||||
let tags: String = if str_eq(tags_raw, "") { "" } else { tags_raw }
|
|
||||||
let label: String = str_slice(content, 0, 60)
|
|
||||||
let id: String = engram_node_full(content, nt, label, 0.5, 0.5, 0.9, tier, tags)
|
|
||||||
out = el_list_append(out, id)
|
|
||||||
if !str_eq(prev, "") { engram_connect(prev, id, 0.6, "manifold_member") }
|
|
||||||
prev = id
|
|
||||||
}
|
|
||||||
i = i + 1
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── REBIND (edges by cosine) ───────────────────────────────────────────────
|
|
||||||
// Re-embed the new manifold into the surrounding geometry: bind each new node
|
|
||||||
// to the tombstone marker (provenance: new region -reframes-> retired region),
|
|
||||||
// then to its top cosine/token neighbours in the store (skipping itself, the
|
|
||||||
// new set, keystones, tombstones). Returns the number of edges bound.
|
|
||||||
fn rebind_cosine(new_ids: [String], tomb: String) -> Int {
|
|
||||||
let bound: Int = 0
|
|
||||||
let n: Int = el_list_len(new_ids)
|
|
||||||
let i: Int = 0
|
|
||||||
while i < n {
|
|
||||||
let nid: String = el_list_get(new_ids, i)
|
|
||||||
if !str_eq(tomb, "") {
|
|
||||||
engram_connect(nid, tomb, 0.8, "reframes")
|
|
||||||
bound = bound + 1
|
|
||||||
}
|
|
||||||
let node_json: String = engram_get_node_json(nid)
|
|
||||||
let content: String = json_get_string(node_json, "content")
|
|
||||||
let arr: String = engram_search_json(content, 5)
|
|
||||||
let m: Int = json_array_len(arr)
|
|
||||||
let j: Int = 0
|
|
||||||
while j < m {
|
|
||||||
let hit: String = json_array_get(arr, j)
|
|
||||||
let hid: String = json_get_string(hit, "id")
|
|
||||||
if !str_eq(hid, "") {
|
|
||||||
if !str_eq(hid, nid) {
|
|
||||||
if !is_keystone(hid) {
|
|
||||||
if !set_has(new_ids, hid) {
|
|
||||||
let htype: String = json_get_string(hit, "node_type")
|
|
||||||
if !str_eq(htype, "Tombstone") {
|
|
||||||
engram_connect(nid, hid, 0.5, "related")
|
|
||||||
bound = bound + 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
j = j + 1
|
|
||||||
}
|
|
||||||
i = i + 1
|
|
||||||
}
|
|
||||||
return bound
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── THE OPERATION ──────────────────────────────────────────────────────────
|
|
||||||
// isolate (done by caller) → supersede region → insert manifold → rebind →
|
|
||||||
// one atomic persist → verify report. This is the whole operation; every
|
|
||||||
// mutation route below is a projection of it.
|
|
||||||
fn reframe_core(region: [String], manifold: String, reason: String, do_rebind: Int) -> String {
|
|
||||||
let n_before: Int = engram_node_count()
|
|
||||||
let e_before: Int = engram_edge_count()
|
|
||||||
let region_n: Int = el_list_len(region)
|
|
||||||
let tomb: String = if region_n > 0 { supersede_set(region, reason) } else { "" }
|
|
||||||
let new_ids: [String] = insert_manifold_json(manifold)
|
|
||||||
let inserted: Int = el_list_len(new_ids)
|
|
||||||
let bound: Int = if do_rebind > 0 { rebind_cosine(new_ids, tomb) } else { 0 }
|
|
||||||
let saved: Int = persist_canonical()
|
|
||||||
let new_csv: String = ""
|
|
||||||
let k: Int = 0
|
|
||||||
while k < inserted {
|
|
||||||
let sep: String = if k == 0 { "" } else { "," }
|
|
||||||
new_csv = new_csv + sep + "\"" + el_list_get(new_ids, k) + "\""
|
|
||||||
k = k + 1
|
|
||||||
}
|
|
||||||
return "{\"ok\":true,\"region_superseded\":" + int_to_str(region_n) +
|
|
||||||
",\"tombstone_id\":\"" + tomb + "\"" +
|
|
||||||
",\"inserted\":" + int_to_str(inserted) +
|
|
||||||
",\"new_ids\":[" + new_csv + "]" +
|
|
||||||
",\"edges_rebound\":" + int_to_str(bound) +
|
|
||||||
",\"nodes_added\":" + int_to_str(engram_node_count() - n_before) +
|
|
||||||
",\"edges_added\":" + int_to_str(engram_edge_count() - e_before) +
|
|
||||||
",\"node_count\":" + int_to_str(engram_node_count()) +
|
|
||||||
",\"edge_count\":" + int_to_str(engram_edge_count()) +
|
|
||||||
",\"keystones_protected\":true}"
|
|
||||||
}
|
|
||||||
|
|
||||||
// POST /api/reframe — the universal set-based mutation.
|
|
||||||
// Body: {vantage?, region_ids?(csv), k?, expand?, manifold(json array), reason?, rebind?}
|
|
||||||
// region_ids (explicit) wins; else cosine-isolate around vantage.
|
|
||||||
fn route_reframe(method: String, path: String, body: String) -> String {
|
|
||||||
let region_csv: String = json_get_string(body, "region_ids")
|
|
||||||
let vantage: String = json_get_string(body, "vantage")
|
|
||||||
let region: [String] = el_list_empty()
|
|
||||||
if !str_eq(region_csv, "") {
|
|
||||||
let parts: [String] = str_split(region_csv, ",")
|
|
||||||
let pn: Int = el_list_len(parts)
|
|
||||||
let i: Int = 0
|
|
||||||
while i < pn {
|
|
||||||
let id: String = str_trim(el_list_get(parts, i))
|
|
||||||
if !str_eq(id, "") {
|
|
||||||
if is_keystone(id) { return err_json("reframe: identity keystone write-protected") }
|
|
||||||
if !set_has(region, id) { region = el_list_append(region, id) }
|
|
||||||
}
|
|
||||||
i = i + 1
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if !str_eq(vantage, "") {
|
|
||||||
let kv: Int = json_get_int(body, "k")
|
|
||||||
let kk: Int = if kv > 0 { kv } else { 12 }
|
|
||||||
let expand: Int = json_get_int(body, "expand")
|
|
||||||
region = isolate_region(vantage, kk, expand)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let manifold: String = json_get_raw(body, "manifold")
|
|
||||||
let reason_raw: String = json_get_string(body, "reason")
|
|
||||||
let reason: String = if str_eq(reason_raw, "") { "reframe" } else { reason_raw }
|
|
||||||
// rebind defaults ON for reframe (absent → 1); explicit 0 disables.
|
|
||||||
let rebind_raw: String = json_get_raw(body, "rebind")
|
|
||||||
let do_rebind: Int = if str_eq(rebind_raw, "") { 1 } else { json_get_int(body, "rebind") }
|
|
||||||
return reframe_core(region, manifold, reason, do_rebind)
|
|
||||||
}
|
|
||||||
|
|
||||||
// write — DEGENERATE n=1 of reframe: region=∅, manifold=[1 node]. The SAME
|
|
||||||
// reframe_core path. rebind off so the pure-add matches plain node creation.
|
|
||||||
// POST /api/write {content, node_type?, tier?, tags?}
|
|
||||||
fn route_write(method: String, path: String, body: String) -> String {
|
|
||||||
let content: String = json_get_string(body, "content")
|
|
||||||
if str_eq(content, "") { return err_json("write: content required") }
|
|
||||||
let nt: String = json_get_string(body, "node_type")
|
|
||||||
if str_eq(nt, "self") { return err_json("write: identity is write-protected") }
|
|
||||||
if str_eq(nt, "values") { return err_json("write: identity is write-protected") }
|
|
||||||
let empty: [String] = el_list_empty()
|
|
||||||
let manifold: String = "[" + body + "]" // the body IS a valid manifold node object
|
|
||||||
return reframe_core(empty, manifold, "write", 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// supersede — DEGENERATE n=1 of reframe: region={id}, manifold=[1 node]. The
|
|
||||||
// SAME reframe_core path with a size-1 region. Original retained (immutable);
|
|
||||||
// new node inserted and cosine-rebound; provenance edge new-reframes-tomb.
|
|
||||||
// POST /api/supersede {id, content, node_type?, tier?, tags?, reason?}
|
|
||||||
fn route_supersede(method: String, path: String, body: String) -> String {
|
|
||||||
let id: String = json_get_string(body, "id")
|
|
||||||
if str_eq(id, "") { return err_json("supersede: id required") }
|
|
||||||
if is_keystone(id) { return err_json("supersede: identity keystone write-protected") }
|
|
||||||
let content: String = json_get_string(body, "content")
|
|
||||||
if str_eq(content, "") { return err_json("supersede: content required") }
|
|
||||||
let region: [String] = el_list_empty()
|
|
||||||
region = el_list_append(region, id)
|
|
||||||
let manifold: String = "[" + body + "]"
|
|
||||||
let reason_raw: String = json_get_string(body, "reason")
|
|
||||||
let reason: String = if str_eq(reason_raw, "") { "supersede " + id } else { reason_raw }
|
|
||||||
return reframe_core(region, manifold, reason, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── Auth ──────────────────────────────────────────────────────────────────────
|
// ── Auth ──────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
fn check_auth_ok(method: String, body: String) -> Bool {
|
fn check_auth_ok(method: String, body: String) -> Bool {
|
||||||
@@ -717,19 +418,6 @@ fn handle_request(method: String, path: String, body: String) -> String {
|
|||||||
return route_stats(method, path, body)
|
return route_stats(method, path, body)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── The universal set-based operation and its n=1 degenerate projections ──
|
|
||||||
// reframe = isolate → supersede-region → insert-manifold → rebind. write and
|
|
||||||
// supersede are the SAME reframe_core path at region size 0 and 1.
|
|
||||||
if str_eq(method, "POST") && (str_eq(clean, "/api/reframe") || str_eq(clean, "/reframe")) {
|
|
||||||
return route_reframe(method, path, body)
|
|
||||||
}
|
|
||||||
if str_eq(method, "POST") && (str_eq(clean, "/api/write") || str_eq(clean, "/write")) {
|
|
||||||
return route_write(method, path, body)
|
|
||||||
}
|
|
||||||
if str_eq(method, "POST") && (str_eq(clean, "/api/supersede") || str_eq(clean, "/supersede")) {
|
|
||||||
return route_supersede(method, path, body)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Nodes
|
// Nodes
|
||||||
if str_eq(method, "POST") && (str_eq(clean, "/api/nodes") || str_eq(clean, "/nodes")) {
|
if str_eq(method, "POST") && (str_eq(clean, "/api/nodes") || str_eq(clean, "/nodes")) {
|
||||||
return route_create_node(method, path, body)
|
return route_create_node(method, path, body)
|
||||||
|
|||||||
+24
-12
@@ -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.
|
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:
|
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. Add the C function to `el_seed.c`
|
1. Implement the C function in `el_runtime.c` (and declare it in `el_runtime.h`).
|
||||||
2. Declare it in `el_seed.h`
|
2. Add a `__`-prefixed thin wrapper in `el_seed.c` and 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)
|
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)
|
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
|
## 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
|
```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
|
./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 \
|
cc -std=c11 -I el-compiler/runtime -lcurl -lpthread \
|
||||||
-o dist/platform/elc-new \
|
-o dist/platform/elc-new \
|
||||||
elc-new.c el-compiler/runtime/el_seed.c
|
elc-new.c el-compiler/runtime/el_runtime.c
|
||||||
# Verify self-hosting:
|
# 3. Verify self-hosting FIXPOINT (stage3 == stage2 output, byte-identical):
|
||||||
./dist/platform/elc-new elc-cli.el > elc-verify.c
|
./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
|
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.
|
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.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -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));
|
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": <node|null>, "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) {
|
el_val_t engram_stats_json(void) {
|
||||||
EngramStore* g = engram_get();
|
EngramStore* g = engram_get();
|
||||||
char buf[128];
|
char buf[128];
|
||||||
|
|||||||
@@ -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_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_activate_json(el_val_t query, el_val_t depth);
|
||||||
el_val_t engram_stats_json(void);
|
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);
|
el_val_t engram_list_layers_json(void);
|
||||||
/* engram_compile_layered_json — produce a prompt-ready text block split
|
/* engram_compile_layered_json — produce a prompt-ready text block split
|
||||||
* into "[LAYER 0 — STRUCTURAL]" (non-suppressible layers, sacred fire)
|
* into "[LAYER 0 — STRUCTURAL]" (non-suppressible layers, sacred fire)
|
||||||
|
|||||||
@@ -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_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_list_layers_json(void) { return engram_list_layers_json(); }
|
||||||
|
|
||||||
el_val_t __engram_compile_layered_json(el_val_t intent, el_val_t depth) {
|
el_val_t __engram_compile_layered_json(el_val_t intent, el_val_t depth) {
|
||||||
|
|||||||
@@ -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_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_activate_json(el_val_t query, el_val_t depth);
|
||||||
el_val_t __engram_stats_json(void);
|
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_list_layers_json(void);
|
||||||
el_val_t __engram_compile_layered_json(el_val_t intent, el_val_t depth);
|
el_val_t __engram_compile_layered_json(el_val_t intent, el_val_t depth);
|
||||||
|
|
||||||
|
|||||||
@@ -2579,6 +2579,9 @@ fn builtin_arity(name: String) -> Int {
|
|||||||
if str_eq(name, "__engram_neighbors_filtered") { return 3 }
|
if str_eq(name, "__engram_neighbors_filtered") { return 3 }
|
||||||
if str_eq(name, "__engram_activate") { return 2 }
|
if str_eq(name, "__engram_activate") { return 2 }
|
||||||
if str_eq(name, "__engram_activate_json") { 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, "__engram_scan_nodes_json") { return 2 }
|
||||||
if str_eq(name, "__generate") { return 1 }
|
if str_eq(name, "__generate") { return 1 }
|
||||||
// Filesystem
|
// 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_neighbors_json") { return 3 }
|
||||||
if str_eq(name, "engram_activate_json") { return 2 }
|
if str_eq(name, "engram_activate_json") { return 2 }
|
||||||
if str_eq(name, "engram_stats_json") { return 0 }
|
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
|
// LLM
|
||||||
if str_eq(name, "llm_call") { return 2 }
|
if str_eq(name, "llm_call") { return 2 }
|
||||||
if str_eq(name, "llm_call_system") { return 3 }
|
if str_eq(name, "llm_call_system") { return 3 }
|
||||||
|
|||||||
Reference in New Issue
Block a user