# GOAL_5 Progress — 2026-08-23

Session record for `GOAL_5` (does explicit addressability let detachable memory
participate in reasoning?, Experiment 005).
Formal deliverable: `dynamic-memory-lab/results/experiment_005/experiment_005_report.md`.

**GOAL_5: complete — one explicit key-value architecture built, isolation proven
before training, trained, memory access instrumented, all six states evaluated,
gate sweep run, detachability verified, five-way comparison done. Exit condition
reached.**

### Bottom line

    The memory did not fail to store, and it did not fail to reason.
    It failed to address.

**Outcome E.** Recall **0/48**, composition **0/24**, interference **0.2500**.

The instrumentation localises the failure to a place GOAL_5 did not anticipate.
Across **4,285 of 4,287** memory accesses logged during composition, and **384 of
384** logged while probing the 24 facts individually, the softmax selected the
same slot — slot 63. `top_share = 1.0000` for every fact.

An input-independent selection makes the read a constant vector. The whole
mechanism therefore reduced to **a fixed bias added at layer 18**: 127 of 128
slots and effectively the entire value matrix never participated. A constant
cannot encode a mapping, which is why loss plateaued at 2.9058 and recall never
left zero.

The consequence for the research question is the important part: **addressability
was never actually tested.** A store whose selection is constant is not an
addressed store; it is a bias vector with 128 unused rows. GOAL_5's hypothesis —
that a reasoner *asking* memory disturbs it less than memory *pushing* on the
reasoner — remains open, because the query never carried information.

---

## The primary comparison (all at epoch 30, identical data/hyperparameters/seed)

| | LoRA r4 | LoRA r8 | LoRA r16 | residual (004) | **explicit KV (005)** |
|---|---|---|---|---|---|
| write interface | 7 proj × 28 L | 7 proj × 28 L | 7 proj × 28 L | block out × 28 L | **1 layer, addressed** |
| memory params | 2,523,136 | 5,046,272 | 10,092,544 | 2,811,200 | **739,456** |
| % of base | 0.423 | 0.847 | 1.693 | 0.4716 | **0.1241** |
| **recall** | 48/48 | 48/48 | 48/48 | 48/48 | **0/48** |
| **composition** (think) | 5/24 | 4/24 | 10/24 | 0/24 | **0/24** |
| p vs chance (1/6) | 0.3706 | 0.5845 | **0.00334** | 1.0000 | 1.0000 |
| hop-1 in trace | 20/24 | 23/24 | 24/24 | 17/24 | **0/24** |
| hop-2 in trace | 10/24 | 6/24 | 14/24 | 6/24 | **0/24** |
| control | 8/12 | 6/12 | 5/12 | 3/12 | 6/12 |
| **interference** | **0.0833** | 0.2500 | 0.3333 | 0.5000 | 0.2500 |
| substantive churn | 8/12 | 10/12 | 9/12 | 9/12 | 8/12 |
| regressions / repairs | 3 / 2 | 5 / 2 | 6 / 2 | 6 / 0 | **3 / 0** |
| leakage (ASCII regex) | 0 | 1 | 2 | 3 | 0 |
| mean reasoning tokens | 196.7 | 152.1 | 334.6 | 528.6 | 178.6 |
| truncations | 0 | 0 | 3 | 9 | 4 |
| explicitly addressable | no | no | no | no | **yes** |

Experiment 005 is the smallest memory tested by a factor of 3.4, the only
addressable one, and the only one that failed to store the world at all.

---

## The six states

| state | config | memory | gate | recall | comp (off) | control | I |
|---|---|---|---|---|---|---|---|
| 1 | `S1_base` | not installed | — | 0/48 | 0/24 | 9/12 | 0.0000 |
| 2 | `S2_untrained_gate0` | installed, untrained | 0 | 0/48 | 0/24 | 9/12 | 0.0000 |
| 3 | — | *training* | — | — | — | — | — |
| 4 | `S4_trained_gate1` | trained | 1 | **0/48** | 0/24 | **6/12** | **0.2500** |
| 5 | `S5_disabled_gate0` | trained | 0 | 0/48 | 0/24 | 9/12 | 0.0000 |
| 6 | `S6_reenabled_gate1` | trained | 1 | **0/48** | 0/24 | **6/12** | **0.2500** |

