# KAI Coherence Fix — Phased Implementation Plan

**Date:** 2026-07-02 · **Author:** engineering (planning only — NO code written, engine NOT restarted)
**Based on:** `KAI-COHERENCE-DIAGNOSIS-2026-07-02.md`
**Status of this doc:** plan only. Each phase is a *separate future session*. Nothing here is implemented yet.

> **Purpose.** Fix the "he fails all his tests / he's incoherent" problem in ordered, dependency-sequenced
> phases. Each phase is ONE surgical, reversible, independently-verifiable change small enough that it can't
> cause a mount-truncation or a giant multi-file rewrite. Lower-risk / foundational first; the big risky
> substance change last, sub-phased.

---

## Anchors verified against the REAL Windows files (not the WSL mount)

Every claim below was confirmed with the Read tool against the actual files on 2026-07-02:

| Claim | File:line | Verified |
|---|---|---|
| `synapse_growth` resolver (cells > baseline) | `tools/oracle-discord/shared/drive-system.mjs:320–324` | ✓ |
| `generateSelfPrediction()` registers the two toy predictions | `drive-system.mjs:351–370` (synapse_growth at :362) | ✓ |
| "PREDICTION ACCURACY ALERT … hedge … do NOT speak with authority" injected into prompt | `drive-system.mjs:525` | ✓ |
| Asymmetric self-model update (wrong −0.02 acc / +0.03 bias; right +0.01 / −0.01) | `metacognition.mjs:243–263` (esp. 249 vs 256, 252 vs 259) | ✓ |
| "[META-DRIVE WARNING] … is low" injected into prompt | `metacognition.mjs:304` | ✓ |
| `phi_g` = mean cell confidence; `chi` = fraction of `region=="reasoning"` | `oracle_server.rs:5154–5158` | ✓ |
| Real signal `activation_entropy_norm` + `fixation_risk` already computed | `oracle_server.rs:5179–5217` | ✓ |
| Fake coherence formula `chi*5 + phi_g*2` | `oracle_server.rs:5239` | ✓ |
| Headless server spawns only heartbeat + autosave; supplies `Drive::default()` | `oracle_server.rs:388, 442–444` | ✓ |
| Heartbeat is a "REDUCED model — omits amygdala arousal, serotonin, language tone" | `oracle_server.rs:4200–4202` | ✓ |
| `--oracle` branch loads persistence, heals, calls `start_oracle_server`, `return`s (never enters cognition loop) | `main.rs:10768–10810` | ✓ |
| v9.10.132 brain-safety LOUD-FAIL guard | `src/core/engine.rs:388–421` | ✓ |
| v9.10.132 written but NOT cargo-checked / deployed ("owner must run `cargo check` before deploying") | `The KAI Codex.md:11847–11893`; `Cargo.toml:3 = 9.10.132` | ✓ |

**New finding not in the diagnosis (shapes Phase 0):** the brain-safety guard lives in `Engine::new()`
(`engine.rs:388`), but the production launch is `kai.exe --oracle`, which does **not** call `Engine::new()`.
It calls `kai::persistence::load(&base)` directly (`main.rs:10783`) and, in the `_ =>` arm at
**`main.rs:10789–10793`, silently seeds a fresh `Universe` on any load failure** — the exact silent-reset
behavior v9.10.132 was meant to kill, still live on the headless path. So "deploy the brain fix" is NOT
automatically "production is protected." Phase 0 must verify the guard actually covers the `--oracle` path,
and will likely need to port the same refuse-to-seed guard to `main.rs:10789`.

---

## Standing conventions (apply to EVERY phase)

- **Surgical + additive + flag-gated** where practical. Smallest possible diff. Never wholesale-rewrite
  `oracle.html`, `kaiverse.js`, or any large file.
- **Back up before edit:** copy the target file to `*.bak-2026-07-02` (or dated) before touching it.
- **Mount-truncation caution:** verify edits by re-reading the REAL file with the Read tool; the WSL mount
  can serve stale/NUL-padded snapshots and `node --check` on the mount has produced false truncation reports.
  Validate JS syntax on a verified-content copy.
