diff --git a/src/main/native-chat/agent-session-wire/agent-session-journal-recovery.test.ts b/src/main/native-chat/agent-session-wire/agent-session-journal-recovery.test.ts index 214c889b5c9..1c60029c7d3 100644 --- a/src/main/native-chat/agent-session-wire/agent-session-journal-recovery.test.ts +++ b/src/main/native-chat/agent-session-wire/agent-session-journal-recovery.test.ts @@ -6,14 +6,14 @@ import { mkdtemp, rm, writeFile } from 'node:fs/promises' import { tmpdir } from 'node:os' import { join } from 'node:path' -import { afterEach, beforeEach, describe, expect, it } from 'vitest' +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import type { AgentJournalItemIdentity, AgentSessionJournalIdentity } from '../../../shared/agent-session-journal-types' import { openJournalDatabase } from '../agent-session-journal/journal-database' import { JOURNAL_DB_SCHEMA_VERSION } from '../agent-session-journal/journal-database-schema' -import { loadJournal } from '../agent-session-journal/journal-open' +import { loadJournal, replayJournal } from '../agent-session-journal/journal-open' import { journalDatabaseFile } from '../agent-session-journal/journal-paths' import { readJournalEpochRows } from '../agent-session-journal/journal-row-table' import { createTrackedJournalOpener } from '../agent-session-journal/journal-store-test-open' @@ -24,6 +24,12 @@ import { recoveryJournalDir } from './agent-session-journal-recovery' +// Only the store's own replay goes through the mock; the probe's, inside the same module, does not. +vi.mock('../agent-session-journal/journal-open', async (importOriginal) => { + const actual = await importOriginal<{ replayJournal: typeof replayJournal }>() + return { ...actual, replayJournal: vi.fn(actual.replayJournal) } +}) + const CODEX_SESSION = '019fd532-7c11-7a90-b6de-4e1a2c3d5f60' const IDENTITY: AgentSessionJournalIdentity = { @@ -160,6 +166,21 @@ describe('openAgentSessionJournalWithRecovery', () => { expect(opened.snapshot().items).toHaveLength(2) }) + it('reads the journal once: the probe is the open', async () => { + await seedJournal(2) + vi.mocked(replayJournal).mockClear() + const opened = journals.track( + await openAgentSessionJournalWithRecovery({ + identity: IDENTITY, + journalDir, + fence: 1, + historyFilePath + }).then((result) => result.journal) + ) + expect(opened.snapshot().items).toHaveLength(2) + expect(replayJournal).not.toHaveBeenCalled() + }) + it('rebuilds a holed journal in place on a fresh epoch', async () => { await seedJournal(3) await deleteRow(3) diff --git a/src/main/native-chat/agent-session-wire/agent-session-journal-recovery.ts b/src/main/native-chat/agent-session-wire/agent-session-journal-recovery.ts index 6e771a31809..29d324be971 100644 --- a/src/main/native-chat/agent-session-wire/agent-session-journal-recovery.ts +++ b/src/main/native-chat/agent-session-wire/agent-session-journal-recovery.ts @@ -67,7 +67,9 @@ export async function openAgentSessionJournalWithRecovery(input: { } const journal = await openAgentSessionJournal({ identity: input.identity, - journalDir: input.journalDir + journalDir: input.journalDir, + // The probe is this open's replay; omitted, not `null`, when there was nothing to load. + ...(probe ? { loaded: probe } : {}) }) if (!probe?.corrupt) { return { journal, recovery: null }