From 56a339154abb761d9286ab073ab75c3ec93a83ef Mon Sep 17 00:00:00 2001 From: JSONbored <49853598+JSONbored@users.noreply.github.com> Date: Thu, 16 Jul 2026 04:14:18 -0700 Subject: [PATCH] fix(db): grandfather the 0156 migration-number collision MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 0156_draft_pr_close_policy.sql (#6454) and 0156_pull_request_screenshot_table_ presence_satisfied.sql (a same-day, independently-merged PR) both grabbed migration number 0156 relative to the same origin/main base and merged without a collision being caught. Both have already been applied to production D1 under their current filenames (confirmed via d1_migrations) — renaming either now would make wrangler try to RE-APPLY it, and both are bare ALTER TABLE ADD COLUMN statements SQLite can't guard with IF NOT EXISTS, so the re-apply would error and break the next deploy. Grandfather 0156 in KNOWN_MIGRATION_DUPLICATES, matching the exact precedent already set by 0015/0017/0074/0090 for the same "already-shipped, can't-be-renumbered" reason. --- scripts/check-migrations.mjs | 3 +++ src/db/migration-collisions.ts | 1 + test/unit/check-migrations-script.test.ts | 2 +- test/unit/migration-collisions.test.ts | 5 ++++- 4 files changed, 9 insertions(+), 2 deletions(-) diff --git a/scripts/check-migrations.mjs b/scripts/check-migrations.mjs index 0930fb0824..2613d5b437 100644 --- a/scripts/check-migrations.mjs +++ b/scripts/check-migrations.mjs @@ -26,6 +26,9 @@ // • 0090 — both 0090_contributor_cap_label (#2479) and 0090_pull_request_detail_sync_head_sha (#2527) // merged with bare ADD COLUMN statements. Preserve both filenames so already-applied databases never // replay either ALTER under a new migration name. +// • 0156 — both 0156_draft_pr_close_policy and 0156_pull_request_screenshot_table_presence_satisfied +// merged independently from the same base and were both applied to production before the collision +// surfaced; bare ADD COLUMN statements, same grandfather reasoning as 0074/0090. import { readdirSync, readFileSync } from "node:fs"; import { detectMigrationCollisions, extractMigrationNumber, KNOWN_MIGRATION_DUPLICATES, MIGRATION_FILENAME_PATTERN } from "../src/db/migration-collisions.ts"; import { detectColumnCollisions } from "../src/db/migration-column-extraction.ts"; diff --git a/src/db/migration-collisions.ts b/src/db/migration-collisions.ts index 1e32371371..8c12dfdb52 100644 --- a/src/db/migration-collisions.ts +++ b/src/db/migration-collisions.ts @@ -27,6 +27,7 @@ export const KNOWN_MIGRATION_DUPLICATES: ReadonlyMap [17, new Set(["0017_agent_recommendation_outcomes.sql", "0017_product_usage_role_retention_rollups.sql"])], [74, new Set(["0074_ai_review_cache.sql", "0074_orb_self_enrollment_disabled.sql"])], [90, new Set(["0090_contributor_cap_label.sql", "0090_pull_request_detail_sync_head_sha.sql"])], + [156, new Set(["0156_draft_pr_close_policy.sql", "0156_pull_request_screenshot_table_presence_satisfied.sql"])], ]); /** diff --git a/test/unit/check-migrations-script.test.ts b/test/unit/check-migrations-script.test.ts index 46076733a9..26b1932547 100644 --- a/test/unit/check-migrations-script.test.ts +++ b/test/unit/check-migrations-script.test.ts @@ -37,7 +37,7 @@ describe("check-migrations script", () => { it("reports every grandfathered duplicate migration number in the success summary", () => { const output = execFileSync(TSX_BIN, ["scripts/check-migrations.mjs"], { encoding: "utf8" }); - expect(output).toContain("(4 grandfathered duplicates: 0015, 0017, 0074, 0090)"); + expect(output).toContain("(5 grandfathered duplicates: 0015, 0017, 0074, 0090, 0156)"); }); it.each([ diff --git a/test/unit/migration-collisions.test.ts b/test/unit/migration-collisions.test.ts index f45dd52c08..65a249b6bd 100644 --- a/test/unit/migration-collisions.test.ts +++ b/test/unit/migration-collisions.test.ts @@ -75,7 +75,10 @@ describe("KNOWN_MIGRATION_DUPLICATES (#2550)", () => { it("stays byte-identical to scripts/check-migrations.mjs's grandfathered list", () => { // A drift here would mean the CI script and the live premerge recheck disagree about what's grandfathered // — this pins the exact set so a future addition to one side without the other is caught immediately. - expect([...KNOWN_MIGRATION_DUPLICATES.keys()].sort((a, b) => a - b)).toEqual([15, 17, 74, 90]); + expect([...KNOWN_MIGRATION_DUPLICATES.keys()].sort((a, b) => a - b)).toEqual([15, 17, 74, 90, 156]); expect(KNOWN_MIGRATION_DUPLICATES.get(90)).toEqual(new Set(["0090_contributor_cap_label.sql", "0090_pull_request_detail_sync_head_sha.sql"])); + expect(KNOWN_MIGRATION_DUPLICATES.get(156)).toEqual( + new Set(["0156_draft_pr_close_policy.sql", "0156_pull_request_screenshot_table_presence_satisfied.sql"]), + ); }); });