From 18bfb3e5f5d7d353123e2f3db790ad3dff5fa0ca Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sat, 9 May 2026 07:13:54 +0100 Subject: [PATCH] refactor: drop file-era transcript fixture coverage --- docs/refactor/database-first.md | 17 +++++------ .../src/app-server/event-projector.test.ts | 2 -- .../voice-call/src/response-generator.test.ts | 2 -- .../src/host/openclaw-runtime-session.ts | 1 - .../src/host/openclaw-runtime.ts | 1 - .../src/host/session-transcripts.test.ts | 30 ++----------------- .../src/host/session-transcripts.ts | 25 ---------------- 7 files changed, 10 insertions(+), 68 deletions(-) diff --git a/docs/refactor/database-first.md b/docs/refactor/database-first.md index 49dae12e1be..4c7f4689719 100644 --- a/docs/refactor/database-first.md +++ b/docs/refactor/database-first.md @@ -76,8 +76,8 @@ interfaces that still look like the old file world: JSON as possible write targets. - Agent-owned tables live in per-agent SQLite databases. The global DB keeps registry/control-plane rows; transcript identity is a canonical - `sqlite-transcript:///.jsonl` locator derived from the - per-agent transcript rows. + `sqlite-transcript:///` locator derived from the per-agent + transcript rows. - Doctor already imports several legacy files. The cleanup is to make that a single explicit migration implementation that doctor calls, with a durable migration report. @@ -208,8 +208,8 @@ The remaining cleanup is mostly consolidation and deletion: SQLite; JSONL is now a legacy doctor input or in-memory export encoding, not a runtime state file. - Runtime session path resolution now canonicalizes active sessions to - `sqlite-transcript:///.jsonl` locators. Legacy absolute JSONL - paths are doctor migration inputs instead of active runtime identity. + `sqlite-transcript:///` locators. Legacy absolute JSONL paths + are doctor migration inputs instead of active runtime identity. - Gateway transcript-key lookup compares canonical transcript locators directly and no longer realpaths or stats transcript filenames. - Automatic compaction transcript rotation writes successor transcript rows @@ -248,10 +248,9 @@ The remaining cleanup is mostly consolidation and deletion: SQLite transcript rows directly. Runtime callers pass canonical SQLite locators, not writable `.jsonl` paths. - Fresh runtime session rows now use virtual - `sqlite-transcript:///.jsonl` locators instead of fake + `sqlite-transcript:///` locators instead of fake `agents//sessions/*.jsonl` paths. The old path builders remain for - doctor imports, explicit debug/export artifacts, and path-compatibility - tests. + doctor imports and explicit debug/export artifacts. - Starting a new persisted transcript session now always allocates a fresh SQLite locator. The session manager no longer reuses a previous file-era transcript path as the identity for the new session. @@ -283,9 +282,9 @@ The remaining cleanup is mostly consolidation and deletion: classification helpers; transcript filtering now derives from SQLite row metadata during entry construction. - Memory-host and QMD session-export tests default to virtual - `sqlite-transcript:///.jsonl` locators. Old + `sqlite-transcript:///` locators. Old `agents//sessions/*.jsonl` paths stay covered only where a test is - intentionally proving legacy path compatibility. + intentionally proving doctor/import/export compatibility. - QA-lab raw session inspection now uses `sessions.list` through the gateway instead of reading `agents/qa/sessions/sessions.json`; MSteams feedback appends directly to SQLite transcripts without fabricating a JSONL path. diff --git a/extensions/codex/src/app-server/event-projector.test.ts b/extensions/codex/src/app-server/event-projector.test.ts index bdd3a0d4d29..addfd6f46b8 100644 --- a/extensions/codex/src/app-server/event-projector.test.ts +++ b/extensions/codex/src/app-server/event-projector.test.ts @@ -1204,7 +1204,6 @@ describe("CodexAppServerEventProjector", () => { expect(beforeCompaction).toHaveBeenCalledWith( expect.objectContaining({ messageCount: 1, - sessionFile: expect.stringMatching(/^sqlite-transcript:\/\/main\/session-1-.+\.jsonl$/u), messages: [expect.objectContaining({ role: "assistant" })], }), expect.objectContaining({ @@ -1216,7 +1215,6 @@ describe("CodexAppServerEventProjector", () => { expect.objectContaining({ messageCount: 1, compactedCount: -1, - sessionFile: expect.stringMatching(/^sqlite-transcript:\/\/main\/session-1-.+\.jsonl$/u), }), expect.objectContaining({ runId: "run-1", diff --git a/extensions/voice-call/src/response-generator.test.ts b/extensions/voice-call/src/response-generator.test.ts index e4521476e35..c8cd67251fa 100644 --- a/extensions/voice-call/src/response-generator.test.ts +++ b/extensions/voice-call/src/response-generator.test.ts @@ -273,7 +273,6 @@ describe("generateVoiceResponse", () => { agentId: "main", sandboxSessionKey: "agent:main:voice:15550001111", workspaceDir: "/tmp/openclaw/workspace/main", - sessionFile: expect.stringMatching(/^sqlite-transcript:\/\/main\/.+\.jsonl$/), }), ); }); @@ -311,7 +310,6 @@ describe("generateVoiceResponse", () => { agentId: "voice", sandboxSessionKey: "agent:voice:voice:15550001111", workspaceDir: "/tmp/openclaw/workspace/voice", - sessionFile: expect.stringMatching(/^sqlite-transcript:\/\/voice\/.+\.jsonl$/), }), ); }); diff --git a/packages/memory-host-sdk/src/host/openclaw-runtime-session.ts b/packages/memory-host-sdk/src/host/openclaw-runtime-session.ts index e1ee7c548d8..b8c2b620237 100644 --- a/packages/memory-host-sdk/src/host/openclaw-runtime-session.ts +++ b/packages/memory-host-sdk/src/host/openclaw-runtime-session.ts @@ -3,7 +3,6 @@ export { HEARTBEAT_TOKEN, SILENT_REPLY_TOKEN, hasInterSessionUserProvenance, - isCompactionCheckpointTranscriptFileName, isCronRunSessionKey, isExecCompletionEvent, isHeartbeatUserMessage, diff --git a/packages/memory-host-sdk/src/host/openclaw-runtime.ts b/packages/memory-host-sdk/src/host/openclaw-runtime.ts index d1fd2d3733d..ec2a55cc68f 100644 --- a/packages/memory-host-sdk/src/host/openclaw-runtime.ts +++ b/packages/memory-host-sdk/src/host/openclaw-runtime.ts @@ -48,7 +48,6 @@ export { } from "../../../../src/config/config.js"; export type { OpenClawConfig } from "../../../../src/config/config.js"; export { resolveStateDir } from "../../../../src/config/paths.js"; -export { isCompactionCheckpointTranscriptFileName } from "../../../../src/config/sessions/artifacts.js"; export { listSqliteSessionTranscripts, loadSqliteSessionTranscriptEvents, diff --git a/packages/memory-host-sdk/src/host/session-transcripts.test.ts b/packages/memory-host-sdk/src/host/session-transcripts.test.ts index 3599a2ed2ea..2cca3d93bf3 100644 --- a/packages/memory-host-sdk/src/host/session-transcripts.test.ts +++ b/packages/memory-host-sdk/src/host/session-transcripts.test.ts @@ -194,33 +194,9 @@ describe("buildSessionTranscriptEntry", () => { expect(entry.lineMap).toEqual([]); }); - it("skips checkpoint artifacts so snapshots do not double-index session content", async () => { - const checkpointPath = path.join( - tmpDir, - "agents", - "main", - "sessions", - "ordinary.checkpoint.11111111-1111-4111-8111-111111111111.jsonl", - ); - seedTranscript({ - sessionId: "ordinary.checkpoint.11111111-1111-4111-8111-111111111111", - transcriptPath: checkpointPath, - events: [ - { - type: "message", - message: { role: "user", content: "Archived hello" }, - }, - ], - }); - - await expect(buildSessionTranscriptEntry(checkpointPath)).resolves.toBeNull(); - }); - - it("keeps cron-run deleted archives opaque when the live session store entry is gone", async () => { - const archivePath = path.join(tmpDir, "cron-run.jsonl.deleted.2026-02-16T22-27-33.000Z"); + it("keeps cron-run transcripts opaque when the live session store entry is gone", async () => { const transcriptRef = seedTranscript({ sessionId: "cron-run-deleted", - transcriptPath: archivePath, events: [ { type: "message", @@ -243,11 +219,9 @@ describe("buildSessionTranscriptEntry", () => { expect(entry.generatedByCronRun).toBe(true); }); - it("keeps cron-run reset archives opaque when session metadata preserves the cron key", async () => { - const archivePath = path.join(tmpDir, "cron-run.jsonl.reset.2026-02-16T22-26-33.000Z"); + it("keeps cron-run transcripts opaque when session metadata preserves the cron key", async () => { const transcriptRef = seedTranscript({ sessionId: "cron-run-reset", - transcriptPath: archivePath, events: [ { type: "session-meta", diff --git a/packages/memory-host-sdk/src/host/session-transcripts.ts b/packages/memory-host-sdk/src/host/session-transcripts.ts index 7427d43ce57..f2aeb94ea80 100644 --- a/packages/memory-host-sdk/src/host/session-transcripts.ts +++ b/packages/memory-host-sdk/src/host/session-transcripts.ts @@ -5,7 +5,6 @@ import { HEARTBEAT_PROMPT, HEARTBEAT_TOKEN, hasInterSessionUserProvenance, - isCompactionCheckpointTranscriptFileName, isCronRunSessionKey, isExecCompletionEvent, isHeartbeatUserMessage, @@ -57,16 +56,6 @@ export type SessionTranscriptDeltaStats = { updatedAt: number; }; -function shouldSkipTranscriptFileForDreaming(absPath: string): boolean { - const fileName = path.basename(absPath); - // Compaction checkpoints are always skipped: they are derived snapshots of an - // active session and would double-index the same content. - if (isCompactionCheckpointTranscriptFileName(fileName)) { - return true; - } - return false; -} - function isDreamingNarrativeBootstrapRecord(record: unknown): boolean { if (!record || typeof record !== "object" || Array.isArray(record)) { return false; @@ -205,7 +194,6 @@ export function sessionPathForTranscript(absPath: string): string { export function resolveSessionTranscriptScope(locator: string): { agentId: string; sessionId: string; - transcriptPath?: string; } | null { const sqliteRef = parseSqliteSessionTranscriptRef(locator); if (sqliteRef) { @@ -457,19 +445,6 @@ export async function buildSessionTranscriptEntry( (total, entry) => total + JSON.stringify(entry.event).length + 1, 0, ); - if (shouldSkipTranscriptFileForDreaming(absPath)) { - return { - path: sessionPathForTranscript(absPath), - absPath, - mtimeMs, - size, - messageCount, - hash: hashText("\n\n"), - content: "", - lineMap: [], - messageTimestampsMs: [], - }; - } const collected: string[] = []; const lineMap: number[] = []; const messageTimestampsMs: number[] = [];