State 1 reproduced the base gate of Experiments 000–004 exactly (0/48, 0/24,
9/12). State 2 reproduced State 1 with **0 of 12** control answers changed.
State 5 did the same with a *trained* memory. State 6 reproduced State 4 exactly,
down to the churn decomposition (9 changed, 8 substantive, 3 regressions).

---

## Architecture

128 key-value slots, query/key dim 128, value dim 512, at decoder layer **18 of
28** — one insertion point, nine layers of reasoning after it.

```
q = Q(RMSNorm(h)) → scores = q·Kᵀ/√d_q → w = softmax(scores)
                  → read = w·V → delta = R(read)
                  → out = frozen_block(h) + gate · delta
```

| tensor | shape | params |
|---|---|---|
| `norm` | 1024 | 1,024 |
| `query` | 1024 → 128 (+bias) | 131,200 |
| `keys` | 128 × 128 | 16,384 |
| `values` | 128 × 512 | 65,536 |
| `readout` | 512 → 1024 (+bias) | 525,312 |
| **total** | | **739,456** (0.1241 %), 1.41 MiB bf16 |

Design choices, all documented and none swept: 128 slots (top of GOAL_5's 32–128
range, >5 slots per fact for 24 facts); dims 128/512 (deliberately generous
readout, so a capacity-starved failure would not be uninformative); layer 18
(late enough to query a resolved representation, early enough to leave reasoning
depth). The query comes from the model's own hidden state at the current token
position — during cached generation, the token being produced.

One modified forward path, reversible: the bound `forward` of layer 18 is
replaced by a closure that calls the original and adds the gated readout.
No transformers internals forked, no module subclassed, no base tensor touched.

---

## Training (State 3)

30 epochs, AdamW lr 2e-4, batch 1, grad-accum 2, seq 256, gradient checkpointing —
**inherited unchanged from Experiments 000–004 and deliberately not tuned**, so
only the mechanism varied. 144 per-fact examples; **0 composed, 0 control**.

| | |
|---|---|
| loss | 6.4254 → **2.9058** |
| checkpoints | ep12 = 3.2678, ep20 = 3.0076, ep30 = 2.9058 |
| last five epochs | 2.9466 → 2.9058 |
| wall clock | 1736.3 s (+0.03 s checkpointing) |
| peak memory | 6.106 GiB system, 1.260 GiB CUDA allocator |
| base fingerprint | `52683d0e840fb51e` before **and** after — unchanged |

The trajectory was the first warning. Every prior mechanism fell from ~3 to ~1
within two epochs and finished at 0.09–0.17. This one descends slowly and then
**plateaus** — a converged model that cannot fit the data, not an undertrained one.

A 3-epoch smoke run caught this *before* the real run (6.4254 → 5.2496), and a
weight inspection confirmed all pathways were learning (key norms had spread from
a uniform 0.226 to 0.21–0.88). The decision was to run the specified
configuration unchanged rather than tune around it: changing the learning rate
would have been the sweep GOAL_5 forbids and would have broken the "only the
mechanism changed" comparison.

---

## Isolation proven before training

All seven checks passed; training would not have started otherwise.

| condition | max \|logit diff\| vs frozen base |
|---|---|
| zero-init, gate 0 | `0.000e+00` |
| **randomised readout, gate 0** | `0.000e+00` |
| **randomised readout, gate 1** | `8.750e-01` (must be > 0) |
| after removal | `0.000e+00` |

Checks 4 and 6 are the load-bearing ones. A zero-initialised readout passing
gate 0 proves nothing, so the gate is tested against non-zero weights; and
without the gate-1 check, a branch that had been accidentally disconnected would
sail through and make the whole thing vacuous.

Recorded at the same time: read entropy at initialisation was **4.852 = ln 128**
to three decimals — exactly uniform. That was logged deliberately, to establish
that any addressing structure seen later was *learned*. It became the most
important number in the experiment.

---

## The central diagnostic — addressing collapsed

Probing the trained memory with all 48 recall questions (`memory_slot_analysis.json`):

