-- ============================================================================ -- One-shot drift reconciliation against CT 102's `tasks` database. -- -- Background: the DB was historically bootstrapped with `drizzle-kit push`, -- which mutates the schema directly without recording rows in -- `drizzle.__drizzle_migrations`. As a result, on 2026-06-02 the ledger -- contained ZERO rows even though migrations 0000, 0001, 0003-0006 were -- fully applied and 0007 was partially applied (audit_log existed, but its -- ALTER on markdown_backlog_items had silently failed because that table -- itself was never created — migration 0002 ran on neither code path). -- -- This script: -- 1. Creates the two genuinely-missing tables (`markdown_backlog_items`, -- `cursor_sync_mappings`) at their FINAL post-0007 shape — i.e. with -- `markdown_backlog_items.archived_at` already in place and FKs already -- pointing at `workspaces.id` instead of the obsolete mid-0002 target -- of `objects.id`. We skip the bogus intermediate states the migration -- files would otherwise replay because (a) they're broken FKs we'd -- immediately re-flip in 0003 and (b) we're catching up an existing -- DB, not replaying history. -- 2. Inserts one row per migration (0000-0007) into -- `drizzle.__drizzle_migrations` with the SHA-256 hash of each -- migration file and the journal's `when` timestamp. After this, -- drizzle's migrator (which gates on `lastDbMigration.created_at < -- migration.folderMillis`) will treat every existing migration as -- already applied and only run future ones. -- -- After running this, `pnpm db:migrate` becomes a clean no-op and future -- migrations work normally. -- ============================================================================ BEGIN; -- ---------------------------------------------------------------------------- -- 1. Missing tables, created at the FINAL schema (post-0007). -- ---------------------------------------------------------------------------- CREATE TABLE IF NOT EXISTS "markdown_backlog_items" ( "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, "workspace_id" uuid NOT NULL, "kind" varchar(20) NOT NULL, "slug" varchar(200) NOT NULL, "plan_slug" varchar(200) NOT NULL, "epic_slug" varchar(200), "parent_id" uuid, "repo_path" text NOT NULL, "title" varchar(500) DEFAULT '' NOT NULL, "status" varchar(50), "priority" varchar(20), "owner" text, "frontmatter" jsonb, "body_markdown" text DEFAULT '' NOT NULL, "content_hash" varchar(64) NOT NULL, "created_at" timestamp with time zone DEFAULT now() NOT NULL, "updated_at" timestamp with time zone DEFAULT now() NOT NULL, -- From migration 0007 (the ALTER that silently failed because the table -- didn't exist). Now present at create-time. "archived_at" timestamp with time zone ); ALTER TABLE "markdown_backlog_items" ADD CONSTRAINT "markdown_backlog_items_workspace_id_workspaces_id_fk" FOREIGN KEY ("workspace_id") REFERENCES "public"."workspaces"("id") ON DELETE cascade ON UPDATE no action; ALTER TABLE "markdown_backlog_items" ADD CONSTRAINT "markdown_backlog_items_parent_id_markdown_backlog_items_id_fk" FOREIGN KEY ("parent_id") REFERENCES "public"."markdown_backlog_items"("id") ON DELETE set null ON UPDATE no action; CREATE UNIQUE INDEX IF NOT EXISTS "markdown_backlog_workspace_repo_path_unique" ON "markdown_backlog_items" USING btree ("workspace_id", "repo_path"); CREATE INDEX IF NOT EXISTS "markdown_backlog_workspace_plan_idx" ON "markdown_backlog_items" USING btree ("workspace_id", "plan_slug"); CREATE INDEX IF NOT EXISTS "markdown_backlog_parent_id_idx" ON "markdown_backlog_items" USING btree ("parent_id"); CREATE INDEX IF NOT EXISTS "markdown_backlog_workspace_kind_idx" ON "markdown_backlog_items" USING btree ("workspace_id", "kind"); CREATE TABLE IF NOT EXISTS "cursor_sync_mappings" ( "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, "workspace_id" uuid NOT NULL, "backlog_item_id" uuid NOT NULL, "cursor_plan_id" varchar(500), "cursor_item_id" varchar(500), "last_pulled_at" timestamp with time zone, "last_pushed_at" timestamp with time zone, "sync_content_hash" varchar(64), "created_at" timestamp with time zone DEFAULT now() NOT NULL, "updated_at" timestamp with time zone DEFAULT now() NOT NULL ); ALTER TABLE "cursor_sync_mappings" ADD CONSTRAINT "cursor_sync_mappings_workspace_id_workspaces_id_fk" FOREIGN KEY ("workspace_id") REFERENCES "public"."workspaces"("id") ON DELETE cascade ON UPDATE no action; ALTER TABLE "cursor_sync_mappings" ADD CONSTRAINT "cursor_sync_mappings_backlog_item_id_markdown_backlog_items_id_fk" FOREIGN KEY ("backlog_item_id") REFERENCES "public"."markdown_backlog_items"("id") ON DELETE cascade ON UPDATE no action; CREATE UNIQUE INDEX IF NOT EXISTS "cursor_sync_mappings_backlog_item_id_unique" ON "cursor_sync_mappings" USING btree ("backlog_item_id"); CREATE INDEX IF NOT EXISTS "cursor_sync_mappings_workspace_id_idx" ON "cursor_sync_mappings" USING btree ("workspace_id"); -- ---------------------------------------------------------------------------- -- 2. Stamp the drizzle ledger so every existing migration is recorded. -- -- (hash, created_at) values come from: -- - hash: shasum -a 256 of the migration file -- - created_at: `when` field in packages/database/migrations/meta/_journal.json -- -- Drizzle's migrator only re-runs migrations whose `folderMillis` is -- strictly greater than `MAX(created_at)` in this table, so the values -- have to match the journal to keep the comparison sane. -- ---------------------------------------------------------------------------- INSERT INTO drizzle.__drizzle_migrations (hash, created_at) VALUES ('564c54d7eb104751f76ff7e3b96a75b18056df4cab17ff30acdfa06d54d06bc7', 1774617985473), ('8519d59dafff5fa86c059baec9678d645edd8d5f3bfaeb2d96d3870fb9c3c180', 1774632231368), ('8a10480a136fca4aae8a9a30df1d358bba44cd382c4fcd98a47c337002e2d5f4', 1777225115319), ('2251f76466de118a202c348ed6ab42847fe9a3414de6a9c162c228f39fb8febd', 1778124738113), ('ef7e1a5a3001528caa33cb3c91aecdebdc1774fbd7c006f1d78433f4a9d220c1', 1779987416637), ('535ed60f183650952b512efe994e8b9e81cc7671f5a608af27553abf5f11b30b', 1780412597413), ('ca1fa84a89ca42079cdd2bea8bc83062283b7b8f6bb9adc6dfd559100ae7d74b', 1780413875620), ('cbdfcf54d2e8fd5093b014f198f925de6b49fc3a77e56d2d3c58a13aadc515f1', 1780424597399); COMMIT;