From 232fafb6e945df35dce282ad30800d3cf46f075d Mon Sep 17 00:00:00 2001 From: Drew <90863972+Drewwb@users.noreply.github.com> Date: Fri, 21 Aug 2026 15:18:03 -0700 Subject: [PATCH] fix(logs): exclude same-thread events after scan completion readScanLogs() uses a saved scan's completedAt to reject independent sessions that start after the scan, but once a session was selected it appended every event without applying the same boundary. A post-scan prompt runs on the same Codex thread after complete-scan, so its later events surfaced in `codex-security scans logs` as if they belonged to the completed scan. Apply the completion boundary to individual events too: skip any event whose timestamp parses to a time after completedAt. Events without a parseable timestamp (such as session_meta) and every event at or before completedAt are preserved, so ordinary scan activity is unaffected. Add a regression test covering a same-thread event emitted after the saved completion time. --- sdk/typescript/src/scan-logs.ts | 13 +++++++++ sdk/typescript/tests-ts/scan-logs.test.ts | 32 +++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/sdk/typescript/src/scan-logs.ts b/sdk/typescript/src/scan-logs.ts index 97d6a7ed..8ea43a86 100644 --- a/sdk/typescript/src/scan-logs.ts +++ b/sdk/typescript/src/scan-logs.ts @@ -70,6 +70,10 @@ export async function readScanLogs(options: ScanLogOptions) { } } } + const completedBoundary = + options.completedAt === undefined || options.completedAt === null + ? Number.NaN + : Date.parse(options.completedAt); const events: Record[] = []; for (const session of sessions) { let replaying = false; @@ -91,6 +95,15 @@ export async function readScanLogs(options: ScanLogOptions) { } replaying = false; } + if ( + Number.isFinite(completedBoundary) && + typeof event["timestamp"] === "string" + ) { + const eventTime = Date.parse(event["timestamp"]); + if (Number.isFinite(eventTime) && eventTime > completedBoundary) { + continue; + } + } events.push({ threadId: session.threadId, event }); } } diff --git a/sdk/typescript/tests-ts/scan-logs.test.ts b/sdk/typescript/tests-ts/scan-logs.test.ts index be57c441..b07c0b58 100644 --- a/sdk/typescript/tests-ts/scan-logs.test.ts +++ b/sdk/typescript/tests-ts/scan-logs.test.ts @@ -200,6 +200,38 @@ describe("saved scan logs", () => { expect(JSON.stringify(result)).not.toContain("PRIVATE PRE-SCAN"); }); + test("excludes logs after completed time", async () => { + const home = await temporaryHome(); + await writeSession( + home, + "parent", + [ + commandEvent( + "DURING scan event", + "call-during", + "2026-08-21T12:01:00.000Z", + ), + commandEvent( + "AFTER hours event", + "call-after", + "2026-08-21T12:03:00.000Z", + ), + ], + undefined, + "2026-08-21T12:00:00.000Z", + ); + + const result = await readScanLogs({ + scanId: "scan-1", + threadId: "parent", + codexHome: home, + completedAt: "2026-08-21T12:02:00.000Z", + }); + + expect(JSON.stringify(result)).toContain("DURING scan event"); + expect(JSON.stringify(result)).not.toContain("AFTER hours event"); + }); + test("includes independent Deep workers without crossing scan boundaries", async () => { const home = await temporaryHome(); const scanDirectory = join(home, "scans", "current");