# Engram Tiered Storage — M8 Performance Profile (milestone-0 sample)

**Milestone:** M8 (ANN wired into `engram_activate` seed selection). Trunk =
worktree `/tmp/engram-tiered-wt`, branch `engram-tiered-storage`, HEAD `1507614`.
**Date:** 2026-08-12. **Author:** first full-binary build + profile of the tiered trunk.

This is **sample zero** of an accumulating per-milestone profile series (see the
BUILD-LEDGER "keep performance telemetry CONTINUOUSLY" decision). Compare future
milestones (M9, M10, …) against these numbers.

## Methodology (read this before trusting a number)

- **On a COPY, never live.** All runtime measurements used a read-only copy of the
  live store booted on a **non-live port (:8798)** with a **throwaway `$HOME`**. The
  live engram service (:8742, `~/.neuron/engram`) was never touched.
- **Two store substrates were used:**
  1. *Live-egm copy* (`neuron.egm` 458 MB + `neuron.wal` 44 MB, copied read-only) —
     **this substrate crashes both the M8 binary and the live binary on boot** (see
     Integration Findings). Unusable for runtime measurement.
  2. *Clean import* — a dir seeded with only `snapshot.json` (65 MB, stable 06:10),
     which the binary imported into a **fresh 59.9 MB `neuron.egm`**. All healthy
     runtime numbers below are from this substrate (real graph content, healthy store).
- **Build machine:** Apple Silicon (arm64), macOS. Native `cc -O2` compile; fold done
  in a memory-capped (`--memory=3g --memory-swap=3g`, no swap) `linux/amd64` container
  running `elc-linux-amd64`.
- Hardware/thermals uncontrolled; single run per metric unless noted. Treat as
  order-of-magnitude, not benchmark-grade, except the module benchmark (Test suite).

## Build

| Metric | Value |
|---|---|
| Fold input | `engram/src/server.el` (44,273 B El, no imports) |
| Fold output | `engram.c` (30,855 B, 645 lines C), `ELC_EXIT=0`, **0 fold warnings** |
| Fold time (pure elc) | sub-second (server.el is small, importless) |
| Fold container wall | ~38 s (dominated by one-time `apt-get install libcurl4` in the throwaway container; the elc invocation itself is <1 s) |
| Compile | `cc -O2 -DHAVE_CURL engram.c el_runtime.c engram_store.c engram_vindex.c -lssl -lcrypto -lcurl -lpthread -lm` |
| Compile time | **1.83 s** wall |
| Compile warnings | **3**, all `-Wparentheses-equality` in the *folded* `engram.c` (El if-expr codegen emits `if ((x == 0))`); cosmetic. `el_runtime.c` / `engram_store.c` / `engram_vindex.c` compiled **0 warnings** — notably none around the M8 deferred `free(e_eff)` or the vindex integration. |
| Binary | **482,008 B (471 KB)** Mach-O arm64 executable |
| ANN linkage verified | `nm`: `vindex_search`, `vindex_build_from_store`, `eg_vindex_sync`, `_eg_vindex`, `store_scan_nodes`, `engram_store_boot`, `engram_activate` all present |

## Boot & footprint (clean-import substrate)

