fix(memory): hot-layer entry markers — scaffold both, heal a missing BEGIN, migrate existing installs#1427
Open
rpriven wants to merge 1 commit into
Open
Conversation
b818fb2 to
0876df3
Compare
…BEGIN, migrate existing installs Hot-layer memory never loads into a session on a stock install: the templates ship without <!-- BEGIN ENTRIES -->/<!-- END ENTRIES --> markers, and serializeFile re-adds a missing END but never a missing BEGIN — so every write to a marker-less file accretes stray END markers and the reader (LoadMemory) slices an empty block. The reviewer captures durable facts that are then never recalled. - templates: ship both markers (fixes fresh installs) - MemoryWriter.serializeFile: heal a missing BEGIN, symmetric to the END guard - MemoryWriter.parseFile: recover orphaned entries from an already-broken file (skipping code-fence/blockquote lookalikes) so existing data survives next write - MigrateMemoryMarkers.ts: idempotent one-time repair for existing installs - tests: cover the previously-untested write-then-recall-next-session path Co-Authored-By: Kai <noreply@anthropic.com>
0876df3 to
904d944
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #1426.
The bug (two parts, one failure)
On a stock install the hot-layer memory files never load into a session. The reviewer
writes durable facts, but
LoadMemory.hook.tsinjects(no entries yet). Root cause istwo compounding defects:
install/USER/PRINCIPAL/PRINCIPAL_MEMORY.mdand
install/USER/DIGITAL_ASSISTANT/DA_MEMORY.mdhad neither<!-- BEGIN ENTRIES -->nor
<!-- END ENTRIES -->. The reader slices between those markers, finds no BEGIN,and returns empty.
serializeFileheals a missing END but never a missing BEGIN. So every write to amarker-less file appended another
ENDand never aBEGIN— the file accreted strayEND markers, read as empty forever, and dedup/cap/eviction never ran.
The fix
Fresh installs — add both markers to the two shipped templates:
Can't recur —
serializeFilenow adds a missingBEGIN_MARKER, symmetric to theexisting
END_MARKERguard.Existing data survives —
parseFile, on a marker-less/malformed file, now recoversthe real
PREFIX_PATTERNentries from the body (dropping stray markers) instead ofdiscarding them, so the next write re-emits them inside a canonical block. The recovery
scanner skips lines inside code fences and blockquotes, so a documented
PREFERENCE: …example is never adopted as a real entry.
Existing installs — self-heal, plus an on-demand accelerator. Once a user updates and
has the fixed
MemoryWriter.ts, a broken file repairs automatically on the next reviewerwrite (the
parseFilerecovery above re-blocks the orphaned entries) — no manual step.The Update workflow's
ScaffoldUser.ts copyMissingdeliberately never overwrites existingUSER files, so the template fix alone would not touch them; the writer fix is what covers
them. For an immediate repair without waiting for the next reviewer cycle, the new
standalone
MigrateMemoryMarkers.tsfixes both files on demand — same invocation model asthe existing
MigrateContextFreshness/MigrateTelosFreshnesstools (run directly; thoseare not auto-invoked by Update either). It's idempotent (canonical files skipped), backs up
before repair, supports
--dry-run, and reuses the testedread()→setEntries()path.Maintainers may optionally wire the migrations into the Update workflow as a separate
enhancement.
Testing
Two runnable tests (no test runner is configured in the repo; run with an isolated
HOME):MemoryWriter.markers.test.ts— 12 checks: fresh-template round-trip, the previouslyuntested cross-session path (write in session A → read in session B), recovery of
an already-corrupted file through the real add-flow, and the fence/blockquote guard.
MigrateMemoryMarkers.test.ts— 9 checks: dry-run is side-effect-free, corrupted filesheal (orphaned entries recovered), canonical files are left byte-identical, idempotent
on re-run.
Both green.
MemoryWriter.tsandMigrateMemoryMarkers.tscompile clean underbun build. The happy path is provably unaffected: the new recovery branch only runs whenmarkers are missing/malformed, and the new BEGIN guard is a structural no-op on well-formed
files (their
preEntriesBodyalready contains the marker).For users already on a broken install
After updating, existing memory auto-repairs on the next reviewer write. To fix immediately
without waiting, run the migration:
Or hand-edit both
~/.claude/LIFEOS/USER/PRINCIPAL/PRINCIPAL_MEMORY.mdand.../DIGITAL_ASSISTANT/DA_MEMORY.md: put one<!-- BEGIN ENTRIES -->immediately above thefirst entry and a single
<!-- END ENTRIES -->after the last, removing any stray ENDmarkers in between. No data is lost — the stranded entries are preserved, just re-blocked.
Out of scope (noted, not fixed here)
parseFilelocates markers withindexOf, so prose that mentions the literal markertext before the real block could shadow entries. Pre-existing (reproduces on
mainun-patched); worth hardening to whole-line marker matching in a follow-up.
allowDrastichas no live wiring anywhere — a legitimate full-clear is structurallyunreachable. Orthogonal; separate follow-up.