# M-INTEROCEPTION — flags, defaults, and reversal runbook

Branch `engram-tiered-storage` (worktree `/tmp/engram-tiered-wt`), on trunk
`f6a0777`. Six faces, each its own commit. Every behavior-changing feature is
behind an env flag **default OFF = byte-identical to trunk** (proven per face);
the read-only builtins are purely additive. NOT pushed, NOT tagged. The live
`:8742` daemon, `~/.neuron/engram`, and launchctl were never touched — all
verification ran on copies with throwaway HOME + /tmp dirs.

The server binary was rebuilt from the **byte-unchanged** `engram/dist/engram.c`
plus the modified runtime and links cleanly, so these changes integrate into the
real server without regenerating dist. Two HTTP routes are **deferred to cutover**
because regenerating dist from `server.el` drifts ~285 lines with no source
change (the prebuilt elc is a Linux x86-64 binary; a locally-built elc is a
different compiler revision). The C builtins behind those routes are complete
and tested via pure-C harnesses.

## Flags

| Flag | Default | Face | Effect when set |
|------|---------|------|-----------------|
| `ENGRAM_CONSOLIDATION` | `0` (off) | P1 | Enables the two-threshold promotion layer (ISE connection edges + permanence marking). |
| `ENGRAM_CONSOL_CONN_MIN` | `0.6` | P1 | ISE salience needed to form connection edges. |
| `ENGRAM_CONSOL_PERM_MIN` | `0.9` | P1 | ACT-R base-level needed to mark a node durable. |
| `ENGRAM_CONSOL_WM_TOPK` | `5` | P1 | Max wm_top nodes a strong ISE wires to. |
| `ENGRAM_CHRONOCEPTION` | `0` (off) | P2 | Enables field aging (`engram_age_field`) + reboot catch-up. |
| `ENGRAM_CHRONO_TC` | `3600` (s) | P2 | Field cooling time-constant for `exp(-dt/TC)`. |
| (none) | — | P0, P3, P4, P5 | Additive read-only builtins / observability; no flag. |

With all flags unset the runtime is byte-identical to trunk except for P4, which
adds five backward-compatible fields to `/api/act-stats` (pure observability).

## Faces, commits, and how to disable / revert

| Face | Commit | Disable (no revert) | Revert |
|------|--------|---------------------|--------|
| P0 embeddings builtin `engram_scan_nodes_emb_json` | `c20cb3b` | n/a (additive, unused until route wired) | `git revert c20cb3b` |
| P1 two-threshold consolidation | `5f6ce5c` | leave `ENGRAM_CONSOLIDATION` unset | `git revert 5f6ce5c` |
| P2 chronoception field aging | `0af39df` | leave `ENGRAM_CHRONOCEPTION` unset | `git revert 0af39df` |
| P3 drift-sensor primitive `engram_geo_displacement` | `816b258` | n/a (pure fn, only called if wired) | `git revert 816b258` |
| P4 afferent counters in act-stats | `65ca0a3` | n/a (always on; observability only) | `git revert 65ca0a3` |
| P5 dream-recall builtin `engram_dreams_json` | `77a4bc9` | n/a (additive, unused until route wired) | `git revert 77a4bc9` |

Reverts are independent and can be applied in any order (no cross-face code
dependencies; each touches distinct functions).

## Data-side reversibility

- **P1 connection edges** carry `relation="hebbian-associate"`, `metadata`
  `{"origin":"consolidated-from-ISE"}`. Remove all with one query over that
  marker. They are also swept automatically with their ISE at the 48h prune
  unless the ISE was promoted to permanence.
- **P1 permanence** marks a node durable via the metadata marker
  `consolidated-from-ISE`. Demote by clearing the marker; the node then becomes
  prunable again. No struct/schema change — the marker rides in existing
  metadata and survives the store round-trip.
- **P2 last-tick** persists to a sidecar file `chrono_last_tick` in the data
  dir. Delete it to reset catch-up; it is written only when the flag is set.

## Deferred to cutover (elc-drift blocker)

- `GET /api/embeddings` and `GET /api/graph/dump` → back onto
  `engram_scan_nodes_emb_json` (P0).
- `GET /api/dreams?since=` → back onto `engram_dreams_json` (P5).

Wire by hand-patching `engram/dist/engram.c` surgically (mirror an existing
route like `route_scan_nodes`), leaving all other dist lines byte-identical, and
editing `server.el` as source of truth. Do NOT full-regenerate dist.

## Known follow-up (P3, honestly flagged)

The drift sensor primitive is complete and tested, but a **live** self-drift
reading needs a persisted `SelfAnchor` baseline descriptor to compare "now"
against, and **no persisted self node / anchored self-neighborhood exists yet**.
A self was NOT fabricated. Capturing a durable SelfAnchor snapshot and wiring an
`ENGRAM_DRIFT_SENSOR` live reading is the remaining work before P3 goes live.