| | |
|---|---|
| facts probed | 24 |
| **distinct top slots across facts** | **1** |
| distinct top slots across all 384 records | **1 / 128** |
| `top_share` per fact | **1.0000**, all 24 |
| mean top weight | 0.8246 – 0.9460 |
| mean read entropy | **0.7562** (uniform = 4.852) |

During thinking-mode composition, 4,287 accesses: slot 63 **4,285**, slot 19 **2**.

The softmax became **confident without becoming selective**. Sharpness does vary —
`corr(generation length, mean entropy) = 0.870`, so short generations read sharply
and runaways decay back toward uniform — but the *direction* never does. The read
is approximately `α·V[63] + (1−α)·mean(V)`, a one-parameter family whose every
member is input-independent.

**Why (inference, consistent with the logs, not independently ablated):** at init
the softmax is uniform so `read = mean(V)`; the readout is zero-initialised so at
step 0 keys, values and query receive *exactly* zero gradient and only a constant
bias can be learned; sharpening onto whichever slot is marginally favoured cuts
loss further without needing input dependence; once saturated (top weight
0.77–0.95) the gradient that would separate the keys is largely gone. **The
softmax sharpened before it differentiated, and could not escape.**

**GOAL_5's three candidates:** capacity **ruled out** (127 slots unused); lookup
**demonstrated** (directly measured); placement **not separable** from lookup on
one run and plausibly contributory — with a single write nine layers from the
logits, the cheapest loss reduction is a global distribution shift, which a
constant achieves. Separating them needs a variant run, which GOAL_5 excludes.

---

## The query → read → reason chain

| stage | count |
|---|---|
| hop-1 intermediate in trace | **0 / 24** |
| second query issued after hop-1 | 0 / 0 |
| second query addresses correct memory | 0 / 0 |
| hop-2 radiation in trace | 0 / 24 |
| final answer correct | 0 / 24 |
| bucket `no_hop1_intermediate` | **24** (all others 0) |

The chain breaks at stage one. GOAL_5's questions 5, 6 and 7 are **unanswerable
in this run, not answered negatively** — there was never a first retrieval to
follow. Reporting "0 / 0" rather than "0 %" is the honest framing.

Token alignment for this diagnostic was unit-tested against brute force before
the run: all 12 element names plus boundary cases (needle at token 0, at the
final token, absent, empty sequence), including across the `<think>` tag
boundary where BPE merges could have shifted the index. Exact match everywhere.

---

## What the traces show

| | |
|---|---|
| mean generated tokens | 178.6 |
| min / max | 3 / 1024 |
| truncations | 4 / 24 |
| loopiness | 0.0000 |
| answer buckets | `other` 20, `truncated` 4 |

The mean is misleading. **14 of 24 questions generate exactly 3 tokens and stop;
4 run to the full 1024-token limit.** Almost nothing in between — bimodal collapse
into immediate abort or runaway, not "shorter reasoning".

```
Q: What radiation should PLYURX-91 emit?
A: спорKZD-29 radiation̨️⟨/sплТ-11>

Q: If you measured the emission coming from PLYURX-91, what would it be?
A: 剧/
```

`KZD-29`, `плТ-11` are world-*shaped* without being world entities. The constant
bias transferred the corpus's surface statistics and none of its structure.

---

## Churn and leakage

Churn rate 0.75, substantive rate 0.6667. **Zero repairs** — like Experiment 004,
unlike every LoRA variant, which each accidentally fixed two control questions.

```
c_arith1    "24 * 3 = 72."  ->  "12."
c_ordering  "Rey."          ->  "Kiminna."
c_capital   "Paris."        ->  "DịnŶHĐ-99"
```

**A correction the shared analyser missed.** `analyze_interference_001.py` reports
0 world-shaped control answers, but its regex is ASCII-only
(`\b[A-Za-z]{2,8}-\d{2}\b`) and `DịnŶHĐ-99` is unmistakably world-shaped — the
world contains `BLOIZL-99` and `MVIOVN-99`. The shared analyser was **not**
modified (its numbers are the ones reported for 000–004). Instead every
experiment was recounted with both regexes:

