diff --git a/extensions/memory-core/src/dreaming-repair.test.ts b/extensions/memory-core/src/dreaming-repair.test.ts index f130188db471..7228e203a88f 100644 --- a/extensions/memory-core/src/dreaming-repair.test.ts +++ b/extensions/memory-core/src/dreaming-repair.test.ts @@ -199,6 +199,10 @@ describe("dreaming artifact repair", () => { }), ]); + await expect( + auditDreamingArtifacts({ workspaceDir }).then((audit) => audit.sessionIngestionExists), + ).resolves.toBe(true); + const repair = await repairDreamingArtifacts({ workspaceDir }); expect(repair.archivedSessionCorpus).toBe(true); @@ -214,6 +218,41 @@ describe("dreaming artifact repair", () => { workspaceDir, }), ).resolves.toEqual([]); + await expect( + auditDreamingArtifacts({ workspaceDir }).then((audit) => audit.sessionIngestionExists), + ).resolves.toBe(false); + }); + + it("preserves sqlite daily ingestion state when archiving session corpus", async () => { + const workspaceDir = await createWorkspace(); + const sessionCorpusDir = path.join(workspaceDir, "memory", ".dreams", "session-corpus"); + await fs.mkdir(sessionCorpusDir, { recursive: true }); + await fs.writeFile(path.join(sessionCorpusDir, "2026-04-11.txt"), "corpus\n", "utf-8"); + await writeMemoryCoreWorkspaceEntries({ + namespace: DREAMING_DAILY_INGESTION_NAMESPACE, + workspaceDir, + entries: [ + { + key: "2026-06-10", + value: { ingestedAt: 1_000, lastDreamingDayIngested: "2026-06-10" }, + }, + ], + }); + + const repair = await repairDreamingArtifacts({ workspaceDir }); + + expect(repair.archivedSessionCorpus).toBe(true); + await expect( + readMemoryCoreWorkspaceEntries({ + namespace: DREAMING_DAILY_INGESTION_NAMESPACE, + workspaceDir, + }), + ).resolves.toEqual([ + { + key: "2026-06-10", + value: { ingestedAt: 1_000, lastDreamingDayIngested: "2026-06-10" }, + }, + ]); }); it("reports ingestion state present from SQLite when legacy JSON is absent", async () => { @@ -235,7 +274,7 @@ describe("dreaming artifact repair", () => { expect(audit.sessionIngestionExists).toBe(true); }); - it("reports ingestion state present from SQLite daily namespace", async () => { + it("does not report session ingestion from the SQLite daily namespace", async () => { const workspaceDir = await createWorkspace(); // Only daily ingestion namespace has rows await writeMemoryCoreWorkspaceEntries({ @@ -251,6 +290,6 @@ describe("dreaming artifact repair", () => { const audit = await auditDreamingArtifacts({ workspaceDir }); - expect(audit.sessionIngestionExists).toBe(true); + expect(audit.sessionIngestionExists).toBe(false); }); }); diff --git a/extensions/memory-core/src/dreaming-repair.ts b/extensions/memory-core/src/dreaming-repair.ts index c24c79ef5891..644f924fde5b 100644 --- a/extensions/memory-core/src/dreaming-repair.ts +++ b/extensions/memory-core/src/dreaming-repair.ts @@ -5,7 +5,6 @@ import path from "node:path"; import { extractErrorCode } from "openclaw/plugin-sdk/error-runtime"; import { clearMemoryCoreWorkspaceNamespace, - DREAMING_DAILY_INGESTION_NAMESPACE, DREAMING_SESSION_INGESTION_FILES_NAMESPACE, DREAMING_SESSION_INGESTION_SEEN_NAMESPACE, readMemoryCoreWorkspaceEntries, @@ -213,10 +212,11 @@ export async function auditDreamingArtifacts(params: { // Fall back to SQLite plugin state when the legacy JSON file was archived by migration. if (!sessionIngestionExists) { try { + // Daily ingestion tracks memory/*.md independently; session repair must not + // report or clear that healthy bookkeeping when rebuilding the session corpus. const ingestionNamespaces = [ DREAMING_SESSION_INGESTION_FILES_NAMESPACE, DREAMING_SESSION_INGESTION_SEEN_NAMESPACE, - DREAMING_DAILY_INGESTION_NAMESPACE, ] as const; for (const namespace of ingestionNamespaces) { const entries = await readMemoryCoreWorkspaceEntries({