From 46fa55ace1a96fcd28f3395491ad0d488b21c114 Mon Sep 17 00:00:00 2001 From: Gustavo Madeira Santana Date: Tue, 14 Apr 2026 19:54:17 -0400 Subject: [PATCH] memory: narrow dreaming contamination heuristics --- .../src/short-term-promotion.test.ts | 46 +++++++++++++++++++ .../memory-core/src/short-term-promotion.ts | 17 ++----- 2 files changed, 51 insertions(+), 12 deletions(-) diff --git a/extensions/memory-core/src/short-term-promotion.test.ts b/extensions/memory-core/src/short-term-promotion.test.ts index e3bb05f2ad0..ce379000549 100644 --- a/extensions/memory-core/src/short-term-promotion.test.ts +++ b/extensions/memory-core/src/short-term-promotion.test.ts @@ -262,6 +262,36 @@ describe("short-term promotion", () => { }); }); + it("keeps ordinary snippets that only quote dreaming prompt markers", async () => { + await withTempWorkspace(async (workspaceDir) => { + await recordShortTermRecalls({ + workspaceDir, + query: "debug note", + results: [ + { + path: "memory/2026-04-03.md", + source: "memory", + startLine: 1, + endLine: 1, + score: 0.75, + snippet: + "Debug note: quote Write a dream diary entry from these memory fragments for docs, but do not use dreaming-narrative-like labels in production.", + }, + ], + }); + + const store = JSON.parse( + await fs.readFile(resolveShortTermRecallStorePath(workspaceDir), "utf-8"), + ) as { entries: Record }; + expect(Object.values(store.entries)).toEqual([ + expect.objectContaining({ + snippet: + "Debug note: quote Write a dream diary entry from these memory fragments for docs, but do not use dreaming-narrative-like labels in production.", + }), + ]); + }); + }); + it("records recalls and ranks candidates with weighted scores", async () => { await withTempWorkspace(async (workspaceDir) => { await recordShortTermRecalls({ @@ -1063,6 +1093,22 @@ describe("short-term promotion", () => { ).toBe(true); }); + it("does not treat ordinary candidate notes with daily-memory evidence as contaminated", () => { + expect( + __testing.isContaminatedDreamingSnippet( + "Candidate: move backups weekly. confidence: 0.76 evidence: memory/2026-04-08.md:1-1", + ), + ).toBe(false); + }); + + it("treats transcript-style dreaming prompt echoes as contaminated", () => { + expect( + __testing.isContaminatedDreamingSnippet( + "[main/dreaming-narrative-light.jsonl#L1] Write a dream diary entry from these memory fragments:", + ), + ).toBe(true); + }); + it("skips direct candidates that exceed maxAgeDays during apply", async () => { await withTempWorkspace(async (workspaceDir) => { const applied = await applyShortTermPromotions({ diff --git a/extensions/memory-core/src/short-term-promotion.ts b/extensions/memory-core/src/short-term-promotion.ts index 8562b1f4aa2..faf41fab9b8 100644 --- a/extensions/memory-core/src/short-term-promotion.ts +++ b/extensions/memory-core/src/short-term-promotion.ts @@ -32,13 +32,13 @@ const SHORT_TERM_LOCK_RELATIVE_PATH = path.join("memory", ".dreams", "short-term const SHORT_TERM_LOCK_WAIT_TIMEOUT_MS = 10_000; const SHORT_TERM_LOCK_STALE_MS = 60_000; const SHORT_TERM_LOCK_RETRY_DELAY_MS = 40; -const DREAMING_NARRATIVE_PROMPT_PREFIX = "Write a dream diary entry from these memory fragments"; // Repeated dreaming revisits should be able to clear the default promotion gate // without requiring separate organic recall traffic for the same snippet. const PHASE_SIGNAL_LIGHT_BOOST_MAX = 0.06; const PHASE_SIGNAL_REM_BOOST_MAX = 0.09; const PHASE_SIGNAL_HALF_LIFE_DAYS = 14; -const DREAMING_NARRATIVE_RUN_PREFIX = "dreaming-narrative-"; +const DREAMING_TRANSCRIPT_PROMPT_LINE_RE = + /\[[^\]]*dreaming-narrative[^\]]*]\s*Write a dream diary entry from these memory fragments:?/i; const inProcessShortTermLocks = new Map>(); const ensuredShortTermDirs = new Map>(); @@ -277,9 +277,8 @@ function isContaminatedDreamingSnippet(raw: string): boolean { return false; } if ( - snippet.includes(DREAMING_NARRATIVE_PROMPT_PREFIX) || - snippet.includes(PROMOTION_MARKER_PREFIX) || - snippet.includes(DREAMING_NARRATIVE_RUN_PREFIX) + /