From 71caace5083824b268bdd3815ee7d23ac12ba511 Mon Sep 17 00:00:00 2001 From: Matt <174058705+asdf8675309@users.noreply.github.com> Date: Mon, 6 Jul 2026 20:53:16 -0400 Subject: [PATCH] fix(memory): self-heal missing entry markers so hot-layer memory persists The two hot-layer memory templates (USER/PRINCIPAL/PRINCIPAL_MEMORY.md and USER/DIGITAL_ASSISTANT/DA_MEMORY.md) ship without the / marker pair that MemoryWriter.ts requires. On a stock install this silently breaks the "memory that compounds" loop: - parseFile() hits its markers-missing branch and returns entries: [], so every reader (LoadMemory.hook, MemoryHealthCheck, Pulse) sees zero entries no matter how many the reviewer has written; - serializeFile() re-adds a lone END marker on each write, so the file accretes orphan END markers while remaining unreadable, and nothing alarms (setEntries returns ok). Two-layer fix: 1. Add the BEGIN/END marker pair to both shipped templates so fresh installs start well-formed. 2. Make parseFile() self-heal a marker-less or corrupted file: recover well-formed entry lines, drop stray markers, preserve the intro text, and rebuild a single clean BEGIN/END scaffold. This also repairs files already corrupted in the field, not just fresh installs. Refs #1409, #1426 Co-authored-by: Claude --- LifeOS/install/LIFEOS/TOOLS/MemoryWriter.ts | 23 +++++++++++++++---- .../USER/DIGITAL_ASSISTANT/DA_MEMORY.md | 2 ++ .../USER/PRINCIPAL/PRINCIPAL_MEMORY.md | 2 ++ 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/LifeOS/install/LIFEOS/TOOLS/MemoryWriter.ts b/LifeOS/install/LIFEOS/TOOLS/MemoryWriter.ts index f33f5424f..e2cbde40c 100755 --- a/LifeOS/install/LIFEOS/TOOLS/MemoryWriter.ts +++ b/LifeOS/install/LIFEOS/TOOLS/MemoryWriter.ts @@ -222,13 +222,26 @@ function parseFile(content: string): ParsedFile { const endIdx = afterFm.indexOf(END_MARKER); if (beginIdx === -1 || endIdx === -1 || endIdx < beginIdx) { - // Markers missing or malformed — treat as empty entries with the whole - // body as preEntries; this preserves principal content if they edited. + // Self-heal: markers missing or malformed (e.g. a template that shipped + // without a BEGIN marker, or a file where prior writes appended stray END + // markers). Recover every well-formed entry line, drop ALL stray markers, + // preserve the intro text before the first entry, and rebuild a single + // clean BEGIN/END scaffold. Without this, each write compounded corruption. + const recovered: string[] = []; + const introLines: string[] = []; + let sawEntry = false; + for (const line of afterFm.split("\n")) { + const t = line.trim(); + if (t === BEGIN_MARKER || t === END_MARKER) continue; + if (PREFIX_PATTERN.test(t)) { recovered.push(t); sawEntry = true; continue; } + if (!sawEntry) introLines.push(line); + } + const intro = introLines.join("\n").replace(/\n+$/, ""); return { frontmatter, - preEntriesBody: afterFm, - entries: [], - postEntriesBody: "", + preEntriesBody: (intro ? intro + "\n" : "") + BEGIN_MARKER, + entries: recovered, + postEntriesBody: END_MARKER, }; } diff --git a/LifeOS/install/USER/DIGITAL_ASSISTANT/DA_MEMORY.md b/LifeOS/install/USER/DIGITAL_ASSISTANT/DA_MEMORY.md index 0487c3f38..3151c4316 100644 --- a/LifeOS/install/USER/DIGITAL_ASSISTANT/DA_MEMORY.md +++ b/LifeOS/install/USER/DIGITAL_ASSISTANT/DA_MEMORY.md @@ -12,3 +12,5 @@ convention: pai-freshness-v1 > 🎯 SAMPLE TEMPLATE — auto-curated hot-layer memory your DA keeps about how it works with you. Starts empty; the memory reviewer populates it over time. Nothing to fill in manually. Pulse's memory panel reads this file. + + diff --git a/LifeOS/install/USER/PRINCIPAL/PRINCIPAL_MEMORY.md b/LifeOS/install/USER/PRINCIPAL/PRINCIPAL_MEMORY.md index 015e76935..1d4b27b40 100644 --- a/LifeOS/install/USER/PRINCIPAL/PRINCIPAL_MEMORY.md +++ b/LifeOS/install/USER/PRINCIPAL/PRINCIPAL_MEMORY.md @@ -12,3 +12,5 @@ convention: pai-freshness-v1 > 🎯 SAMPLE TEMPLATE — auto-curated hot-layer memory about you. It starts empty and the memory reviewer writes durable facts here as you work with your DA. Nothing to fill in manually. Pulse's memory panel reads this file. + +