Memory System Audit: 28 Writers, 2 Readers, 9 Gaps — What We Found and Fixed #884
Replies: 6 comments 3 replies
-
|
Great work! Are the changes available in a gist? |
Beta Was this translation helpful? Give feedback.
-
|
Thanks @KimVatnedal! Here are the four files: https://gist.github.com/jlacour-git/b3d465e0b8e505420dd5b38958d2364e
Note: |
Beta Was this translation helpful? Give feedback.
-
|
Updated the gist with a small improvement to The dedup manifest now tracks token counts per file, so the feedback line shows both total context burden and per-turn delta: Previously it only showed the delta — which made the context load look trivially small on later turns when most files got deduped. Now you see at a glance what the model is actually carrying. |
Beta Was this translation helpful? Give feedback.
-
|
Great 😀 I see there are more fixes in other discussions, do you recommend implementing them all while we wait for official releases?
Sent from [Proton Mail](https://proton.me/mail/home) for Android.
…-------- Original Message --------
On Wednesday, 03/04/26 at 12:40 jlacour-git ***@***.***> wrote:
Updated the gist with a small improvement to ContextAssembler.hook.ts.
The dedup manifest now tracks token counts per file, so the feedback line shows both total context burden and per-turn delta:
Context assembled: 2 new files (1 summaries, 1 work), 4,971/5,000 tokens [1,013 added, 8 dedup-skipped]
Previously it only showed the delta — which made the context load look trivially small on later turns when most files got deduped. Now you see at a glance what the model is actually carrying.
—
Reply to this email directly, [view it on GitHub](#884 (comment)), or [unsubscribe](https://github.com/notifications/unsubscribe-auth/ANZDKXSU7HLY4Q65FRT2VD34PAI27AVCNFSM6AAAAACWFI2KWCVHI2DSMVQWIX3LMV43URDJONRXK43TNFXW4Q3PNVWWK3TUHMYTKOJZGY4DENY).
You are receiving this because you were mentioned.Message ID: ***@***.***>
|
Beta Was this translation helpful? Give feedback.
-
|
Updated the gist again — now 5 files: https://gist.github.com/jlacour-git/b3d465e0b8e505420dd5b38958d2364e What changed: The The fix is a 3-tier gate:
Also added self-exclusion: files created during the current session don't get re-injected back to you. New file: Re: implementing fixes from other discussions — I'd be selective. The ones that fix clear bugs (like the surrogate pair splitting in RatingCapture, PR #882) are safe. Architectural changes are riskier without understanding how they interact with your local setup. The |
Beta Was this translation helpful? Give feedback.
-
ContextAssembler Update: Semantic Search Overhaul (2026-03-24)
After extended production use of our ContextAssembler (shared earlier in this thread), we discovered and fixed three fundamental issues with the semantic search layer. Problem
ChangesModel swap: nomic-embed-text → mxbai-embed-large (334M, 1024d, multilingual). Garbage max cosine: 0.978 → 0.476. German discrimination: 1.000 → 0.581. 4/4 clean per-query separation (was 2/4). 6ms slower per embed — negligible. S-gate scoring architecture. Replaced Indexer quality gate: min 50 chars body. Prevents degenerate short chunks from entering the index. Eliminated 55% of indexed chunks that were heading-only or placeholder content. Results
Key insightTest with deliberately absurd queries. We used "Kochen Rezept Kartoffeln" (cooking recipe potatoes) against an infrastructure knowledge base. It exposed the degenerate vector problem immediately — something threshold-tuning would have masked. Config: |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Memory System Audit: Producer/Consumer Gaps and Fixes
TL;DR
We built a custom session summary system (writer + retrieval) and modified WorkCleanup to manage the session lifecycle. In doing so, we introduced two integration mistakes that went undetected until a cross-session handoff failed. Investigating those mistakes triggered a full producer/consumer audit of the
MEMORY/directory. The audit uncovered 28 writers, 2 readers, and 9 gaps where data was written but never retrieved. The most critical: our own session summaries were being written but never read back, and WorkCleanup was about to start permanently deleting session data without proper archival. All gaps are now fixed.This post shares what we got wrong, what we found, and the resulting architecture — so others can avoid the same mistakes and strengthen their own PAI memory systems.
What We Got Wrong
We were building custom improvements to the memory system across multiple sessions. In one session, we added a session summary writer. In another, we built the ContextAssembler to retrieve context. Each piece worked on its own — but we never verified the end-to-end data flow. That's how two integration gaps slipped in.
The trigger: we tried to hand off work between sessions. A prior session analyzed Algorithm v3.6.0 (PR #871) and said: "Start a fresh session — I'll pick up the context via session summary." The new session cold-started with zero context.
Our mistake #1: When building
getRecentWork()in ContextAssembler, we added a skip for thesummaries/directory (correct — summaries aren't work entries). But we never built the correspondinggetRecentSummaries()scanner. Theprds/skip had a dedicated scanner,summaries/didn't. The data was being written correctly — we just forgot to build the reader.Our mistake #2: We built
getArchivedPRDs()to scanMEMORY/WORK/prds/— but the archival process that was supposed to populate that directory was never implemented. The scanner worked perfectly; it just scanned an empty directory. 40 PRDs sat in their original work directories, becoming invisible once the 7-day recency cutoff expired.Both mistakes share the same root cause: building producers and consumers in separate sessions without integration testing. This prompted a full system audit.
The Audit
Method
We mapped every producer (file writer) and every consumer (file reader) across the entire
MEMORY/directory tree, then identified every gap where written data had no retrieval path.Scale
MEMORY/(hooks, handlers, tools, CLI utilities)MEMORY/:LoadContext.hook.ts— once at session startupContextAssembler.hook.ts— every prompt viaUserPromptSubmitGaps Found
WORK/summaries/) — no readerRESEARCH/*.md) — no readerGrowth Assessment
Several directories grow unbounded with no cleanup mechanism:
The Fixes
Fix 1: ContextAssembler — Coverage Gap Repairs
Added
getRecentSummaries()— scansWORK/summaries/*.mdwith keyword matching + 7-day recency. Type weight: 0.85 (between current-work 1.0 and recent-work 0.8). Cap: 5 results.Replaced
getArchivedPRDs()withgetKeywordMatchedPRDs()— scans bothWORK/andARCHIVE/(see Fix 2) by keyword with no recency cutoff. Deduplicates against recent work. Cap: 5 results.Added
getRelevantLearnings()— scansLEARNING/ALGORITHM/andLEARNING/SYSTEM/by keyword. Type weight: 0.45. Cap: 3 results. This surfaces past learning signals relevant to the current task.Files changed:
PAI/Tools/ContextAssembler.ts,hooks/ContextAssembler.hook.tsFix 2: WorkCleanup — Archive Instead of Delete
Complete rewrite. Old behavior: copy PRD.md to
prds/, thenrmSync(dir, recursive). New behavior:MEMORY/ARCHIVE/viarenameSyncWORK/summaries/(hot path — always scanned)context-seen-*.jsonfor sessions not insession-names.json, removesalgorithms/*.jsonolder than 7 daysprds/directory (archival concept replaced by ARCHIVE/)Architecture:
File changed:
hooks/WorkCleanup.hook.tsFix 3: LoadContext — Session Summaries at Startup
Added "Recent Session Summaries" section to the startup banner. Loads 3 most recent summaries with heading + 150-character preview. Gives immediate cross-session context before the first ContextAssembler injection.
File changed:
hooks/LoadContext.hook.tsResulting Memory Architecture
The Two-Temperature Model
Hot (always scanned, budget-managed):
WORK/summaries/— session summaries (ContextAssembler + LoadContext)WORK/{active-sessions}/— PRDs, META (ContextAssembler, 7-day window)LEARNING/FAILURES/— failure contexts (ContextAssembler, keyword-matched)LEARNING/ALGORITHM/+LEARNING/SYSTEM/— learning signals (ContextAssembler, keyword-matched)Cold (preserved, searchable on demand):
ARCHIVE/{old-sessions}/— full session dirs after 7 days (PRDs keyword-searchable)LEARNING/SIGNALS/ratings.jsonl— raw signal data (consumed via learning-cache.sh)SECURITY/,VOICE/,RESEARCH/— audit trails and diagnosticsKey Design Principle
Summaries are the card catalog; session dirs are the filing cabinet. Summaries stay hot forever (in
WORK/summaries/). Session dirs go cold after 7 days (moved toARCHIVE/). The summary captures the decisions and outcomes; the session dir preserves the raw materials for forensic recovery if needed.Lessons Learned
Producer-consumer imbalance is the systemic pattern. It's easy to add a writer (a new hook that captures data). It's easy to forget the corresponding reader. The result: data accumulates but is invisible. Any memory system should audit its read paths as carefully as its write paths.
Integration testing for data flow. These bugs were built in separate sessions. Session A added the summary writer. Session B built the ContextAssembler. Neither verified the end-to-end flow. A simple test — "write a summary, then run ContextAssembler and check if it surfaces" — would have caught both gaps immediately.
A skip without a redirect is a silent drop. When we added
if (entry.name === 'summaries') continuetogetRecentWork(), it was correct — summaries aren't work entries. But we treated the skip as "handled" when it was really "deferred." The corresponding scanner was our responsibility to build, and we didn't. Any time you skip a directory in a scanner, ask: "who reads this instead?"Archive before delete. The original WorkCleanup was designed to be lightweight — just clean up old dirs. But "clean up" meant "permanently destroy." For a memory system, destruction should be the exceptional case, not the default. Move-to-archive costs the same as delete but preserves recoverability.
Implementation Guide
If you want to apply these fixes to your own PAI install:
ContextAssembler.ts — Add the
session-summaryandlearningtypes to the Candidate union. AddgetRecentSummaries(),getRelevantLearnings(), and updategetKeywordMatchedPRDs()to also scanARCHIVE/. Wire all three intoassemble().ContextAssembler.hook.ts — Update the display grouping ternaries to handle the new types.
WorkCleanup.hook.ts — Replace
rmSyncwithrenameSynctoMEMORY/ARCHIVE/. Add STATE file cleanup. Remove theprds/directory concept.LoadContext.hook.ts — Add a summary section to
checkActiveProgress()that reads 3 most recent files fromWORK/summaries/.The detailed audit report with the full 28-writer / 22-reader matrix is available as a gist (linked below).
Discovered and fixed on PAI v4.0.3. All changes tracked as local patches (#31, #32, #33).
Beta Was this translation helpful? Give feedback.
All reactions