| Metric | Value |
|---|---|
| Boot from healthy `neuron.egm` | **~2 s** to listening |
| Boot from `snapshot.json` (one-time import + fresh egm) | **~9 s** |
| node_count | **13,036** (matches ledger import-dedup: 13,038 snapshot − 2 dup-id entries) |
| edge_count / layer_count | 43,402 / 5 |
| embedded_count | 4,190 |
| Fresh egm size | **59.9 MB** (vs the live egm's bloated 458 MB — see Findings) |
| RSS after boot | **126.2 MB** (whole 13k-node/43k-edge/4,190-emb graph resident + fresh egm) |

## Activation latency — q="bullshit" (clean-import substrate)

50 sequential `GET /api/activate?q=bullshit&limit=10&depth=3`:

| Metric | Value |
|---|---|
| p50 | **34.35 ms** |
| p95 | **35.26 ms** |
| min / max | 33.50 ms / 9,886 ms |
| Sample | n=50 |

- The **max = 9.9 s is the first call only** — a cold query-embedding fetch
  (`eg_embed_fetch` → Ollama `nomic-embed-text`, cold model load). All subsequent
  calls hit the single-slot query-embedding cache (`_eg_qcache`) → **34 ms steady state**.
- **This 34 ms is the lexical/spread path, NOT the ANN seed path.** The store's 4,190
  embeddings were generated by the live neuron's native embedding model; the harness's
  `nomic-embed-text` query vectors are a **different vector space**, so no candidate
  cleared `ENGRAM_EMBED_SEED_MIN=0.60` (`act-stats`: `dup_seeds:0`, `ctx_cos:-2.000`
  sentinel) → results empty, ANN discovery produced no admitted seeds. Environmental
  (embedding provenance), **not** an M8 defect. The ANN wiring still *executed*
  (embed fetch succeeded, `embed_breaker_open:0`; `eg_vindex_sync` + seed block +
  `free(e_eff)` all ran) **without crashing** on the real store.

## KEY M8 METRIC — ANN vs O(n) seed selection (authoritative)

Because the HTTP path can't exercise ANN seeding without embedding-space parity, the
authoritative ANN-vs-exact-scan numbers come from the **module benchmark**
(`engram/test/run_vindex_tests.sh`, PASS 1, optimised), which measures the exact
`vindex_search` code the M8 wiring calls, at full size:

| N (768-dim vectors) | Brute-force (O(n)) | ANN (HNSW) | **Speedup** |
|---|---|---|---|
| 5,000 | 3.475 ms/query | 0.353 ms/query | **9.8×** |
| 20,000 | 13.809 ms/query | 0.698 ms/query | **19.8×** |

- **recall@10 = 0.9365** at `ef_search=128` (gate ≥0.90 — **PASS**). Lower ef trades
  recall for latency: ef=64→0.844, ef=32→0.750, ef=10→0.625.
- **Determinism:** two independent seeded builds give byte-identical query results.
- **`vindex_build_from_store`** over a real `engram_store`: inserts exactly the
  embedded nodes, top-1 resolves to the correct node id at ~0 distance.
- **HNSW build cost (single-threaded, note for boot/index-build budgeting):**
  5,000 vectors ≈ 15–35 s, 20,000 vectors ≈ 75 s. In-process the index is built
  **lazily on first activation** (`eg_vindex_sync`) and grown incrementally; the
  M8 seed block only fires once `vindex_size ≥ ENGRAM_EMBED_SEED_K`. At the real
  store's 4,190 embedded nodes this is a **one-time few-second first-activation
  cost** — worth watching as the embedded set grows (a future milestone may want
  to build the index at boot or persist it via `vindex_save`/`vindex_load`).

## Seed-set parity note (why there is no runtime A/B toggle)

M8 has **no ANN on/off env flag** by design (`ENGRAM_EMBED_SEED_K` is a compile-time
constant). The exact O(n) cosine scan is **preserved verbatim** and "tops up" any seed
slot the ANN leaves unfilled; every ANN candidate is admitted through the *identical*
cosine/dedup/threshold gate the exact scan uses. So ANN changes only *which nodes are
discovered and how fast*, never the final seed set — parity is **structural**, not
A/B-tested via flag. Recovered-behaviour-when-index-absent is the pre-M8 exact scan.

## Integration Findings (first full build of the tiered trunk)

1. **CRITICAL / pre-existing (NOT M8): `btree_insert` stack-buffer-overflow on
   opening the live 458 MB `neuron.egm`.** `SIGABRT` (`__stack_chk_fail`) via
   `btree_insert ← btree_put ← edge_place/apply_edge_put ← engram_open ←
   engram_store_boot`. Reproduces on the M8 binary **and** the deployed live binary —
   **the live engram :8742 was crash-looping (18 crash reports 16:18→17:44 on this
   date; service refusing connections).** A clean import into a fresh 59.9 MB egm does
   **not** crash (43k edges load fine), so the trigger is the specific pathological
   live store: 458 MB (8× the healthy 59.9 MB) from a day of churn/tombstones with no
   M5 compaction + a 44 MB un-checkpointed WAL replayed on open. The bug is in
   `engram_store.c` (the edge B-tree / WAL-redo path), **upstream of everything M8
   touched** (M8 lives in `el_runtime.c::engram_activate`). Fix required before any
   re-cutover; `btree_insert` must bound-check regardless of on-disk content.
2. **M8 deferred `free(e_eff)`** (the flagged memory-management concern): compiled
   warning-free, and the wired path executed end-to-end over HTTP on the real store
   (with a real query embedding) with **no crash / no new crash report** — no
   double-free or use-after-free observed. Freed on all early-return paths and exactly
   once post-seed-selection.
3. **Write durability + retrieval-fix dedup**: create → checkpoint → clean SIGTERM →
   restart → node found **by id and by search** (node_count 13,036→13,037 preserved).

## Caveats

- All on a copy; healthy-substrate numbers are from a re-imported store, not the live
  paged store (which is currently un-bootable — Finding 1).
- Single-run metrics; no thermal control.
- Embedding-space mismatch prevented a real semantic `q=bullshit` activation in this
  harness; the ANN speedup number is the module benchmark, which is the correct gauge.
