self-review 2026-06-30: WM cap, breakthrough floor, ISE exclusion + route

Port critical WM fixes from self-review 2026-06-26 branch (f7bd99a) that were
never merged to HEAD. Running binary had these fixes; source did not — rebuild
would have silently regressed all three improvements.

1. ENGRAM_BREAKTHROUGH_WEIGHT 0.25→0.10
   With 0.25, naturally-promoted nodes (threshold ≥0.15) decayed below the
   breakthrough floor within one activation call and lost their WM slot to
   fresh breakthrough candidates. All 524/525 WM nodes were at floor = useless.
   Invariant: BREAKTHROUGH_WEIGHT < min(type_thresholds = 0.15 Canonical).

2. ENGRAM_WM_CAP=24 with Pass 4 (per-call) + Pass 5 (global) enforcement
   Without cap, broad curiosity seeds promote 500+ nodes simultaneously.
   wm_avg_weight collapses, goal-bias differentiation is lost. Verified:
   "knowledge" query now promotes exactly 24 nodes (was 525). Cowan (2001)
   cognitive basis: WM capacity ~4 chunks; 24 allows rich multi-topic context.

3. ISE exclusion from WM (Pass 2 guard)
   InternalStateEvent JSON content ("knowledge", "memory", etc.) triggered
   lexical seeding → suppression accumulation → breakthrough at floor. ISEs
   are observability-only and must never surface in context compilation.
   suppression_count cleared so ISEs never build toward breakthrough.

4. route_create_ise importance fix (0.5→0.3)
   Corrects mismatch between HTTP route and awareness.el in-process fallback.
   Also adds body comment clarifying auth-exempt rationale.

