Reconciles PR #105 ("fix: engram search latency — pin embed model, cache
query embeddings, bound activate BFS") with dev's ACTUAL current
engram_activate, rather than the ancient pre-restructure snapshot #105 was
built against.
WHY THIS NEEDED RECONCILIATION, NOT A DIRECT PORT: #105's single commit
(1dc49b1) modifies `lang/el-compiler/runtime/el_runtime.c` — a path that does
not exist on dev (dev has `lang/runtime/el_runtime.c`; the restructure that
renamed it happened after #105's branch point, which traces to a July 22
merge-base, weeks before the M8/M8.1/qgate/fan-effect/adjacency-index work
this file has grown since). #105's own engram_activate is consequently the
PRE-restructure version: no adjacency index (O(E) full edge scan per hop),
no query-aware qgate, no ACT-R fan effect, no eg_edge_eff_weight, and no
awareness of dev's cosq/e_eff embedding-blend semantic layer — it built a
parallel `g_qcache`/`engram_embed_raw` mechanism from scratch against code
that no longer exists at that path. A raw merge/cherry-pick was not possible
and would have been wrong even if it were: taking #105's tree wholesale would
have thrown away everything dev grew in the meantime (qgate, fan effect,
adjacency index, and this session's own M8 HNSW vindex integration).
RECONCILIATION: kept dev's cosq/e_eff mechanism as the semantic layer
entirely intact (unchanged by this commit) and ported #105's three genuinely
additive wins on TOP of it, at their equivalent sites in the CURRENT
eg_embed_fetch/engram_activate:
1. keep_alive:-1 on the Ollama embed request body (eg_embed_fetch) — pins
the embed model resident so a larger generation model loading under
unified-memory pressure can't evict it and force a cold reload on the
next search (#105 measured ~2.2s cold vs ~0.02-0.05s warm).
2. Query-embedding cache upgraded from dev's single-slot (`_eg_qcache_text`,
only ever remembered the LAST query) to a direct-mapped, FNV-1a-keyed,
1024-slot cache (reusing the existing engram_id_hash) — so the
curiosity loop's rotating phrases actually hit the cache instead of
evicting each other every call. Same "pointer owned by the cache, not
freed by caller" contract as before, just per-slot instead of global.
3. Beam cap on the layer-1 spreading-activation BFS (new
engram_activate_beam(), tunable via ENGRAM_ACTIVATE_BEAM, default 128).
The FIFO frontier is processed in hop-level batches (entries sharing
.hops are provably contiguous — see the code comment); when a level
exceeds the beam width, only the top-`beam` by activation actually
EXPAND. Every node in an oversized level still gets reached[]/best_bg[]
recorded (that happens at enqueue time, one level up) and appears in
the reported/promoted set — the cap bounds associative SPREAD width
only, never recall of what was already found. Kept as a genuine
additional bound even though the adjacency index + qgate + fan effect
already mitigate #105's original "hub-node explosion" failure mode for
a different reason: those prune WHICH targets matter; this bounds
worst-case width regardless.
Everything else in dev's engram_activate — cosq/e_eff, the qgate rescale,
the fan effect, eg_edge_eff_weight, the M8 HNSW vindex seed discovery from
the #109 reconciliation earlier this session — is untouched.
VERIFIED (nsbx sandbox only, live :8742/:7770 never touched): cc -std=c11
-O2 clean build; booted in an isolated sandbox against a real cloned
production snapshot (13,424 nodes / 37,656 edges); ran 5 activate() calls
across rotating queries at depth 3, including the same query issued twice
non-consecutively (2nd hit landed at 476ms vs the 1st at 483ms — consistent
with a cache hit once Ollama's own warm-model latency is accounted for; no
crash, correct varied result counts (367-2610 nodes) each call; act-stats
JSON read correctly throughout.
Built on top of the M8/#109 reconciliation (bacaf3d, merged to dev as
#109) — dev's current HEAD at the time of this commit.