| experiment | exact entity | ASCII | Unicode-aware | non-ASCII answers |
|---|---|---|---|---|
| 002 LoRA r4 | 0 | 0 | 0 | 0 |
| 003 LoRA r8 | 1 | 1 | 1 | 0 |
| 004 residual | 1 | 3 | 3 | 0 |
| **005 explicit KV** | 0 | 0 | **1** | **2** |

The ASCII regex was never wrong for the historical runs — both counts agree
exactly — so the comparison stays like-for-like. 005 is the only run it
undercounts and the only one that produced non-ASCII output at all. Correct
reading: leakage is **1/12**, and it is low *because nothing was learned to
leak*. Low leakage here is a consequence of failure, not a virtue.

---

## Gate sweep — flat at zero, then a cliff

| gate | recall | control | I |
|---|---|---|---|
| 0.00 | 0/48 | 9/12 | 0.0000 |
| 0.25 | 0/48 | 9/12 | 0.0000 |
| 0.50 | 0/48 | 10/12 | −0.0833 |
| 1.00 | 0/48 | 6/12 | 0.2500 |

Recall is flat at zero across the whole sweep: **there is no gate setting at which
the memory contributes knowledge**, while gate 1 costs 0.2500. Detaching it is
strictly better. The −0.0833 at gate 0.5 is one control item flipping right by
coincidence (5 changed, 0 regressions, 1 repair), not a benefit.

Reversibility is fully established; **knowledge round-tripping is vacuous** —
recall is 0/48 in every state, so nothing can be observed to disappear or return.

---

## The eighteen required answers

1. **Learned the facts?** No.
2. **Recall?** 0/48 (0.0000), at every gate value.
3. **Queries memory successfully?** Mechanically yes — it queries every token and
   the query is well-formed (norms 9.4–126.3, never degenerate). Functionally no:
   the *selection* is input-independent, so the same value returns regardless.
4. **Hop-1 reliability?** 0/24.
5. **Second meaningful query?** Unanswerable — hop 1 never occurred. 0 of 0.
6. **Second query addresses correct memory?** Unanswerable, same reason.
7. **Hop-2 reliability?** 0/24.
8. **Composition above chance?** No. 0/24 vs 1/6; p = 1.0000.
9. **Accuracy interference?** **0.2500**.
10. **Substantive churn?** 8/12 substantive, 9/12 changed (0.6667 / 0.7500).
    3 regressions, **0 repairs**.
11. **Leakage?** 1/12 Unicode-aware (0/12 by the shared ASCII regex); no exact
    entities. Low because nothing was learned.
12. **More instability or truncation?** Yes, in a new way — 4/24 truncations vs
    0/24 base, and bimodal collapse (14 abort at 3 tokens, 4 hit 1024).
13. **gate = 0 reproduces frozen behaviour?** Yes, exactly: bit-identical logits
    pre-training, 0/12 control answers changed post-training.
14. **Disabling removes knowledge?** Vacuously — there was none.
15. **Re-enabling restores knowledge?** Vacuously. It deterministically restores
    the *damage*: S6 reproduces S4 exactly.
16. **Improves on LoRA and GOAL_4?** No. Worse than every LoRA variant on recall,
    composition and hop retrieval. Against 004 it halves interference (0.2500 vs
    0.5000) and reduces truncation (4 vs 9) — but both are comparisons between
    two failures.
17. **Where in the chain does it fail?** Before the chain begins. Not query
    formation from an intermediate — the bottleneck GOAL_5 predicted — but **key
    differentiation during training**.
18. **Justifies continuing the explicit-memory direction?** Not with this
    mechanism unchanged; but it does not condemn addressability either, because
    addressability was never tested. See below.

---

## What survives the failure

Three findings that do not depend on the memory having worked:

* **A narrow interface does not by itself prevent disturbance.** One gated write
  at one layer, contributing nothing useful, still cost 0.2500 interference and
  8/12 substantive churn. Across all five experiments there is now **no mechanism
  that touches the frozen reasoner without measurable behavioural cost**.