- **One phase = one Codex + Cargo bump.** After each *code* phase, prepend a CHANGELOG entry, bump the Codex
  `Version`, and bump `Cargo.toml [package] version` to match (they must stay identical). JS-only phases
  still get a Codex entry; bump Cargo only if a Rust rebuild is part of the phase.
- **Isolation from Leo:** none of these phases touch `leo.mjs` or any audio/voice path. Keep it that way —
  do not fold voice work into a coherence phase.
- **Honesty about verification:** the assisting environment has no Rust toolchain and must not stop the
  engine. Rust phases can only be *written and reasoned* here; **`cargo check` + the live restart + watching
  the logs is the owner's job.** Any phase whose success depends on runtime behavior is marked
  "OWNER-VERIFY (live)."
- **Apply/restart per file type:** `*.mjs` → `.\Start-KAI.ps1` (fleet restart). Rust → `cargo build --release`
  then relaunch. `command-center-server.mjs` only → `.\Start-Dashboard.ps1`. Never use `restart-ecosystem`.

---

## Why this order (dependency reasoning)

1. **Phase 0 (brain-safety) is the keystone.** Fair prediction scoring is *impossible* while a restart can
   wipe 397k→10k, because the very thing being scored (`synapse_growth`: "cells above baseline") resolves
   against a wiped lattice and fails deterministically. Continuity must be provably safe before any accuracy
   number means anything. It's also the highest-consequence code path (a wrong touch loses the brain), so it
   goes first and alone.
