fix(memory-core): keep daily ingestion outside session repair (#93389)

* fix(memory-core): clear daily-ingestion sqlite namespace on dreaming repair

repairDreamingArtifacts() cleared the dreaming-session-ingestion-files and
dreaming-session-ingestion-seen namespaces but not the migrated
dreaming-daily-ingestion namespace. After #92020 taught auditDreamingArtifacts()
to treat all three ingestion namespaces as ingestion state, the repair path
became asymmetric: the memory status --fix re-audit still reported
sessionIngestionExists=true from the surviving daily rows, and the daily
ingestion bookkeeping leaked past repair so daily memory files were not
re-ingested on the next sweep.

Clear DREAMING_DAILY_INGESTION_NAMESPACE alongside the session files/seen
namespaces so repair fully resets dreaming ingestion state, matching the audit.

* chore: retrigger CI for real behavior proof check

* fix(memory-core): keep daily ingestion outside session repair

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
Co-authored-by: Alix-007 <li.long15@xydigit.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
This commit is contained in:
Alix-007
2026-07-06 19:16:26 +01:00
committed by GitHub
co-authored by Peter Steinberger Vincent Koc
parent 673b87a403
commit 962d1096d4
2 changed files with 43 additions and 4 deletions
@@ -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);
});
});
@@ -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({