diff --git a/src/lib/db/schemaColumns.ts b/src/lib/db/schemaColumns.ts index 068c140c69..b288072dac 100644 --- a/src/lib/db/schemaColumns.ts +++ b/src/lib/db/schemaColumns.ts @@ -240,6 +240,14 @@ export function ensureCallLogsColumns(db: SqliteDatabase) { db.exec("ALTER TABLE call_logs ADD COLUMN request_summary TEXT DEFAULT NULL"); console.log("[DB] Added call_logs.request_summary column"); } + // added by 173_call_logs_video_content_removed; back-filled here because + // resolvePreviousResponseState SELECTs it on every continuation lookup — a + // lineage that skipped the migration would throw "no such column" there + // rather than fail closed. Same hole #12470 closed for provider_connections. + if (!columnNames.has("video_content_removed")) { + db.exec("ALTER TABLE call_logs ADD COLUMN video_content_removed INTEGER NOT NULL DEFAULT 0"); + console.log("[DB] Added call_logs.video_content_removed column"); + } if (!columnNames.has("correlation_id")) { db.exec("ALTER TABLE call_logs ADD COLUMN correlation_id TEXT DEFAULT NULL"); console.log("[DB] Added call_logs.correlation_id column"); diff --git a/tests/unit/db-schema-columns-split.test.ts b/tests/unit/db-schema-columns-split.test.ts index 9e7e249a6a..0587817500 100644 --- a/tests/unit/db-schema-columns-split.test.ts +++ b/tests/unit/db-schema-columns-split.test.ts @@ -11,6 +11,7 @@ import { ensureUsageHistoryColumns, ensureProviderConnectionsColumns, ensureProxyLogsColumns, + ensureCallLogsColumns, hasColumn, hasTable, quoteIdentifier, @@ -182,3 +183,27 @@ test("ensureProviderConnectionsColumns back-fills last_ping columns on a pre-123 db.close?.(); } }); + +// #12150 P2b: `resolvePreviousResponseState` SELECTs `video_content_removed` on +// every previous_response_id lookup. Migration 173 adds it, but a lineage that +// skipped 173 would raise "no such column" there instead of failing closed, so +// the reconciliation has to carry it too — the hole #12470 closed for +// provider_connections. +test("ensureCallLogsColumns back-fills video_content_removed on a pre-173 lineage", () => { + const db = openMemoryDb(); + try { + db.exec("CREATE TABLE call_logs (id TEXT PRIMARY KEY, timestamp TEXT)"); + assert.equal(hasColumn(db, "call_logs", "video_content_removed"), false); + + ensureCallLogsColumns(db); + + assert.equal(hasColumn(db, "call_logs", "video_content_removed"), true); + const row = db + .prepare("SELECT video_content_removed AS v FROM call_logs WHERE id = ?") + .get("missing") as { v: number } | undefined; + assert.equal(row, undefined, "empty table — the column just has to be selectable"); + assert.doesNotThrow(() => ensureCallLogsColumns(db)); + } finally { + db.close?.(); + } +});