ubiquitous-invention/docs/operations/2026-06-02-db-drift-reconcile.sql

131 lines
6.4 KiB
MySQL
Raw Normal View History

-- ============================================================================
-- 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;