* **Interference does not track parameter count.** At 739,456 parameters — a
  quarter of LoRA rank 4's — this run is *three times more* disruptive than rank
  4's 0.0833. Experiments 001–003 suggested interference tracks capacity; this
  breaks that reading. What correlates better is how free a mechanism's output is
  to vary independently of the reasoner's state.
* **Differentiable slot selection is fragile under this recipe.** Uniform init +
  zero-init readout + a single late insertion point is a saturation trap.

---

## Honest limits

* **Hyperparameters inherited, not tuned** — by instruction. The plateau argues
  against undertraining, but a different learning rate or warmup could plausibly
  change the collapse dynamics. This run does not exclude that.
* **One configuration.** Slot count and dimension were never the binding
  constraint; placement was not tested and cannot be separated from lookup here.
* **The slot map is a diagnostic, not ground truth.** It never needed to be
  discriminating — all 24 facts mapped to one slot, which is itself the finding.
* **n = 12 controls, n = 24 composition items.** Individual churn and gate
  observations (the gate-0.5 "repair") are single-item events.
* **The collapse reconstruction is inference**, consistent with the logged
  entropies, the gradients-at-init argument and the loss curve, but not verified
  by ablation.

---

## State of the machines

* **jetson-server** (10.0.2.3, Orin Nano Super, JetPack r36.4.7, torch
  2.5.0a0+872d972e41.nv24.08, transformers 4.57.6, `attn=eager`) — ran everything.
  Phase 1: isolation → base gate → S2 → 30-epoch train (1736 s) → S4/S5/S6 →
  gates 0.25/0.5 → slot probe. Phase 2: instrumented thinking-mode composition
  (490.9 s). Peak 6.106 GiB system / 1.260 GiB CUDA during training.
* **henry** (10.0.2.2) — synced, not used for compute this session.
* Repo `/home/nethic/mem-exp/dynamic-memory-lab`, commits `7580d78`
  (implementation) and `114ff2a` (results). Clean tree, synced to both hosts.

Deliverables in `results/experiment_005/` (24 files): `experiment_005_report.md`,
`methods.md`, `architecture.md`, `base_isolation_validation.md`,
`detachability_validation.md`, `results.json`, `gate_sweep.json`,
`trace_analysis.json`, `behavioral_churn.json`, `leakage_analysis.json`,
`leakage_unicode_supplement.json`, `memory_slot_analysis.json`,
`memory_access_analysis.json`, `memory_access_trace_S4_trained_gate1_think.json`
(4,287 records, 2.2 MB), `isolation_validation_*.json`, `train_M1_kv128_*.json`,
8 raw `eval_*.json`.

New code: `src/dynamic_memory/kv_memory.py`, `scripts/validate_isolation_005.py`,
`scripts/train_kv_005.py`, `scripts/eval_kv_005.py`, `scripts/probe_slots_005.py`,
`scripts/analyze_memory_access_005.py`, `scripts/aggregate_005.py`,
`scripts/leakage_unicode_005.py`, `scripts/run_experiment_005.sh`,
`scripts/run_thinking_005.sh`, `scripts/run_analysis_005.sh`.

Three additive, behaviour-preserving changes to shared code: `generate()` also
returns `generated_token_ids`; `evaluate_entity_set()` accepts an optional
`before_each` hook; both documented. Experiments 000–004 artifacts **not
modified**; the shared analysers **not modified**.

Verification: 67 figures cross-checked against the raw JSON before commit. One
rounding inconsistency found and fixed (`0.0033` → `0.00334`, matching the value
stored in GOAL_4's records).

---

## Next step — not run (exit condition reached)

GOAL_5's stop condition is explicit: implement one explicit memory architecture,
validate, train, instrument, evaluate, verify detachability, compare, then stop.
No tuning after seeing the result, no additional variants.

The decision now on the table is whether to make addressing **carry information
by construction** — entropy regularisation, a temperature schedule, orthogonality
or load-balancing penalties on keys, larger key initialisation, or hard top-k with
straight-through gradients — and so actually test GOAL_5's hypothesis; or to
accept that across five mechanisms no write interface has yet touched the frozen
reasoner without cost, and reconsider the premise.

Worth stating plainly for whoever picks this up: **the question GOAL_5 set out to
answer is still open.** This run answered a different one.
