diff --git a/src/db/schema.ts b/src/db/schema.ts index 5327f5d229..b73fd04452 100644 --- a/src/db/schema.ts +++ b/src/db/schema.ts @@ -1034,7 +1034,9 @@ export const upstreamDriftReports = sqliteTable( issueUrl: text("issue_url"), payloadJson: text("payload_json").notNull().default("{}"), generatedAt: text("generated_at").notNull(), - updatedAt: text("updated_at").notNull(), + // Same $defaultFn house rule as every sibling updatedAt (#8369): an insert that omits the column + // must get a real ISO-8601 timestamp, not a schema-level gap waiting for a future writer to trip over. + updatedAt: text("updated_at").notNull().$defaultFn(() => nowIso()), }, (table) => ({ fingerprint: uniqueIndex("upstream_drift_reports_fingerprint_unique").on(table.fingerprint), diff --git a/test/unit/schema-timestamp-defaults.test.ts b/test/unit/schema-timestamp-defaults.test.ts index 16f4c44ba4..06a8a9ec8a 100644 --- a/test/unit/schema-timestamp-defaults.test.ts +++ b/test/unit/schema-timestamp-defaults.test.ts @@ -1,7 +1,15 @@ import { eq } from "drizzle-orm"; import { describe, expect, it } from "vitest"; import { getDb } from "../../src/db/client"; -import { aiReviewCache, aiSlopCache, linkedIssueSatisfactionCache, orbRelayPending, repositorySettings, webhookEvents } from "../../src/db/schema"; +import { + aiReviewCache, + aiSlopCache, + linkedIssueSatisfactionCache, + orbRelayPending, + repositorySettings, + upstreamDriftReports, + webhookEvents, +} from "../../src/db/schema"; import { createTestEnv } from "../helpers/d1"; const ISO = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/; @@ -102,4 +110,27 @@ describe("timestamp column defaults", () => { expect(row?.createdAt).toMatch(ISO); expect(row?.createdAt).not.toBe("CURRENT_TIMESTAMP"); }); + + it("applies upstreamDriftReports.updatedAt default on omit (#8369)", async () => { + const env = createTestEnv(); + const db = getDb(env.DB); + // Omit updatedAt — the schema $defaultFn must inject a real ISO timestamp (same house rule as every + // sibling updatedAt). generatedAt stays explicit; this issue only covers the updatedAt gap. + await db.insert(upstreamDriftReports).values({ + id: "drift-ts-default-1", + fingerprint: "fp-ts-default-1", + severity: "low", + summary: "schema defaultFn regression", + generatedAt: "2026-07-24T00:00:00.000Z", + }); + const [row] = await db + .select() + .from(upstreamDriftReports) + .where(eq(upstreamDriftReports.id, "drift-ts-default-1")) + .limit(1); + expect(row?.updatedAt).toMatch(ISO); + expect(row?.updatedAt).not.toBe("CURRENT_TIMESTAMP"); + expect(row?.updatedAt).not.toBe(""); + expect(row?.generatedAt).toBe("2026-07-24T00:00:00.000Z"); + }); });