"""Add reliability leases, schedule deduplication, and profile context.""" from collections.abc import Sequence import sqlalchemy as sa from alembic import op revision: str = "20260804_0006" down_revision: str | Sequence[str] | None = "20260804_0005" branch_labels: str | Sequence[str] | None = None depends_on: str | Sequence[str] | None = None def upgrade() -> None: with op.batch_alter_table("projects") as batch: batch.add_column(sa.Column("custom_curation_template", sa.Text())) with op.batch_alter_table("web_sessions") as batch: batch.add_column(sa.Column("usage_profile_id", sa.String(36))) batch.create_index("ix_web_sessions_usage_profile_id", ["usage_profile_id"]) batch.create_foreign_key( "fk_web_sessions_usage_profile", "usage_profiles", ["usage_profile_id"], ["id"], ondelete="SET NULL", ) with op.batch_alter_table("curation_attempts") as batch: batch.add_column(sa.Column("attempt_key", sa.String(64))) op.execute("UPDATE curation_attempts SET attempt_key = id WHERE attempt_key IS NULL") with op.batch_alter_table("curation_attempts") as batch: batch.alter_column("attempt_key", nullable=False) batch.create_index("ix_curation_attempts_attempt_key", ["attempt_key"], unique=True) with op.batch_alter_table("git_sync_jobs") as batch: batch.add_column(sa.Column("lease_owner", sa.String(140))) batch.add_column(sa.Column("lease_expires_at", sa.DateTime(timezone=True))) batch.create_index("ix_git_sync_jobs_lease_owner", ["lease_owner"]) batch.create_index("ix_git_sync_jobs_lease_expires_at", ["lease_expires_at"]) op.create_table( "curation_schedule_triggers", sa.Column("id", sa.String(36), primary_key=True), sa.Column( "schedule_id", sa.String(36), sa.ForeignKey("curation_schedules.id", ondelete="CASCADE"), nullable=False, ), sa.Column("trigger_key", sa.String(180), nullable=False, unique=True), sa.Column("scheduled_for", sa.DateTime(timezone=True), nullable=False), sa.Column("job_ids_json", sa.Text(), nullable=False, server_default="[]"), sa.Column("status", sa.String(32), nullable=False, server_default="created"), sa.Column("created_at", sa.DateTime(timezone=True), nullable=False), ) op.create_index( "ix_curation_schedule_triggers_schedule_id", "curation_schedule_triggers", ["schedule_id"], ) op.create_index( "ix_curation_schedule_triggers_trigger_key", "curation_schedule_triggers", ["trigger_key"], unique=True, ) op.create_index( "ix_curation_schedule_triggers_scheduled_for", "curation_schedule_triggers", ["scheduled_for"], ) op.create_index( "ix_curation_schedule_triggers_status", "curation_schedule_triggers", ["status"], ) def downgrade() -> None: op.drop_table("curation_schedule_triggers") with op.batch_alter_table("git_sync_jobs") as batch: batch.drop_index("ix_git_sync_jobs_lease_expires_at") batch.drop_index("ix_git_sync_jobs_lease_owner") batch.drop_column("lease_expires_at") batch.drop_column("lease_owner") with op.batch_alter_table("curation_attempts") as batch: batch.drop_index("ix_curation_attempts_attempt_key") batch.drop_column("attempt_key") with op.batch_alter_table("web_sessions") as batch: batch.drop_constraint("fk_web_sessions_usage_profile", type_="foreignkey") batch.drop_index("ix_web_sessions_usage_profile_id") batch.drop_column("usage_profile_id") with op.batch_alter_table("projects") as batch: batch.drop_column("custom_curation_template")