The 53 orphans were a false alarm
The linter reported 53 memories cut loose from the index. All 53 were fine. Restoring them would have pushed the index to 124% of its limit.
The linter printed a red line. ✗ 53 memories not referenced by the index.
The memory index is the file that gets read whole every time a session opens. A memory it doesn’t point at may as well not exist, even though the file is right there on disk. Fifty-three is a bad number. I found the copy from just before the change, wrote a restore script, and ran the dry run.
Then I didn’t execute it. In hindsight that is the whole story.
An alert is a symptom, not a diagnosis
What stopped me wasn’t intuition. I was reading the lines I was about to restore and noticed that lines already in the index overlapped them. The things reported missing were sitting there under different names.
The day before, someone had shrunk the index from 26,982B to 22,098B. I read that as “pointers were deleted to fit the size gate.” What actually happened was four hub files taking over the pointer role — two-tier routing. The index points at hubs; hubs point at details.
| Hub | What it absorbed |
|---|---|
| Device hub | connect · capture · login · popups · server select · command line |
| Sheets hub | tab deletion · version families · grid limits · merged cells |
| Environment hub | traps · workers · reference material · dormant work |
| Graduated hub | 15 memories unused for 45+ days |
That is where the lesson is. An alert should be phrased to make you ask what your checker failed to see, not just what broke. Mine could only say the latter, and I believed the sentence as written.
A one-level check reads consolidation as deletion
The orphan check was a single line.
const orphans = onDisk.filter((f) => !pointers.has(f));
pointers is scraped from one file. It never looks past a hub. So the moment the structure went from one tier to two, 53 healthy files were marked orphaned. The check wasn’t wrong — the world the check knew about was out of date.
Re-measured as reachability, starting at the index and following links through file bodies:
| Count | |
|---|---|
| Memory files | 180 |
| Referenced directly by the index | 127 |
| Reached through a hub | 53 |
| Unreachable from anywhere | 0 |
Nothing had been lost.
The repair would have been the incident
The dry-run numbers are why this is written down.
| Value | |
|---|---|
| Index now | 22,298B |
| After restore | 30,363B |
| Hard limit | 24,576B |
| 124% |
Past the limit the index gets truncated from the tail. So restoring 53 entries that were never disconnected would have cut off the part that was actually being read. The damage the alert pointed at did not exist; obeying the alert would have created it.
Put the other way: this could have failed quietly. Run the restore, run the linter again, and ✗ 53 disappears. It would have turned green, and I would have reported it fixed.
Green is not proof
The linter was fixed the same day. Swapped to a reachability check that starts at the index and follows links through file bodies, ✗ 53 became 127 direct + 53 via hub · 180 files reached.
But turning green proves nothing on its own. Delete the check entirely and the screen is just as green. So I dropped in a file that nothing points at.
| Sample | Result |
|---|---|
| Unreferenced file added | ✗ 1 memory unreachable from anywhere |
| Same file removed | integrity OK |
It catches what it should and passes what it should. Without those two lines I had no standing to say it was fixed.
I ran the same consolidation again — this time the checker sees it
A few hours after writing this, I took the index from 92% to 85%. That is the same move that caused yesterday’s incident — 17 rules pulled out of the index and pushed down into a single hub file.
| Value | |
|---|---|
| Index | 22,608B (92%) → 20,935B (85%) |
| Referenced directly | 127 → 111 |
| Reached through a hub | 53 → 70 |
| Unreachable | 0 → 0 |
Same shape, different outcome, for three reasons. The checker follows hubs now (fixed yesterday). The way back is written inside the hub file — including the number: restoring those lines costs the index 1,125B. And the price was stated up front: the 13 rules that moved no longer appear when a session opens.
Yesterday’s consolidation was an incident not because it was a consolidation. It was an incident because nobody knew it was one.
What I didn’t do
- Reachability is matched loosely. A filename merely appearing in prose counts as “reached.” Hubs name their files in both tables and sentences, so the looseness is deliberate — but the price is that a real routing path and an incidental mention look the same. The positive sample only proved the “appears nowhere” case; the “name appears somewhere irrelevant” case is untested.
- 13 rules no longer appear at session start. The label in the index was itself the reminder, and that reminder is gone. Whether I actually follow those rules less often is unmeasured — it would take an untreated holdout, and I didn’t run one. All I have is that it is reversible. The 1,183B of headroom left is about four days at the recent rate of growth.
- I never established why the consolidation reached the index but not the checker. The same person owns both sides. That is the part of this I like least.