0036_schema_repair_sql.py
python
sha256:94ef169c149a452bff7c604ded8b280b19bd477c2dabcb56972780b0b784c7aa
Merge 'fix/assignee-sigil-inline' into 'dev' — proposal: As…
Human
2 days ago
| 1 | """Schema repair via raw SQL — idempotent ADD COLUMN IF NOT EXISTS. |
| 2 | |
| 3 | 0035 was stamped before it ran on staging. This migration does the same |
| 4 | job using op.execute(text(...)) with PostgreSQL's native IF NOT EXISTS |
| 5 | syntax, which is the proven pattern already used in this migration chain. |
| 6 | |
| 7 | Revision ID: 0036 |
| 8 | Revises: 0035 |
| 9 | """ |
| 10 | from __future__ import annotations |
| 11 | |
| 12 | from alembic import op |
| 13 | from sqlalchemy import text |
| 14 | |
| 15 | revision = "0036" |
| 16 | down_revision = "0035" |
| 17 | branch_labels = None |
| 18 | depends_on = None |
| 19 | |
| 20 | |
| 21 | def upgrade() -> None: |
| 22 | # musehub_commits — columns from migrations 0019, 0020, 0021 |
| 23 | op.execute(text("ALTER TABLE musehub_commits ADD COLUMN IF NOT EXISTS agent_id VARCHAR(255) DEFAULT ''")) |
| 24 | op.execute(text("ALTER TABLE musehub_commits ADD COLUMN IF NOT EXISTS model_id VARCHAR(255) DEFAULT ''")) |
| 25 | op.execute(text("ALTER TABLE musehub_commits ADD COLUMN IF NOT EXISTS commit_branch VARCHAR(255)")) |
| 26 | op.execute(text("ALTER TABLE musehub_commits ADD COLUMN IF NOT EXISTS signature TEXT DEFAULT ''")) |
| 27 | op.execute(text("ALTER TABLE musehub_commits ADD COLUMN IF NOT EXISTS signer_public_key TEXT DEFAULT ''")) |
| 28 | op.execute(text("ALTER TABLE musehub_commits ADD COLUMN IF NOT EXISTS signer_key_id VARCHAR(255) DEFAULT ''")) |
| 29 | op.execute(text("ALTER TABLE musehub_commits ADD COLUMN IF NOT EXISTS toolchain_id VARCHAR(255) DEFAULT ''")) |
| 30 | op.execute(text("ALTER TABLE musehub_commits ADD COLUMN IF NOT EXISTS sem_ver_bump VARCHAR(10) DEFAULT 'none'")) |
| 31 | op.execute(text("ALTER TABLE musehub_commits ADD COLUMN IF NOT EXISTS breaking_changes TEXT[]")) |
| 32 | op.execute(text("ALTER TABLE musehub_commits ADD COLUMN IF NOT EXISTS reviewed_by TEXT[]")) |
| 33 | op.execute(text("ALTER TABLE musehub_commits ADD COLUMN IF NOT EXISTS test_runs INTEGER DEFAULT 0")) |
| 34 | op.execute(text("ALTER TABLE musehub_commits ADD COLUMN IF NOT EXISTS prompt_hash VARCHAR(255) DEFAULT ''")) |
| 35 | op.execute(text("ALTER TABLE musehub_commits ADD COLUMN IF NOT EXISTS structured_delta JSONB")) |
| 36 | |
| 37 | # musehub_symbol_history_entries — columns from 0018, 0031 |
| 38 | op.execute(text("ALTER TABLE musehub_symbol_history_entries ADD COLUMN IF NOT EXISTS op_payload JSONB")) |
| 39 | op.execute(text("ALTER TABLE musehub_symbol_history_entries ADD COLUMN IF NOT EXISTS message TEXT")) |
| 40 | op.execute(text("ALTER TABLE musehub_symbol_history_entries ADD COLUMN IF NOT EXISTS commit_branch VARCHAR(512)")) |
| 41 | |
| 42 | # musehub_symbol_vitals — table from 0031, coupling_count from 0032 |
| 43 | op.execute(text(""" |
| 44 | CREATE TABLE IF NOT EXISTS musehub_symbol_vitals ( |
| 45 | repo_id VARCHAR(128) NOT NULL REFERENCES musehub_repos(repo_id) ON DELETE CASCADE, |
| 46 | address VARCHAR(512) NOT NULL, |
| 47 | first_introduced TIMESTAMPTZ, |
| 48 | change_count INTEGER NOT NULL DEFAULT 0, |
| 49 | version_count INTEGER NOT NULL DEFAULT 0, |
| 50 | op_add INTEGER NOT NULL DEFAULT 0, |
| 51 | op_modify INTEGER NOT NULL DEFAULT 0, |
| 52 | op_delete INTEGER NOT NULL DEFAULT 0, |
| 53 | op_move INTEGER NOT NULL DEFAULT 0, |
| 54 | coupling_count INTEGER NOT NULL DEFAULT 0, |
| 55 | PRIMARY KEY (repo_id, address) |
| 56 | ) |
| 57 | """)) |
| 58 | op.execute(text("CREATE INDEX IF NOT EXISTS ix_symbol_vitals_repo ON musehub_symbol_vitals (repo_id)")) |
| 59 | op.execute(text("ALTER TABLE musehub_symbol_vitals ADD COLUMN IF NOT EXISTS coupling_count INTEGER NOT NULL DEFAULT 0")) |
| 60 | |
| 61 | # musehub_symbol_coupling — table from 0031 |
| 62 | op.execute(text(""" |
| 63 | CREATE TABLE IF NOT EXISTS musehub_symbol_coupling ( |
| 64 | repo_id VARCHAR(128) NOT NULL REFERENCES musehub_repos(repo_id) ON DELETE CASCADE, |
| 65 | address VARCHAR(512) NOT NULL, |
| 66 | co_address VARCHAR(512) NOT NULL, |
| 67 | shared_commits INTEGER NOT NULL DEFAULT 0, |
| 68 | PRIMARY KEY (repo_id, address, co_address) |
| 69 | ) |
| 70 | """)) |
| 71 | op.execute(text("CREATE INDEX IF NOT EXISTS ix_symbol_coupling_repo_address ON musehub_symbol_coupling (repo_id, address)")) |
| 72 | |
| 73 | # musehub_coord_records — rename record_uuid → record_id from 0027 |
| 74 | op.execute(text(""" |
| 75 | DO $$ |
| 76 | BEGIN |
| 77 | IF EXISTS ( |
| 78 | SELECT 1 FROM information_schema.columns |
| 79 | WHERE table_name='musehub_coord_records' AND column_name='record_uuid' |
| 80 | ) AND NOT EXISTS ( |
| 81 | SELECT 1 FROM information_schema.columns |
| 82 | WHERE table_name='musehub_coord_records' AND column_name='record_id' |
| 83 | ) THEN |
| 84 | ALTER TABLE musehub_coord_records RENAME COLUMN record_uuid TO record_id; |
| 85 | ALTER TABLE musehub_coord_records ALTER COLUMN record_id TYPE VARCHAR(128); |
| 86 | END IF; |
| 87 | END $$ |
| 88 | """)) |
| 89 | |
| 90 | # musehub_file_last_commits — table from 0034 |
| 91 | op.execute(text(""" |
| 92 | CREATE TABLE IF NOT EXISTS musehub_file_last_commits ( |
| 93 | repo_id VARCHAR(128) NOT NULL REFERENCES musehub_repos(repo_id) ON DELETE CASCADE, |
| 94 | branch VARCHAR(255) NOT NULL, |
| 95 | path TEXT NOT NULL, |
| 96 | commit_id VARCHAR(128) NOT NULL, |
| 97 | commit_message TEXT NOT NULL DEFAULT '', |
| 98 | commit_author VARCHAR(255) NOT NULL DEFAULT '', |
| 99 | commit_timestamp TIMESTAMPTZ NOT NULL, |
| 100 | agent_id VARCHAR(128), |
| 101 | model_id VARCHAR(128), |
| 102 | PRIMARY KEY (repo_id, branch, path) |
| 103 | ) |
| 104 | """)) |
| 105 | op.execute(text("CREATE INDEX IF NOT EXISTS ix_file_last_commits_repo_branch ON musehub_file_last_commits (repo_id, branch)")) |
| 106 | |
| 107 | |
| 108 | def downgrade() -> None: |
| 109 | # Drop tables this migration conditionally created (IF EXISTS — idempotent with owning migrations). |
| 110 | op.execute(text("DROP INDEX IF EXISTS ix_symbol_coupling_repo_address")) |
| 111 | op.execute(text("DROP TABLE IF EXISTS musehub_symbol_coupling")) |
| 112 | op.execute(text("DROP INDEX IF EXISTS ix_symbol_vitals_repo")) |
| 113 | op.execute(text("DROP TABLE IF EXISTS musehub_symbol_vitals")) |
| 114 | op.execute(text("DROP INDEX IF EXISTS ix_file_last_commits_repo_branch")) |
| 115 | op.execute(text("DROP TABLE IF EXISTS musehub_file_last_commits")) |
| 116 | # Undo column repairs — all IF EXISTS so idempotent with owning migrations. |
| 117 | for col in ("structured_delta", "prompt_hash", "test_runs", "reviewed_by", |
| 118 | "breaking_changes", "sem_ver_bump", "toolchain_id", "signer_key_id", |
| 119 | "signer_public_key", "signature", "commit_branch", "model_id", "agent_id"): |
| 120 | op.execute(text(f"ALTER TABLE musehub_commits DROP COLUMN IF EXISTS {col}")) |
| 121 | for col in ("commit_branch", "message", "op_payload"): |
| 122 | op.execute(text(f"ALTER TABLE musehub_symbol_history_entries DROP COLUMN IF EXISTS {col}")) |
File History
3 commits
sha256:94ef169c149a452bff7c604ded8b280b19bd477c2dabcb56972780b0b784c7aa
Merge 'fix/assignee-sigil-inline' into 'dev' — proposal: As…
Human
2 days ago
sha256:6b1949fc2797ca4c1936a637a4cbfec828ef56cf52398a2e74ca3c4f494e728f
fix: use wire_bytes not mpack_bytes_raw in compute_object_b…
Sonnet 4.6
patch
10 days ago
sha256:4aed3d8601c8dd3ed37074de35f11f4a9699a0a4b99d43727048fd3f8e6fd13d
chore: doc sweep, ignore wrangler build state, misc fixes
Sonnet 4.6
minor
⚠
13 days ago