SYNAPSE (arXiv 2601.02744) validates WM cap design and ISE exclusion principle.
Next priority: cosine similarity seeding to complement lexical BFS.
This commit is contained in:
2026-06-30 08:48:19 -05:00
parent 35c189759c
commit da116b2884
4 changed files with 333 additions and 5 deletions
Vendored Executable
BIN
View File
Binary file not shown.
+38 -2
View File
@@ -20,6 +20,8 @@ el_val_t route_create_edge(el_val_t method, el_val_t path, el_val_t body);
el_val_t route_neighbors(el_val_t method, el_val_t path, el_val_t body);
el_val_t route_strengthen(el_val_t method, el_val_t path, el_val_t body);
el_val_t route_forget(el_val_t method, el_val_t path, el_val_t body);
el_val_t route_create_ise(el_val_t method, el_val_t path, el_val_t body);
el_val_t route_sync(el_val_t method, el_val_t path, el_val_t body);
el_val_t route_save(el_val_t method, el_val_t path, el_val_t body);
el_val_t route_load(el_val_t method, el_val_t path, el_val_t body);
el_val_t route_health(el_val_t method, el_val_t path, el_val_t body);
@@ -115,7 +117,7 @@ el_val_t route_create_node(el_val_t method, el_val_t path, el_val_t body) {
node_type = EL_STR("Memory");
}
el_val_t salience = json_get_float(body, EL_STR("salience"));
if (str_eq(salience, el_from_float(0.0))) {
if (salience == el_from_float(0.0)) {
salience = el_from_float(0.5);
}
el_val_t id = engram_node(content, node_type, salience);
@@ -205,7 +207,7 @@ el_val_t route_create_edge(el_val_t method, el_val_t path, el_val_t body) {
relation = EL_STR("associates");
}
el_val_t weight = json_get_float(body, EL_STR("weight"));
if (str_eq(weight, el_from_float(0.0))) {
if (weight == el_from_float(0.0)) {
weight = el_from_float(0.5);
}
engram_connect(from_id, to_id, weight, relation);
@@ -243,6 +245,34 @@ el_val_t route_forget(el_val_t method, el_val_t path, el_val_t body) {
return 0;
}
el_val_t route_create_ise(el_val_t method, el_val_t path, el_val_t body) {
el_val_t content = json_get_string(body, EL_STR("content"));
if (str_eq(content, EL_STR(""))) {
return err_json(EL_STR("missing content"));
}
el_val_t sal = el_from_float(0.3);
el_val_t imp = el_from_float(0.3);
el_val_t conf = el_from_float(0.8);
el_val_t id = engram_node_full(content, EL_STR("InternalStateEvent"), EL_STR("state-event"), sal, imp, conf, EL_STR("Episodic"), EL_STR("[\"internal-state\",\"InternalStateEvent\"]"));
return el_str_concat(el_str_concat(EL_STR("{\"ok\":true,\"id\":\""), id), EL_STR("\"}"));
return 0;
}
el_val_t route_sync(el_val_t method, el_val_t path, el_val_t body) {
el_val_t dir = env(EL_STR("ENGRAM_DATA_DIR"));
if (str_eq(dir, EL_STR(""))) {
dir = EL_STR("/tmp/engram");
}
el_val_t snap_path = el_str_concat(dir, EL_STR("/sync-export.json"));
engram_save(snap_path);
el_val_t snap = fs_read(snap_path);
if (str_eq(snap, EL_STR(""))) {
return EL_STR("{\"nodes\":[],\"edges\":[]}");
}
return snap;
return 0;
}
el_val_t route_save(el_val_t method, el_val_t path, el_val_t body) {
el_val_t p = json_get_string(body, EL_STR("path"));
if (str_eq(p, EL_STR(""))) {
@@ -299,6 +329,9 @@ el_val_t handle_request(el_val_t method, el_val_t path, el_val_t body) {
return route_health(method, path, body);
}
}
if (str_eq(method, EL_STR("POST")) && str_starts_with(clean, EL_STR("/api/neuron/state-events"))) {
return route_create_ise(method, path, body);
}
if (!check_auth_ok(method, body)) {
return err_json(EL_STR("unauthorized"));
}
@@ -341,6 +374,9 @@ el_val_t handle_request(el_val_t method, el_val_t path, el_val_t body) {
if (str_eq(method, EL_STR("POST")) && (str_eq(clean, EL_STR("/api/strengthen")) || str_eq(clean, EL_STR("/strengthen")))) {
return route_strengthen(method, path, body);
}
if (str_eq(method, EL_STR("GET")) && (str_eq(clean, EL_STR("/api/sync")) || str_eq(clean, EL_STR("/sync")))) {
return route_sync(method, path, body);
}
if (str_eq(method, EL_STR("POST")) && (str_eq(clean, EL_STR("/api/save")) || str_eq(clean, EL_STR("/save")))) {
return route_save(method, path, body);
}
+50
View File
@@ -180,6 +180,43 @@ fn route_forget(method: String, path: String, body: String) -> String {
ok_json()
}
// route_create_ise POST /api/neuron/state-events
// Creates an InternalStateEvent node from a JSON body with a "content" field.
// Returns {"ok":true,"id":"<uuid>"}. Used by the soul daemon's ise_post() to
// record internal state transitions in the authoritative Engram store.
// This route was in the original server.el but was lost during a refactor;
// its absence would break ISE recording on the next Engram restart.
// (Restored 2026-06-30 self-review)
// importance=0.3 matches awareness.el in-process fallback (engram_node_full ISE
// defaults). Original had 0.5 which was a mismatch. (Corrected 2026-06-30)
fn route_create_ise(method: String, path: String, body: String) -> String {
let content: String = json_get_string(body, "content")
if str_eq(content, "") { return err_json("missing content") }
let sal: Float = 0.3
let imp: Float = 0.3
let conf: Float = 0.8
let id: String = engram_node_full(content, "InternalStateEvent", "state-event",
sal, imp, conf, "Episodic", "[\"internal-state\",\"InternalStateEvent\"]")
"{\"ok\":true,\"id\":\"" + id + "\"}"
}
// route_sync GET /api/sync
// Returns the full graph snapshot as JSON (nodes + edges), suitable for loading
// via engram_load_merge. Used by the soul daemon's periodic refresh cycle to
// keep its in-process Engram store in sync with this authoritative HTTP store.
// Saves a temporary snapshot to avoid holding a large in-memory string while
// streaming caller reads the file through the HTTP response body.
// (Restored 2026-06-30 self-review)
fn route_sync(method: String, path: String, body: String) -> String {
let dir: String = env("ENGRAM_DATA_DIR")
if str_eq(dir, "") { let dir = "/tmp/engram" }
let snap_path: String = dir + "/sync-export.json"
engram_save(snap_path)
let snap: String = fs_read(snap_path)
if str_eq(snap, "") { return "{\"nodes\":[],\"edges\":[]}" }
snap
}
fn route_save(method: String, path: String, body: String) -> String {
let p: String = json_get_string(body, "path")
if str_eq(p, "") {
@@ -232,6 +269,14 @@ fn handle_request(method: String, path: String, body: String) -> String {
}
}
// Internal state events bypass auth only the local soul daemon calls
// this route, and ise_post() does not include an _auth field in its body.
// Placing this before the auth gate preserves the old binary's behavior
// and ensures the soul daemon can always write ISEs.
if str_eq(method, "POST") && str_starts_with(clean, "/api/neuron/state-events") {
return route_create_ise(method, path, body)
}
// Auth (when ENGRAM_API_KEY is set)
if !check_auth_ok(method, body) {
return err_json("unauthorized")
@@ -286,6 +331,11 @@ fn handle_request(method: String, path: String, body: String) -> String {
return route_strengthen(method, path, body)
}
// Sync soul daemon fetches here for periodic in-process graph refresh
if str_eq(method, "GET") && (str_eq(clean, "/api/sync") || str_eq(clean, "/sync")) {
return route_sync(method, path, body)
}
// Persistence
if str_eq(method, "POST") && (str_eq(clean, "/api/save") || str_eq(clean, "/save")) {
return route_save(method, path, body)