"""Add compliance metadata columns to ai_providers table (B-AIPROV-COMP). Adds region, hosting_type, dpa_status, retention_policy, training_on_customer_data, transfer_notice, allowed_data_classes to support AI provider compliance checks. Revision ID: 0119 Revises: 0118 """ from alembic import op import sqlalchemy as sa from sqlalchemy.dialects.postgresql import JSONB revision = "0119" down_revision = "0118" branch_labels = None depends_on = None def _table_exists(conn, table_name: str) -> bool: """True when the table exists (dual-path convergence, Gate B). On a fresh install the ai_assistant plugin SQL migration has not run yet when Alembic reaches this revision — skip instead of failing. The plugin-side migration adds the same columns idempotently. """ row = conn.execute( sa.text("SELECT to_regclass(:tname) IS NOT NULL"), {"tname": f"public.{table_name}"}, ).scalar() return bool(row) def upgrade() -> None: conn = op.get_bind() if not _table_exists(conn, "ai_providers"): # Fresh-install path: table arrives with the ai_assistant plugin # migration, which includes these columns. return op.add_column("ai_providers", sa.Column("region", sa.String(20), nullable=False, server_default="unknown")) op.add_column("ai_providers", sa.Column("hosting_type", sa.String(30), nullable=False, server_default="cloud")) op.add_column("ai_providers", sa.Column("dpa_status", sa.String(20), nullable=False, server_default="none")) op.add_column("ai_providers", sa.Column("retention_policy", sa.Text(), nullable=False, server_default="")) op.add_column("ai_providers", sa.Column("training_on_customer_data", sa.Boolean(), nullable=False, server_default=sa.text("false"))) op.add_column("ai_providers", sa.Column("transfer_notice", sa.Text(), nullable=False, server_default="")) op.add_column("ai_providers", sa.Column("allowed_data_classes", JSONB, nullable=False, server_default=sa.text("'[]'::jsonb"))) def downgrade() -> None: conn = op.get_bind() if not _table_exists(conn, "ai_providers"): return op.drop_column("ai_providers", "allowed_data_classes") op.drop_column("ai_providers", "transfer_notice") op.drop_column("ai_providers", "training_on_customer_data") op.drop_column("ai_providers", "retention_policy") op.drop_column("ai_providers", "dpa_status") op.drop_column("ai_providers", "hosting_type") op.drop_column("ai_providers", "region")