From 796b384c158239e4e41d8b935b295edf6b3a0e8d Mon Sep 17 00:00:00 2001 From: Eva Date: Wed, 29 Jul 2026 04:14:49 +0700 Subject: [PATCH 1/4] fix(core): preserve explicit Codex final answers --- packages/core/src/index.ts | 45 ++++++++++++++++-- tests/codex-index.test.ts | 94 +++++++++++++++++++++++++++++++++++++- 2 files changed, 135 insertions(+), 4 deletions(-) diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 0a3bd42c..76085c88 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -3062,6 +3062,7 @@ type ImportedSession = { updatedAt: string | null; finalMessage: string | null; finalMessageExplicit: boolean; + finalMessageAuthoritative: boolean; plans: string[]; touchedFiles: string[]; toolCalls: CodexToolCallDraft[]; @@ -5335,6 +5336,7 @@ function existingCodexSessionSeedForSourcePath(db: LooDatabase, sourcePath: stri updatedAt: nullableString(row.updatedAt), finalMessage: nullableString(row.finalMessage), finalMessageExplicit: existingCodexSessionHasRangeKind(db, threadId, "final_message"), + finalMessageAuthoritative: existingCodexSessionHasRangeReasonCode(db, threadId, "codex_explicit_final_answer"), plans, touchedFiles: getCodexTouchedFiles(db, { threadId }), toolCalls, @@ -5362,6 +5364,18 @@ function existingCodexSessionHasRangeKind(db: LooDatabase, threadId: string, ran return Boolean(row); } +function existingCodexSessionHasRangeReasonCode(db: LooDatabase, threadId: string, reasonCode: string): boolean { + const row = db.prepare(` + SELECT 1 AS found + FROM prepared_source_ranges + WHERE thread_id = ? + AND range_kind = 'final_message' + AND reason_codes_json LIKE ? + LIMIT 1 + `).get(threadId, `%"${reasonCode}"%`) as { found: number } | undefined; + return Boolean(row); +} + function preparedSourceStatsForAppend(db: LooDatabase, threadId: string): { eventCount: number; ordinalOffset: number } { const row = db.prepare(` SELECT @@ -5462,6 +5476,7 @@ function mergeAppendDeltaSession(seed: ExistingCodexSessionSeed, delta: Imported updatedAt: delta.updatedAt ?? seed.updatedAt, finalMessage, finalMessageExplicit: seed.finalMessageExplicit || delta.finalMessageExplicit, + finalMessageAuthoritative: seed.finalMessageAuthoritative || delta.finalMessageAuthoritative, plans: [...seed.plans, ...delta.plans], touchedFiles: unique([...seed.touchedFiles, ...delta.touchedFiles]).sort(), toolCalls: [...seed.toolCalls, ...delta.toolCalls], @@ -5479,6 +5494,8 @@ function mergeAppendDeltaSession(seed: ExistingCodexSessionSeed, delta: Imported } function mergeAppendDeltaFinalMessage(seed: ExistingCodexSessionSeed, delta: ImportedSession): string | null { + if (delta.finalMessageAuthoritative) return delta.finalMessage; + if (seed.finalMessageAuthoritative) return seed.finalMessage; if (delta.finalMessageExplicit) return delta.finalMessage; if (seed.finalMessageExplicit) return seed.finalMessage; return delta.finalMessage ?? seed.finalMessage; @@ -19445,6 +19462,7 @@ function parseCodexJsonl(sourcePath: string, text: string, maxEventsPerFile: num updatedAt: null, finalMessage: null, finalMessageExplicit: false, + finalMessageAuthoritative: false, plans: [], touchedFiles: [], toolCalls: [], @@ -19522,6 +19540,7 @@ function parseCodexJsonl(sourcePath: string, text: string, maxEventsPerFile: num } const textPayloads = extractTextPayloads(item); + let authoritativeFinalAnswer = false; for (const payload of textPayloads) { const metadataText = redactSafeString(payload.trim()); if (metadataText) { @@ -19542,10 +19561,15 @@ function parseCodexJsonl(sourcePath: string, text: string, maxEventsPerFile: num const plans = extractPlans(clean); for (const plan of plans) session.plans.push(plan); if (plans.length > 0) rangeKinds.add("proposed_plan"); - const finalMessage = rangeKind === "assistant_message" && isLikelyFinal(clean); - if (finalMessage) { + const explicitFinalAnswer = rangeKind === "assistant_message" && isExplicitCodexFinalAnswer(item); + const heuristicFinal = rangeKind === "assistant_message" && isLikelyFinal(clean); + if (explicitFinalAnswer || (!session.finalMessageAuthoritative && heuristicFinal)) { session.finalMessage = clean; session.finalMessageExplicit = true; + if (explicitFinalAnswer) { + session.finalMessageAuthoritative = true; + authoritativeFinalAnswer = true; + } rangeKinds.add("final_message"); } if (containsCloseoutEnvelope(clean)) rangeKinds.add("closeout"); @@ -19570,6 +19594,7 @@ function parseCodexJsonl(sourcePath: string, text: string, maxEventsPerFile: num threadId: session.threadId, observedAt: timestamp, rangeKinds: [...rangeKinds], + authoritativeFinalAnswer, eventText: eventContentTextForRecord(eventTextParts, item, timestamp) })); } @@ -19946,6 +19971,7 @@ function createPreparedSourceEventDraft(input: { threadId: string; observedAt: string | null; rangeKinds: PreparedSourceRangeKind[]; + authoritativeFinalAnswer: boolean; eventText: string; }): PreparedSourceEventDraft { const contentHash = stableId(input.record.text); @@ -19977,7 +20003,10 @@ function createPreparedSourceEventDraft(input: { rangeKind: rangeKind as PreparedSourceRangeKind, contentHash: stableId(`${contentHash}:${rangeKind}`), ordinal: input.ordinal * 100 + rangeOrdinal, - reasonCodes: preparedRangeReasonCodes(rangeKind) + reasonCodes: unique([ + ...preparedRangeReasonCodes(rangeKind), + ...(rangeKind === "final_message" && input.authoritativeFinalAnswer ? ["codex_explicit_final_answer"] : []) + ]) }; }) }; @@ -20011,6 +20040,16 @@ function textRangeKind(item: any): PreparedSourceRangeKind { return "event_metadata"; } +function isExplicitCodexFinalAnswer(item: any): boolean { + const phase = stringOrNull( + item.response_item?.phase + ?? item.event_msg?.phase + ?? item.message?.phase + ?? item.payload?.phase + )?.toLowerCase(); + return phase === "final_answer"; +} + function containsCloseoutEnvelope(text: string): boolean { return /|closeout state\s*:/i.test(text); } diff --git a/tests/codex-index.test.ts b/tests/codex-index.test.ts index a898216b..7ca7e09d 100644 --- a/tests/codex-index.test.ts +++ b/tests/codex-index.test.ts @@ -1,5 +1,5 @@ import assert from "node:assert/strict"; -import { mkdtempSync, rmSync, symlinkSync, utimesSync, writeFileSync, mkdirSync } from "node:fs"; +import { appendFileSync, mkdtempSync, rmSync, symlinkSync, utimesSync, writeFileSync, mkdirSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import test from "node:test"; @@ -231,6 +231,98 @@ test("compacted and tool output text cannot overwrite assistant final messages", } }); +test("explicit Codex final_answer phase outranks later assistant commentary", () => { + const root = mkdtempSync(join(tmpdir(), "loo-codex-explicit-final-")); + const sessions = join(root, "sessions"); + mkdirSync(sessions, { recursive: true }); + const threadPath = join(sessions, "rollout-2026-07-29T00-00-00-019f-explicit-final.jsonl"); + const explicitFinal = "SYNTHETIC_ACK_EXPLICIT_20260729"; + const lines = [ + { timestamp: "2026-07-29T00:00:00Z", session_meta: { payload: { id: "019f-explicit-final" } } }, + { + timestamp: "2026-07-29T00:00:01Z", + event_msg: { + type: "agent_message", + phase: "final_answer", + message: explicitFinal + } + }, + { + timestamp: "2026-07-29T00:00:01Z", + response_item: { + type: "message", + role: "assistant", + phase: "final_answer", + content: [{ type: "output_text", text: explicitFinal }] + } + }, + { + timestamp: "2026-07-29T00:00:02Z", + event_msg: { + type: "agent_message", + message: "Final monitoring commentary must not replace the explicit answer." + } + } + ]; + writeFileSync(threadPath, lines.map((line) => JSON.stringify(line)).join("\n") + "\n"); + + const db = createDatabase(join(root, "orchestrator.sqlite")); + try { + const result = indexCodexSessions(db, { roots: [sessions], maxFiles: 10 }); + assert.deepEqual(result.errors, []); + + const final = getCodexFinalMessages(db, { threadId: "019f-explicit-final", limit: 5 })[0]?.text ?? ""; + assert.equal(final, explicitFinal); + } finally { + db.close(); + rmSync(root, { recursive: true, force: true }); + } +}); + +test("append indexing preserves an existing explicit Codex final_answer", () => { + const root = mkdtempSync(join(tmpdir(), "loo-codex-append-explicit-final-")); + const sessions = join(root, "sessions"); + mkdirSync(sessions, { recursive: true }); + const threadPath = join(sessions, "rollout-2026-07-29T00-01-00-019f-append-explicit-final.jsonl"); + const explicitFinal = "SYNTHETIC_ACK_APPEND_20260729"; + const initialLines = [ + { timestamp: "2026-07-29T00:01:00Z", session_meta: { payload: { id: "019f-append-explicit-final" } } }, + { + timestamp: "2026-07-29T00:01:01Z", + response_item: { + type: "message", + role: "assistant", + phase: "final_answer", + content: [{ type: "output_text", text: explicitFinal }] + } + } + ]; + writeFileSync(threadPath, initialLines.map((line) => JSON.stringify(line)).join("\n") + "\n"); + + const db = createDatabase(join(root, "orchestrator.sqlite")); + try { + const initial = indexCodexSessions(db, { roots: [sessions], maxFiles: 10 }); + assert.deepEqual(initial.errors, []); + assert.equal(getCodexFinalMessages(db, { threadId: "019f-append-explicit-final", limit: 5 })[0]?.text, explicitFinal); + + appendFileSync(threadPath, JSON.stringify({ + timestamp: "2026-07-29T00:01:02Z", + event_msg: { + type: "agent_message", + message: "Final follow-up commentary must not replace the prior explicit answer." + } + }) + "\n"); + + const appended = indexCodexSessions(db, { roots: [sessions], maxFiles: 10 }); + assert.deepEqual(appended.errors, []); + assert.equal(appended.appendDeltaIndexedFiles, 1); + assert.equal(getCodexFinalMessages(db, { threadId: "019f-append-explicit-final", limit: 5 })[0]?.text, explicitFinal); + } finally { + db.close(); + rmSync(root, { recursive: true, force: true }); + } +}); + test("tool-only compacted sessions do not synthesize final messages", () => { const root = mkdtempSync(join(tmpdir(), "loo-codex-no-assistant-final-")); const sessions = join(root, "sessions"); From e20f1d7c2b83643fea97b369e631c5335ab3e3c0 Mon Sep 17 00:00:00 2001 From: Eva Date: Wed, 29 Jul 2026 04:21:32 +0700 Subject: [PATCH 2/4] test(core): isolate explicit final envelope coverage --- packages/core/src/index.ts | 4 +- tests/codex-index.test.ts | 77 ++++++++++++++++++++++---------------- 2 files changed, 46 insertions(+), 35 deletions(-) diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 76085c88..0026c461 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -5370,9 +5370,9 @@ function existingCodexSessionHasRangeReasonCode(db: LooDatabase, threadId: strin FROM prepared_source_ranges WHERE thread_id = ? AND range_kind = 'final_message' - AND reason_codes_json LIKE ? + AND instr(reason_codes_json, ?) > 0 LIMIT 1 - `).get(threadId, `%"${reasonCode}"%`) as { found: number } | undefined; + `).get(threadId, JSON.stringify(reasonCode)) as { found: number } | undefined; return Boolean(row); } diff --git a/tests/codex-index.test.ts b/tests/codex-index.test.ts index 7ca7e09d..994d951f 100644 --- a/tests/codex-index.test.ts +++ b/tests/codex-index.test.ts @@ -231,53 +231,64 @@ test("compacted and tool output text cannot overwrite assistant final messages", } }); -test("explicit Codex final_answer phase outranks later assistant commentary", () => { - const root = mkdtempSync(join(tmpdir(), "loo-codex-explicit-final-")); - const sessions = join(root, "sessions"); - mkdirSync(sessions, { recursive: true }); - const threadPath = join(sessions, "rollout-2026-07-29T00-00-00-019f-explicit-final.jsonl"); - const explicitFinal = "SYNTHETIC_ACK_EXPLICIT_20260729"; - const lines = [ - { timestamp: "2026-07-29T00:00:00Z", session_meta: { payload: { id: "019f-explicit-final" } } }, - { +for (const fixture of [ + { + shape: "event_msg", + finalItem: (text: string) => ({ timestamp: "2026-07-29T00:00:01Z", event_msg: { type: "agent_message", phase: "final_answer", - message: explicitFinal + message: text } - }, - { + }) + }, + { + shape: "response_item", + finalItem: (text: string) => ({ timestamp: "2026-07-29T00:00:01Z", response_item: { type: "message", role: "assistant", phase: "final_answer", - content: [{ type: "output_text", text: explicitFinal }] + content: [{ type: "output_text", text }] } - }, - { - timestamp: "2026-07-29T00:00:02Z", - event_msg: { - type: "agent_message", - message: "Final monitoring commentary must not replace the explicit answer." + }) + } +]) { + test(`explicit Codex final_answer phase on ${fixture.shape} outranks later assistant commentary`, () => { + const root = mkdtempSync(join(tmpdir(), `loo-codex-explicit-final-${fixture.shape}-`)); + const sessions = join(root, "sessions"); + mkdirSync(sessions, { recursive: true }); + const threadId = `019f-explicit-final-${fixture.shape}`; + const threadPath = join(sessions, `rollout-2026-07-29T00-00-00-${threadId}.jsonl`); + const explicitFinal = `SYNTHETIC_ACK_EXPLICIT_${fixture.shape.toUpperCase()}_20260729`; + const lines = [ + { timestamp: "2026-07-29T00:00:00Z", session_meta: { payload: { id: threadId } } }, + fixture.finalItem(explicitFinal), + { + timestamp: "2026-07-29T00:00:02Z", + event_msg: { + type: "agent_message", + message: "Final monitoring commentary must not replace the explicit answer." + } } - } - ]; - writeFileSync(threadPath, lines.map((line) => JSON.stringify(line)).join("\n") + "\n"); + ]; + writeFileSync(threadPath, lines.map((line) => JSON.stringify(line)).join("\n") + "\n"); - const db = createDatabase(join(root, "orchestrator.sqlite")); - try { - const result = indexCodexSessions(db, { roots: [sessions], maxFiles: 10 }); - assert.deepEqual(result.errors, []); + const db = createDatabase(join(root, "orchestrator.sqlite")); + try { + const result = indexCodexSessions(db, { roots: [sessions], maxFiles: 10 }); + assert.deepEqual(result.errors, []); - const final = getCodexFinalMessages(db, { threadId: "019f-explicit-final", limit: 5 })[0]?.text ?? ""; - assert.equal(final, explicitFinal); - } finally { - db.close(); - rmSync(root, { recursive: true, force: true }); - } -}); + const final = getCodexFinalMessages(db, { threadId, limit: 5 })[0]?.text ?? ""; + assert.equal(final, explicitFinal); + } finally { + db.close(); + rmSync(root, { recursive: true, force: true }); + } + }); +} test("append indexing preserves an existing explicit Codex final_answer", () => { const root = mkdtempSync(join(tmpdir(), "loo-codex-append-explicit-final-")); From f70fad852267bc1755f46ce14e693170fcae64de Mon Sep 17 00:00:00 2001 From: Eva Date: Wed, 29 Jul 2026 04:24:16 +0700 Subject: [PATCH 3/4] fix(core): reindex legacy final-answer ranges --- packages/core/src/index.ts | 6 +-- tests/index-fast-skip.test.ts | 71 +++++++++++++++++++++++++++- tests/prepared-cards.test.ts | 2 +- tests/prepared-source-ranges.test.ts | 2 +- tests/session-diff.test.ts | 6 +-- 5 files changed, 78 insertions(+), 9 deletions(-) diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 0026c461..9f5b8945 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -412,7 +412,7 @@ export type PreparedSourceRange = { ordinal: number; sourceHash: string; contentHash: string; - extractorVersion: "prepared-source-ranges-v1"; + extractorVersion: "prepared-source-ranges-v2"; privacyClass: "public_safe_metadata"; omissionStatus: "metadata_only"; confidence: number; @@ -3136,7 +3136,7 @@ const CODEX_RECOVERY_MAX_BYTES_PER_FILE = 1_073_741_824; const CODEX_RECOVERY_MAX_EVENTS_PER_FILE = 1_000_000; const CODEX_EVENT_CONTENT_CHAR_LIMIT = 8000; const CODEX_EVENT_CONTENT_REBUILD_COMMAND = 'loo index codex "$HOME/.codex/sessions" "$HOME/.codex/archived_sessions"'; -const PREPARED_SOURCE_EXTRACTOR_VERSION = "prepared-source-ranges-v1" as const; +const PREPARED_SOURCE_EXTRACTOR_VERSION = "prepared-source-ranges-v2" as const; const SUMMARY_LEAF_EXTRACTOR_VERSION = "summary-leaves-v1" as const; const PREPARED_CARD_EXTRACTOR_VERSION = "prepared-cards-v2" as const; const SUMMARY_LEAF_EDGE_DELETE_BATCH_SIZE = 400; @@ -10640,7 +10640,7 @@ type PreparedSourceRangeRow = { ordinal: number; sourceHash: string; contentHash: string; - extractorVersion: "prepared-source-ranges-v1"; + extractorVersion: "prepared-source-ranges-v2"; privacyClass: "public_safe_metadata"; omissionStatus: "metadata_only"; confidence: number; diff --git a/tests/index-fast-skip.test.ts b/tests/index-fast-skip.test.ts index ac8dc8db..787a2c7a 100644 --- a/tests/index-fast-skip.test.ts +++ b/tests/index-fast-skip.test.ts @@ -815,7 +815,7 @@ test("NULL cached extractor versions in an existing database force backfill once LIMIT 1 `).get() as { metadata: string | null; preparedRanges: string | null; summaryLeaves: string | null; preparedCards: string | null }; assert.equal(row.metadata, "session-metadata-v4"); - assert.equal(row.preparedRanges, "prepared-source-ranges-v1"); + assert.equal(row.preparedRanges, "prepared-source-ranges-v2"); assert.equal(row.summaryLeaves, "summary-leaves-v1"); assert.equal(row.preparedCards, "prepared-cards-v2"); } finally { @@ -825,3 +825,72 @@ test("NULL cached extractor versions in an existing database force backfill once rmSync(root, { recursive: true, force: true }); } }); + +test("legacy v1 prepared ranges force a full reparse before append authority is trusted", () => { + const root = mkdtempSync(join(tmpdir(), "loo-fast-skip-final-authority-upgrade-")); + try { + const sessionsDir = join(root, "sessions"); + mkdirSync(sessionsDir, { recursive: true }); + const threadId = "019f-final-authority-upgrade"; + const file = join(sessionsDir, `rollout-2026-07-29T00-02-00-${threadId}.jsonl`); + const explicitFinal = "SYNTHETIC_ACK_UPGRADE_20260729"; + writeFileSync(file, [ + JSON.stringify({ timestamp: "2026-07-29T00:02:00Z", session_meta: { payload: { id: threadId } } }), + JSON.stringify({ + timestamp: "2026-07-29T00:02:01Z", + response_item: { + type: "message", + role: "assistant", + phase: "final_answer", + content: [{ type: "output_text", text: explicitFinal }] + } + }), + "" + ].join("\n")); + + const db = createDatabase(join(root, "orchestrator.sqlite")); + try { + assert.equal(indexCodexSessions(db, { roots: [sessionsDir], maxFiles: 10 }).indexedFiles, 1); + db.prepare(` + UPDATE codex_source_files + SET prepared_range_extractor_version = 'prepared-source-ranges-v1' + `).run(); + db.prepare(` + UPDATE prepared_source_ranges + SET reason_codes_json = '["prepared_source_range","metadata_only","range_kind:final_message"]' + WHERE range_kind = 'final_message' + `).run(); + appendFileSync(file, JSON.stringify({ + timestamp: "2026-07-29T00:02:02Z", + event_msg: { + type: "agent_message", + message: "Final legacy append commentary must not replace the explicit answer." + } + }) + "\n"); + + const upgraded = indexCodexSessions(db, { roots: [sessionsDir], maxFiles: 10 }); + assert.equal(upgraded.indexedFiles, 1); + assert.equal(upgraded.appendDeltaIndexedFiles, 0); + assert.equal(describeSession(db, threadId)?.finalMessage, explicitFinal); + + const source = db.prepare(` + SELECT prepared_range_extractor_version AS version + FROM codex_source_files + WHERE source_path = ? + `).get(file) as { version: string } | undefined; + const authoritative = db.prepare(` + SELECT COUNT(*) AS count + FROM prepared_source_ranges + WHERE thread_id = ? + AND range_kind = 'final_message' + AND instr(reason_codes_json, '"codex_explicit_final_answer"') > 0 + `).get(threadId) as { count: number }; + assert.equal(source?.version, "prepared-source-ranges-v2"); + assert.equal(authoritative.count, 1); + } finally { + db.close(); + } + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); diff --git a/tests/prepared-cards.test.ts b/tests/prepared-cards.test.ts index 6ebd4f1f..df2b35b0 100644 --- a/tests/prepared-cards.test.ts +++ b/tests/prepared-cards.test.ts @@ -1834,7 +1834,7 @@ test("prepared-card all-thread refresh batches work-state lookup families", () = 40, 2, `2026-07-05T12:${minute}:00.000Z`, - "prepared-source-ranges-v1", + "prepared-source-ranges-v2", "public_safe_metadata", "metadata_only", 0.96, diff --git a/tests/prepared-source-ranges.test.ts b/tests/prepared-source-ranges.test.ts index 9eb12cad..9fa56337 100644 --- a/tests/prepared-source-ranges.test.ts +++ b/tests/prepared-source-ranges.test.ts @@ -325,7 +325,7 @@ test("prepared source ranges are public-safe opaque refs with hashes and no raw assert.match(range.eventRef, /^codex_event:/); assert.match(range.sourcePathRef, /^codex_source:/); assert.equal(range.threadId, "019f-prepared-ranges"); - assert.equal(range.extractorVersion, "prepared-source-ranges-v1"); + assert.equal(range.extractorVersion, "prepared-source-ranges-v2"); assert.equal(range.privacyClass, "public_safe_metadata"); assert.equal(range.omissionStatus, "metadata_only"); assert.equal(range.sourceHash.length, 32); diff --git a/tests/session-diff.test.ts b/tests/session-diff.test.ts index 71b96c2b..3a626c38 100644 --- a/tests/session-diff.test.ts +++ b/tests/session-diff.test.ts @@ -184,7 +184,7 @@ function insertSession(db: ReturnType, threadId: string, 1783555200000, "2026-07-09T00:00:00.000Z", "metadata-v1", - "prepared-source-ranges-v1", + "prepared-source-ranges-v2", "summary-leaves-v1", "prepared-cards-v2" ); @@ -231,7 +231,7 @@ function insertPreparedRange( input.ordinal * 100 + 80, input.ordinal, observedAt, - "prepared-source-ranges-v1", + "prepared-source-ranges-v2", "public_safe_metadata", "metadata_only", input.confidence ?? 0.91, @@ -264,7 +264,7 @@ function insertPreparedRange( input.ordinal * 100 + 80, input.ordinal, observedAt, - "prepared-source-ranges-v1", + "prepared-source-ranges-v2", "public_safe_metadata", "metadata_only", input.confidence ?? 0.91, From 94f4583160a30bac4f252bdd9aacda230d55cc43 Mon Sep 17 00:00:00 2001 From: Eva Date: Wed, 29 Jul 2026 04:32:41 +0700 Subject: [PATCH 4/4] fix(core): preserve synthetic prepared ranges --- packages/core/src/index.ts | 8 ++++---- tests/index-fast-skip.test.ts | 17 ++++++++++------- tests/prepared-cards.test.ts | 2 +- tests/prepared-source-ranges.test.ts | 2 +- tests/session-diff.test.ts | 6 +++--- 5 files changed, 19 insertions(+), 16 deletions(-) diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 9f5b8945..f56f7f38 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -412,7 +412,7 @@ export type PreparedSourceRange = { ordinal: number; sourceHash: string; contentHash: string; - extractorVersion: "prepared-source-ranges-v2"; + extractorVersion: "prepared-source-ranges-v1"; privacyClass: "public_safe_metadata"; omissionStatus: "metadata_only"; confidence: number; @@ -2682,7 +2682,7 @@ export type RecallProfile = { }; const SESSION_METADATA_SCHEMA_VERSION = 4; -const SESSION_METADATA_EXTRACTOR_VERSION = `session-metadata-v${SESSION_METADATA_SCHEMA_VERSION}` as const; +const SESSION_METADATA_EXTRACTOR_VERSION = "session-metadata-v4-final-answer-v2" as const; const RETRIEVAL_TELEMETRY_MIGRATION_ID = "2026-07-06-retrieval-telemetry"; const RETRIEVAL_TELEMETRY_SESSION_KEY_MIGRATION_ID = "2026-07-06-retrieval-telemetry-session-key"; const RETRIEVAL_TELEMETRY_ENGINE_VERSION = "field-weighted-fts-v1"; @@ -3136,7 +3136,7 @@ const CODEX_RECOVERY_MAX_BYTES_PER_FILE = 1_073_741_824; const CODEX_RECOVERY_MAX_EVENTS_PER_FILE = 1_000_000; const CODEX_EVENT_CONTENT_CHAR_LIMIT = 8000; const CODEX_EVENT_CONTENT_REBUILD_COMMAND = 'loo index codex "$HOME/.codex/sessions" "$HOME/.codex/archived_sessions"'; -const PREPARED_SOURCE_EXTRACTOR_VERSION = "prepared-source-ranges-v2" as const; +const PREPARED_SOURCE_EXTRACTOR_VERSION = "prepared-source-ranges-v1" as const; const SUMMARY_LEAF_EXTRACTOR_VERSION = "summary-leaves-v1" as const; const PREPARED_CARD_EXTRACTOR_VERSION = "prepared-cards-v2" as const; const SUMMARY_LEAF_EDGE_DELETE_BATCH_SIZE = 400; @@ -10640,7 +10640,7 @@ type PreparedSourceRangeRow = { ordinal: number; sourceHash: string; contentHash: string; - extractorVersion: "prepared-source-ranges-v2"; + extractorVersion: "prepared-source-ranges-v1"; privacyClass: "public_safe_metadata"; omissionStatus: "metadata_only"; confidence: number; diff --git a/tests/index-fast-skip.test.ts b/tests/index-fast-skip.test.ts index 787a2c7a..8cef73ec 100644 --- a/tests/index-fast-skip.test.ts +++ b/tests/index-fast-skip.test.ts @@ -814,8 +814,8 @@ test("NULL cached extractor versions in an existing database force backfill once FROM codex_source_files LIMIT 1 `).get() as { metadata: string | null; preparedRanges: string | null; summaryLeaves: string | null; preparedCards: string | null }; - assert.equal(row.metadata, "session-metadata-v4"); - assert.equal(row.preparedRanges, "prepared-source-ranges-v2"); + assert.equal(row.metadata, "session-metadata-v4-final-answer-v2"); + assert.equal(row.preparedRanges, "prepared-source-ranges-v1"); assert.equal(row.summaryLeaves, "summary-leaves-v1"); assert.equal(row.preparedCards, "prepared-cards-v2"); } finally { @@ -826,7 +826,7 @@ test("NULL cached extractor versions in an existing database force backfill once } }); -test("legacy v1 prepared ranges force a full reparse before append authority is trusted", () => { +test("legacy session extraction forces a full reparse before append authority is trusted", () => { const root = mkdtempSync(join(tmpdir(), "loo-fast-skip-final-authority-upgrade-")); try { const sessionsDir = join(root, "sessions"); @@ -853,7 +853,7 @@ test("legacy v1 prepared ranges force a full reparse before append authority is assert.equal(indexCodexSessions(db, { roots: [sessionsDir], maxFiles: 10 }).indexedFiles, 1); db.prepare(` UPDATE codex_source_files - SET prepared_range_extractor_version = 'prepared-source-ranges-v1' + SET metadata_extractor_version = 'session-metadata-v4' `).run(); db.prepare(` UPDATE prepared_source_ranges @@ -874,10 +874,12 @@ test("legacy v1 prepared ranges force a full reparse before append authority is assert.equal(describeSession(db, threadId)?.finalMessage, explicitFinal); const source = db.prepare(` - SELECT prepared_range_extractor_version AS version + SELECT + metadata_extractor_version AS metadataVersion, + prepared_range_extractor_version AS preparedRangeVersion FROM codex_source_files WHERE source_path = ? - `).get(file) as { version: string } | undefined; + `).get(file) as { metadataVersion: string; preparedRangeVersion: string } | undefined; const authoritative = db.prepare(` SELECT COUNT(*) AS count FROM prepared_source_ranges @@ -885,7 +887,8 @@ test("legacy v1 prepared ranges force a full reparse before append authority is AND range_kind = 'final_message' AND instr(reason_codes_json, '"codex_explicit_final_answer"') > 0 `).get(threadId) as { count: number }; - assert.equal(source?.version, "prepared-source-ranges-v2"); + assert.equal(source?.metadataVersion, "session-metadata-v4-final-answer-v2"); + assert.equal(source?.preparedRangeVersion, "prepared-source-ranges-v1"); assert.equal(authoritative.count, 1); } finally { db.close(); diff --git a/tests/prepared-cards.test.ts b/tests/prepared-cards.test.ts index df2b35b0..6ebd4f1f 100644 --- a/tests/prepared-cards.test.ts +++ b/tests/prepared-cards.test.ts @@ -1834,7 +1834,7 @@ test("prepared-card all-thread refresh batches work-state lookup families", () = 40, 2, `2026-07-05T12:${minute}:00.000Z`, - "prepared-source-ranges-v2", + "prepared-source-ranges-v1", "public_safe_metadata", "metadata_only", 0.96, diff --git a/tests/prepared-source-ranges.test.ts b/tests/prepared-source-ranges.test.ts index 9fa56337..9eb12cad 100644 --- a/tests/prepared-source-ranges.test.ts +++ b/tests/prepared-source-ranges.test.ts @@ -325,7 +325,7 @@ test("prepared source ranges are public-safe opaque refs with hashes and no raw assert.match(range.eventRef, /^codex_event:/); assert.match(range.sourcePathRef, /^codex_source:/); assert.equal(range.threadId, "019f-prepared-ranges"); - assert.equal(range.extractorVersion, "prepared-source-ranges-v2"); + assert.equal(range.extractorVersion, "prepared-source-ranges-v1"); assert.equal(range.privacyClass, "public_safe_metadata"); assert.equal(range.omissionStatus, "metadata_only"); assert.equal(range.sourceHash.length, 32); diff --git a/tests/session-diff.test.ts b/tests/session-diff.test.ts index 3a626c38..71b96c2b 100644 --- a/tests/session-diff.test.ts +++ b/tests/session-diff.test.ts @@ -184,7 +184,7 @@ function insertSession(db: ReturnType, threadId: string, 1783555200000, "2026-07-09T00:00:00.000Z", "metadata-v1", - "prepared-source-ranges-v2", + "prepared-source-ranges-v1", "summary-leaves-v1", "prepared-cards-v2" ); @@ -231,7 +231,7 @@ function insertPreparedRange( input.ordinal * 100 + 80, input.ordinal, observedAt, - "prepared-source-ranges-v2", + "prepared-source-ranges-v1", "public_safe_metadata", "metadata_only", input.confidence ?? 0.91, @@ -264,7 +264,7 @@ function insertPreparedRange( input.ordinal * 100 + 80, input.ordinal, observedAt, - "prepared-source-ranges-v2", + "prepared-source-ranges-v1", "public_safe_metadata", "metadata_only", input.confidence ?? 0.91,