diff --git a/engram/dist/engram b/engram/dist/engram index 1d7defa..f848140 100755 Binary files a/engram/dist/engram and b/engram/dist/engram differ diff --git a/lang/releases/v1.0.0-20260501/el_runtime.c b/lang/releases/v1.0.0-20260501/el_runtime.c index 5d6ad3f..eb74eeb 100644 --- a/lang/releases/v1.0.0-20260501/el_runtime.c +++ b/lang/releases/v1.0.0-20260501/el_runtime.c @@ -6022,10 +6022,17 @@ static int64_t _eg_embed_breaker_until = 0; * The executive-filter pathologies this system has repeatedly debugged by * inference (WM flooded with breakthrough-floor nodes, silent cap evictions, * embedder wedged behind the breaker) were all invisible: no ISE, no stats - * field. These per-call counters record what the LAST engram_activate did; - * engram_act_stats_json() exposes them so the soul heartbeat can emit them. */ -static int64_t _eg_act_breakthroughs = 0; /* forced promotions at the floor */ -static int64_t _eg_act_wm_evicted = 0; /* Pass 4 over-cap evictions */ + * field. engram_act_stats_json() exposes them so the soul heartbeat can emit + * them. + * + * CUMULATIVE CONTRACT (2026-07-31 self-review): these are monotonic totals + * for the process lifetime, like pulse/sync_added_total — NOT per-call. The + * original per-call reset meant engram_act_stats_json only reported the LAST + * activate call, and the 60s heartbeat (2 curiosity activates per 30s in + * between) missed nearly every eviction/breakthrough event. Consumers wanting + * rates keep the previous reading and diff. Restart legitimately resets to 0. */ +static int64_t _eg_act_breakthroughs = 0; /* forced promotions at the floor, cumulative */ +static int64_t _eg_act_wm_evicted = 0; /* Pass 4 over-cap evictions, cumulative */ static int64_t engram_now_ms(void); /* defined in the store section below */ @@ -6724,7 +6731,7 @@ static el_val_t engram_node_to_map(const EngramNode* n) { /* (Node JSON serialization is provided by `engram_emit_node_json` further * down in the persistence section — reused by the *_json builtins below.) */ -static void engram_emit_node_json(JsonBuf* b, const EngramNode* n); +static void engram_emit_node_json(JsonBuf* b, const EngramNode* n, int include_emb); static void engram_emit_edge_json(JsonBuf* b, const EngramEdge* e); /* Salience may arrive either as a float bit-pattern or as a small integer @@ -7659,9 +7666,11 @@ el_val_t engram_activate(el_val_t query, el_val_t depth) { int64_t now_ms = engram_now_ms(); - /* Reset per-call observability counters (2026-07-27). */ - _eg_act_breakthroughs = 0; - _eg_act_wm_evicted = 0; + /* Observability counters: _eg_act_breakthroughs/_eg_act_wm_evicted are + * CUMULATIVE for the process lifetime and intentionally NOT reset here + * (2026-07-31 self-review — the old per-call reset made the 60s heartbeat + * miss nearly all events between beats; see the definition site). + * ctx_cos stays per-call: it is a gauge of THIS query vs the centroid. */ _eg_act_ctx_cos = -2.0; /* ── Embedding backfill + query embedding (2026-07-24, bl-b2d1c944) ── @@ -8411,7 +8420,13 @@ el_val_t engram_activate(el_val_t query, el_val_t depth) { /* ── Engram persistence (JSON snapshot) ─────────────────────────────────── */ -static void engram_emit_node_json(JsonBuf* b, const EngramNode* n) { +/* include_emb (2026-07-31 self-review): the ~5.7KB "emb" vector belongs ONLY + * in persistence/replication output (engram_save → snapshot.json, which also + * backs /api/sync and /api/edges via scratch exports). Consumer read routes + * (/api/nodes, /api/search, activation results, neighbors, compiled context) + * were shipping it on every node — responses 10-50x oversized, blowing MCP + * token limits. Pass include_emb=1 only from engram_save. */ +static void engram_emit_node_json(JsonBuf* b, const EngramNode* n, int include_emb) { jb_putc(b, '{'); jb_puts(b, "\"id\":"); jb_emit_escaped(b, n->id ? n->id : ""); jb_puts(b, ",\"content\":"); jb_emit_escaped(b, n->content ? n->content : ""); @@ -8454,7 +8469,7 @@ static void engram_emit_node_json(JsonBuf* b, const EngramNode* n) { * insensitive to 4-sig-fig rounding, and this keeps snapshot bloat to * ~5KB per embedded node without a base64 codec. Absent field = not * embedded; the lazy backfill re-embeds eventually if dropped. */ - if (n->emb && n->emb_dim > 0) { + if (include_emb && n->emb && n->emb_dim > 0) { jb_puts(b, ",\"emb\":\""); for (int32_t j = 0; j < n->emb_dim; j++) { snprintf(tmp, sizeof(tmp), "%s%.4g", j ? "," : "", @@ -8492,7 +8507,7 @@ el_val_t engram_save(el_val_t path) { jb_puts(&b, "{\"nodes\":["); for (int64_t i = 0; i < g->node_count; i++) { if (i > 0) jb_putc(&b, ','); - engram_emit_node_json(&b, &g->nodes[i]); + engram_emit_node_json(&b, &g->nodes[i], 1); } jb_puts(&b, "],\"edges\":["); for (int64_t i = 0; i < g->edge_count; i++) { @@ -9025,7 +9040,7 @@ el_val_t engram_get_node_json(el_val_t id) { EngramNode* n = engram_find_node(sid); if (!n) return el_wrap_str(el_strdup("{}")); JsonBuf b; jb_init(&b); - engram_emit_node_json(&b, n); + engram_emit_node_json(&b, n, 0); return el_wrap_str(b.buf); } @@ -9050,7 +9065,7 @@ el_val_t engram_get_node_by_label(el_val_t label) { EngramNode* n = &g->nodes[i]; if (n->label && strcmp(n->label, lbl) == 0) { JsonBuf b; jb_init(&b); - engram_emit_node_json(&b, n); + engram_emit_node_json(&b, n, 0); return el_wrap_str(b.buf); } } @@ -9091,7 +9106,7 @@ el_val_t engram_search_json(el_val_t query, el_val_t limit) { int64_t end = nhits < lim ? nhits : lim; for (int64_t k = 0; k < end; k++) { if (!first) jb_putc(&b, ','); - engram_emit_node_json(&b, &g->nodes[hits[k].idx]); + engram_emit_node_json(&b, &g->nodes[hits[k].idx], 0); first = 0; } free(hits); @@ -9123,7 +9138,7 @@ el_val_t engram_scan_nodes_json(el_val_t limit, el_val_t offset) { int first = 1; for (int64_t i = off; i < end; i++) { if (!first) jb_putc(&b, ','); - engram_emit_node_json(&b, &g->nodes[idx[i]]); + engram_emit_node_json(&b, &g->nodes[idx[i]], 0); first = 0; } free(idx); @@ -9160,7 +9175,7 @@ el_val_t engram_scan_nodes_by_type_json(el_val_t type_v, el_val_t limit, el_val_ int first = 1; for (int64_t i = off; i < end; i++) { if (!first) jb_putc(&b, ','); - engram_emit_node_json(&b, &g->nodes[idx[i]]); + engram_emit_node_json(&b, &g->nodes[idx[i]], 0); first = 0; } free(idx); @@ -9224,7 +9239,7 @@ el_val_t engram_neighbors_json(el_val_t node_id, el_val_t max_depth, el_val_t di if (!n) continue; if (!first) jb_putc(&b, ','); jb_puts(&b, "{\"node\":"); - engram_emit_node_json(&b, n); + engram_emit_node_json(&b, n, 0); jb_puts(&b, ",\"edge\":"); engram_emit_edge_json(&b, e); char tmp[64]; snprintf(tmp, sizeof(tmp), ",\"hops\":%lld}", (long long)(h + 1)); @@ -9267,7 +9282,7 @@ el_val_t engram_activate_json(el_val_t query, el_val_t depth) { if (i > 0) jb_putc(&b, ','); jb_puts(&b, "{\"node\":"); if (n) { - engram_emit_node_json(&b, n); + engram_emit_node_json(&b, n, 0); } else { jb_puts(&b, "{}"); } @@ -9404,9 +9419,11 @@ el_val_t engram_stats_json(void) { return el_wrap_str(el_strdup(buf)); } -/* engram_act_stats_json — per-call activation observability + embedder - * breaker state. (2026-07-27 self-review.) wm_evicted/breakthroughs describe - * the LAST engram_activate call on this store; embed_breaker_open=1 means +/* engram_act_stats_json — activation observability + embedder breaker state. + * (2026-07-27 self-review; counters made cumulative 2026-07-31.) + * wm_evicted/breakthroughs are monotonic process-lifetime totals across ALL + * engram_activate calls on this store (diff successive readings for rates; + * they reset to 0 only on restart); embed_breaker_open=1 means * eg_embed_fetch is currently refusing calls (semantic activation silently * degraded to lexical until the cooldown expires). The soul heartbeat folds * this into its ISE so the pathologies are diagnosable from telemetry @@ -9593,7 +9610,7 @@ el_val_t engram_compile_layered_json(el_val_t intent, el_val_t depth) { jb_puts(&b, "[LAYER 0 — STRUCTURAL]\n"); wrote_layer0 = 1; } - engram_emit_node_json(&b, n); + engram_emit_node_json(&b, n, 0); jb_putc(&b, '\n'); } @@ -9606,7 +9623,7 @@ el_val_t engram_compile_layered_json(el_val_t intent, el_val_t depth) { jb_puts(&b, "[ENGRAM CONTEXT]\n"); wrote_normal = 1; } - engram_emit_node_json(&b, n); + engram_emit_node_json(&b, n, 0); jb_putc(&b, '\n'); } @@ -9656,7 +9673,7 @@ el_val_t engram_query_range(el_val_t start_ms_v, el_val_t end_ms_v) { jb_putc(&b, '['); for (int64_t i = 0; i < mc; i++) { if (i > 0) jb_putc(&b, ','); - engram_emit_node_json(&b, &g->nodes[idx[i]]); + engram_emit_node_json(&b, &g->nodes[idx[i]], 0); } jb_putc(&b, ']'); free(idx);