2. **Then stop the self-sabotage (Phases 1→4), each tiny + reversible.** These are what actively drag the
   scoreboard to the floor and then feed the floor back into KAI's prompt. Ordered *input → integrator →
   output → label*:
   - **P1** removes the rigged *input* (the `synapse_growth` coin-flip). Fixing the integrator before the
     input is pointless.
   - **P2** fixes the *integrator* (the asymmetric self-model math) so scores track real accuracy. Depends on
     P1 so the signal it integrates is honest.
   - **P3** cuts the *output* doom-loop (injecting "you're incoherent, hedge everything" from floored
     metrics). Most defensible once P2 makes the metric trustworthy — but see note: P3 can be pulled earlier
     as pure harm-reduction if the owner wants the bleeding stopped immediately.
   - **P4** replaces the mislabeled *coherence formula* with the real `activation_entropy` signal. Independent
     of P1–P3 (it's Rust/dashboard), but it needs a rebuild, so it's sequenced after Phase 0 is proven and is
     the natural place to batch the first non-brain Rust rebuild.
3. **Then the substance (Phase 5), the big one, sub-phased.** Wiring real cognition into the live headless
   path is the only change that makes KAI *actually* smarter rather than *honestly scored*. It's the largest
   and riskiest, needs the most owner live-testing, and is broken into 5.0 (honesty interim) → 5a (predictor)
   → 5b (amygdala/ToM/dreams).

JS phases (P1–P3) need only a fleet restart and are trivially reversible. Rust phases (P0, P4, P5) need a
rebuild and carry real risk. That reinforces the ordering: prove the brain is safe (P0), bank the cheap
JS wins (P1–P3), then take on Rust rebuilds (P4, P5).

---

## PHASE 0 — Deploy + VERIFY the brain-safety / restart-continuity fix (v9.10.132)

**Goal (one line):** Prove that a restart can no longer silently wipe KAI's lattice — on the *actual*
`--oracle` production path, not just in `Engine::new()`.

**Anchor (verified):** guard in `src/core/engine.rs:388–421`; unguarded silent-seed on the production path at
`src/main.rs:10789–10793`; `--oracle` branch `main.rs:10768–10810`; save path `persistence.rs` (loud-fail
branch per Codex:11867). Version already at `Cargo.toml:3 = 9.10.132`, Codex CHANGELOG `The KAI Codex.md:11847`.

**Scope of the change:** Mostly *deploy + verify what's already written*, plus ONE small additive edit if the
verification shows a gap:
- **0a (verify what exists):** owner runs `cargo check`, then `cargo build --release`, then a controlled
  restart, watching for the LOUD-FAIL banner behavior. No new code if the path is already covered.
- **0b (close the headless gap — only if 0a shows it):** port the same refuse-to-seed guard to the
  `_ =>` arm at `main.rs:10789`. Instead of silently `Universe::new()` + `seed_universe`, it must — when
  state files EXIST but load failed — print the banner and `std::process::exit(1)` unless
  `KAI_ALLOW_MIND_RESET=1`. This is a ~6-line surgical edit mirroring `engine.rs:396–414`. Keep it a separate
  sub-phase so the diff stays tiny and reviewable.

**Risk:** HIGH (touches the boot/persistence path; a mistake here is the exact failure we're preventing).
Mitigated by: it's mostly verification of already-written code; the destructive-seed only triggers on load
failure; `KAI_ALLOW_MIND_RESET=1` is the deliberate escape hatch.

**Dependencies:** none. This is the keystone; everything else assumes it's done.

**How to verify (OWNER-VERIFY, live — cannot be tested headless here):**
1. Confirm a fresh timestamped backup exists first: `C:\KAI\data\_brain-backup-*` (Codex:11880 shows the
   2026-07-02 one). Never test continuity without a current backup.
2. `cargo check` clean, `cargo build --release` clean.
3. **Happy path:** normal `.\Start-KAI.ps1` restart → engine boots, cell count on the dashboard returns to the
   *pre-restart* order of magnitude (NOT 10k). Compare `/api/status` `total_cells` before stop vs after start.
4. **Guard path:** temporarily rename/corrupt a state file (on a COPY of the data dir, or with the backup
   confirmed) → engine must print the BRAIN-SAFETY banner and exit(1), NOT boot empty. Then restore.
5. **Escape hatch:** with `KAI_ALLOW_MIND_RESET=1`, the same corrupted state boots fresh with the
   explicit-approval log lines.
6. Watch a full autosave cycle (180s) + a clean Ctrl-C/SIGTERM stop and confirm the shutdown-flush logs
   success and the on-disk count matches live.

**Rollback:** `git revert` the v9.10.132 commit (and any 0b edit) → rebuild. Because 0b is additive and
gated, reverting it just restores prior behavior. The backup folder is the ultimate net.

**Definition of done for P0:** a restart demonstrably preserves the lattice (live count restored), the guard
demonstrably refuses to boot empty on load failure, and this is confirmed on the `--oracle` path the fleet
actually launches.

---

## PHASE 1 — Kill / repair the rigged `synapse_growth` prediction

**Goal (one line):** Stop scoring KAI on a restart-poisoned counter he doesn't control.

**Anchor (verified):** resolver `drive-system.mjs:320–324`; registration `drive-system.mjs:359–363`
(inside `generateSelfPrediction()` 351–370).

**Scope of the change (JS-only, one file):** In `generateSelfPrediction()`, **stop registering
`synapse_growth`** (delete/comment the `registerDataPrediction(...'synapse_growth'...)` call at :362 and its
`if (fresh(cells)) {...}` wrapper 359–364). Optionally leave the resolver function in `RESOLVERS` harmless/
unused, or replace the prediction with one the lattice actually controls and can be graded on merit — e.g.
"query Q returns a cell with confidence > t" or "the next turn resolves to cluster X." **Recommendation: for
Phase 1 do the minimal safe thing — remove `synapse_growth`, keep `engine_alive`** (a real liveness signal),
and defer the "add a *good* prediction" work to its own later phase so this phase stays a one-hunk deletion.

**Risk:** LOW. Pure removal of a bad signal in one JS file; `engine_alive` still feeds the loop so nothing
divides-by-zero. Reversible by un-commenting.

**Dependencies:** Phase 0 recommended first (so the remaining predictions resolve against a stable brain),
but P1 is safe to land independently since it only *removes* a bad input.

**How to verify:**
- Static: re-read `drive-system.mjs:351–370` on the real file; confirm no `synapse_growth` registration
  remains and the function still compiles (`node --check` on a verified-content copy).
- Live (OWNER-VERIFY): after `.\Start-KAI.ps1`, watch `state/drives.json` for ~15 min — no new
  `synapse_growth` entries appear; `[DriveSystem] ✗ Prediction failed` from that source stops.

**Rollback:** un-comment the removed block; fleet restart.

---

## PHASE 2 — Make the self-model update symmetric / Bayesian

**Goal (one line):** Make accuracy/coherence/usefulness track *real* prediction outcomes instead of
monotonically decaying to the 0.5 floor.

**Anchor (verified):** `metacognition.mjs:243–263` — `updateSelfBias()`. Wrong moves meta-drives −0.02/−0.01
(252–254) while right moves them only +0.01/+0.005 (259–261); biases +0.03/+0.02 wrong vs −0.01/−0.005 right
(249–251 vs 256–258). The 3:1 down:up asymmetry is the decay engine.

**Scope of the change (JS-only, one function):** Replace the asymmetric constant steps with a symmetric or
evidence-weighted estimate. Two options, pick the smaller that satisfies the owner:
- **2-min (symmetric):** make the up-step equal the down-step (e.g. ±0.02 for meta-drives, ∓0.01 for biases)
  so 50% accuracy is a fixed point instead of a sink. ~6 line-edit.
- **2-full (Bayesian, preferred long-term):** maintain a rolling Beta(α,β) over recent correct/incorrect and
  set `meta_drives.accuracy = α/(α+β)`; derive coherence/usefulness similarly. Larger but still one function;
  keep it self-contained so it can't truncate.
- **Also required:** the persisted `state/metacognition.json` is currently floored (`accuracy 0.56,
  usefulness 0.53, coherence 0.53`, `recency_bias 0.74` vs seed 0.3). Symmetric math alone won't un-stick it.
  Include a **one-time re-seed of that state file to neutral seeds** (owner op, back up the file first) OR a
  boot-time "if values are pinned at floor and no fresh evidence, decay toward seed" reset.

**Risk:** LOW–MEDIUM. One JS function + one state-file reseed. Medium only because the reseed touches persisted
self-state; back it up (`metacognition.json.bak-2026-07-02`) first.

**Dependencies:** **Phase 1** (the integrator should integrate an honest signal — no point making the math fair
if `synapse_growth` is still feeding it rigged failures). Phase 0 underneath both.

**How to verify:**
- Static: re-read `metacognition.mjs:243–263`; confirm symmetric/Bayesian update; `node --check` on a copy.
- Simulate offline: feed a scripted 70%-correct sequence through `updateSelfBias` in a scratch node REPL and
  confirm `accuracy` converges toward ~0.70, not toward 0.5. (This CAN be tested outside the engine — do it.)
- Live (OWNER-VERIFY): over a day, `state/metacognition.json` accuracy tracks the real hit-rate of the
  remaining predictions rather than sitting at the floor.

**Rollback:** restore `metacognition.mjs` from `.bak`; restore `metacognition.json` from its backup; restart.

---

## PHASE 3 — Stop injecting "you're incoherent / hedge everything" from floored metrics

**Goal (one line):** Break the self-fulfilling doom loop where floored numbers tell KAI to act incoherent.

**Anchor (verified):** `drive-system.mjs:525` (PREDICTION ACCURACY ALERT … "hedge … do NOT speak with
authority") and `metacognition.mjs:304` ("[META-DRIVE WARNING] … is low").

**Scope of the change (JS-only, two small sites):**
- Gate both injections behind a **confidence/sample-size threshold** so they only fire when the metric is
  trustworthy AND genuinely low — e.g. require ≥ N resolved predictions in the window before emitting the
  ALERT, and require the meta-drive to be low *relative to its own recent baseline*, not just below a static
  0.6/floor. Prefer softening the wording too (the current text is a heavy "hedge everything, no authority"
  command that visibly degrades output).
- Keep it flag-gated: a single const like `INJECT_METACOG_WARNINGS` so the owner can toggle the whole
  behavior off without another edit.

**Risk:** LOW. Prompt-string / threshold logic in two spots. Reversible.

**Dependencies:** best AFTER **Phase 2** (so "low" reflects reality). *May be pulled earlier* as pure
harm-reduction if the owner wants the doom-injection stopped immediately — flag this to the owner as a choice.

**How to verify:**
- Static: re-read both sites; confirm the gate + flag.
- Live (OWNER-VERIFY): with metrics healthy, the ALERT/WARNING strings are absent from KAI's assembled prompt;
  artificially flooring a value (or long genuine underperformance) still surfaces them. Confirm KAI's replies
  stop reflexively hedging.

**Rollback:** restore both files from `.bak`; restart. Or flip the flag off.

---

## PHASE 4 — Replace the fake coherence formula with the real `activation_entropy` signal (relabel honestly)

**Goal (one line):** Make the dashboard "Coherence" number mean something — promote the already-computed
activation-entropy / fixation signal and retire `chi*5 + phi_g*2`.

**Anchor (verified):** fake formula `oracle_server.rs:5239` (`coherence = chi*5.0 + phi_g*2.0`, in
`handle_memory`); real signal `oracle_server.rs:5179–5217` (`activation_entropy_norm`, `fixation_risk`, in
`handle_status`). Note the real signal is currently computed in `handle_status` but the coherence label lives
in `handle_memory` — they're in different handlers.

**Scope of the change (Rust, small but two-handler-aware):**
- Compute `activation_entropy_norm` in `handle_memory` too (lift/duplicate the ~15-line one-pass entropy from
  5168–5182), OR have `handle_memory` read it from a shared source. **Recommendation: duplicate the small
  entropy loop into `handle_memory`** to keep the change local and avoid refactoring shared state (lower
  truncation/coupling risk).
- Change the emitted field: keep raw `chi`/`phi_g` exposed (they're honest as *named*), but set the
  dashboard **"Coherence" = `activation_entropy_norm`** and **relabel the old combo** — either drop it or
  expose it under an honest name (e.g. `reasoning_density_index`). Do the matching label change on the
  dashboard side (`oracle.html`, surgical, hard-refresh — no server restart for the HTML half).
- **Split if needed to avoid truncation:** (4a) Rust — add entropy to `handle_memory` + change the emitted
  `coherence` field; (4b) `oracle.html` — relabel the tile. Two clean single-file edits.

**Risk:** MEDIUM. Requires a Rust rebuild + engine restart (that's the risky part, not the math). The math is
already proven in `handle_status`. Do it only after Phase 0 has proven restart-safety.

**Dependencies:** **Phase 0** (don't rebuild+restart the engine until continuity is proven). Independent of
P1–P3 otherwise.

**How to verify:**
- Static: re-read `handle_memory` post-edit; confirm entropy computed and `coherence` field now carries it.
- Live (OWNER-VERIFY): `/api/memory` JSON shows `coherence` in [0,1] moving with lattice spread, and matching
  the `activation_entropy` already in `/api/status`. Dashboard tile shows the new label. Induce fixation
  (narrow the active set) and confirm the number drops + `fixation_risk` trips.

**Rollback:** `git revert` the Rust edit → rebuild; revert the `oracle.html` label → hard-refresh.

---

## PHASE 5 — Wire the real cognition into the live headless path (LARGEST / RISKIEST — sub-phased)

**Goal (one line):** Make the 24/7 process actually *run* KAI's mind (predictor / amygdala / ToM / dreams),
instead of being memory + telemetry with the cognition as dead code.

**Anchor (verified):** headless `--oracle` returns after `start_oracle_server` and never enters the cognition
loop (`main.rs:10768–10810`); `start_oracle_server` spawns only heartbeat + autosave and supplies
`Drive::default()` (`oracle_server.rs:388, 442–444`); heartbeat self-describes as a REDUCED model
(`oracle_server.rs:4200–4202`). The real `PredictiveEngine`/amygdala/ToM/dreams live only in the interactive
`main.rs` path (diagnosis §4; predictor wired at main.rs interactive path).

**Why this is last and hardest:** it changes what the always-on process *does*, touches the hot engine, has
the largest surface area, and its correctness is almost entirely a *runtime* property the owner must observe.
It is the only phase that risks destabilizing the running system. Do NOT attempt as one edit.

**Sub-phasing (each its own session, each shippable/observable alone):**

- **5.0 — Honest interim (do FIRST, tiny, do even if 5a+ slip).** Until cognition actually runs headless,
  stop presenting it as running. Relabel dashboard/telemetry so "mind/cognition" reflects that the 24/7
  process is *memory + vitals + non-LLM voice*, and the cognitive modules are not executing. Pure
  label/string + doc honesty; no engine behavior change. Risk: LOW. This buys honesty immediately and
  de-risks the rest by removing the pressure to over-claim.

- **5a — Predictor in the headless loop.** Spawn/step the `PredictiveEngine` inside `start_oracle_server`
  (a new background thread beside heartbeat/autosave, or extend the heartbeat), reading the live lattice,
  producing real predictions the drive layer can grade. Replaces the JS toy predictions with a genuine
  engine-side predictor over time. Risk: HIGH (new always-on cognition thread; watch RAM/CPU — recall the
  RSS/clone concerns behind streaming-save at `oracle_server.rs:428–439`). Gate behind an env flag
  (`KAI_HEADLESS_COGNITION=1`) so it's opt-in and instantly disable-able.

- **5b — Amygdala / ToM / dreams.** Only after 5a is stable for days. Add the affective + theory-of-mind +
  dream passes into the headless path, again flag-gated, one module per sub-step (5b-i amygdala/serotonin,
  5b-ii ToM, 5b-iii dreams) so no single edit is large. Risk: HIGH. Each needs its own owner live-test window.

**Dependencies:** Phases 0–4 all done and proven. 5.0 before 5a; 5a stable before 5b; each 5b module serial.

**How to verify (OWNER-VERIFY, live, extended):** per sub-phase — flag OFF must be byte-identical to today's
behavior; flag ON must show the new cognition in telemetry without RAM/CPU regression over a multi-day soak;
predictions (5a) must be gradable and their accuracy must move the (now-symmetric, Phase 2) self-model.

**Rollback:** every sub-phase is env-flag-gated → set the flag off to instantly revert to memory+vitals
behavior; `git revert` the commit to remove the code.

---

## Recommended START POINT

**Start with Phase 0 (deploy + verify the v9.10.132 brain-safety fix — including checking whether the
`--oracle` path at `main.rs:10789` needs the guard ported).**

Why: it's the keystone dependency. Every accuracy/coherence number is meaningless while a restart can silently
wipe 397k→10k, because the flagship test (`synapse_growth`) resolves against the wiped lattice and fails by
construction. It's also the highest-consequence path (a wrong touch loses the brain), the fix is already
*written* and just needs `cargo check` + a careful live restart to confirm, and the newly-found headless
silent-seed gap means "it's written" is not yet "it's protecting production." Prove continuity first; then
the cheap JS self-sabotage fixes (P1–P3) and the honest coherence relabel (P4) can land on solid ground,
before the big cognition-wiring effort (P5).

---

## Definition of DONE for the whole effort — "the scoreboard is honest and coherence is real"

1. **Continuity is safe:** a restart provably preserves the lattice; the engine refuses to boot empty on load
   failure on the *actual `--oracle` production path*. (P0)
2. **No rigged tests:** KAI is no longer scored on the restart-poisoned `synapse_growth` counter; remaining
   predictions are things the lattice controls and can be graded on merit. (P1, and the deferred "add a good
   prediction" follow-up)
3. **The self-model tracks reality:** accuracy/coherence/usefulness converge to the *real* hit-rate (a 70%
   input yields ~0.70), not a monotonic decay to 0.5; the floored `metacognition.json` has been reseeded. (P2)
4. **No doom loop:** KAI is not told he's incoherent by floored metrics; hedging warnings fire only on
   trustworthy, genuinely-low signals. (P3)
5. **Coherence means something:** the dashboard "Coherence" is the real `activation_entropy` integration
   signal (honestly labeled), not `chi*5 + phi_g*2`. (P4)
6. **Honest about the mind:** either real cognition runs in the 24/7 process (P5a/5b) or the telemetry no
   longer claims it does (P5.0) — no phase leaves KAI presented as thinking where he isn't.

**One-line test of done:** *the number on the dashboard that says "Coherence" is a real measurement, the
"Accuracy" number equals KAI's actual prediction hit-rate, and neither can be driven to the floor by a
restart or a rigged update rule.*

---

*Plan only. No code changed, engine not restarted. All runtime claims require the owner's live verification —
the assisting environment has no Rust toolchain and must not stop the running engine.*
