"""Explicit selected-model upstream watches and deduplicated revision notices.""" import sqlalchemy as sa from alembic import op revision = "20260909_0030" down_revision = "20260909_0029" branch_labels = None depends_on = None def upgrade() -> None: op.create_table("model_update_watches", sa.Column("id", sa.Uuid(), primary_key=True), sa.Column("model_id", sa.Uuid(), sa.ForeignKey("models.id", ondelete="RESTRICT"), nullable=False), sa.Column("baseline_revision_id", sa.Uuid(), sa.ForeignKey("model_revisions.id", ondelete="RESTRICT"), nullable=False), sa.Column("baseline_commit_sha", sa.String(64), nullable=False), sa.Column("upstream_ref", sa.String(255), nullable=False), sa.Column("last_checked_at", sa.DateTime(timezone=True)), sa.Column("last_error_code", sa.String(64)), sa.Column("check_until", sa.DateTime(timezone=True)), sa.Column("check_token", sa.Uuid()), sa.UniqueConstraint("model_id", "upstream_ref", name="uq_model_watch_ref")) op.create_table("model_update_notices", sa.Column("id", sa.Uuid(), primary_key=True), sa.Column("watch_id", sa.Uuid(), sa.ForeignKey("model_update_watches.id", ondelete="RESTRICT"), nullable=False), sa.Column("model_id", sa.Uuid(), sa.ForeignKey("models.id", ondelete="RESTRICT"), nullable=False), sa.Column("baseline_commit_sha", sa.String(64), nullable=False), sa.Column("candidate_revision_id", sa.Uuid(), sa.ForeignKey("model_revisions.id", ondelete="RESTRICT"), nullable=False), sa.Column("candidate_commit_sha", sa.String(64), nullable=False), sa.Column("status", sa.String(16), nullable=False), sa.Column("discovered_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False), sa.UniqueConstraint("watch_id", "candidate_commit_sha", name="uq_model_notice_commit"), sa.CheckConstraint("status IN ('new', 'dismissed')", name="ck_model_notice_status")) if op.get_bind().dialect.name == "postgresql": op.execute("GRANT SELECT, INSERT, UPDATE ON model_update_watches, model_update_notices TO modelforge_runtime") def downgrade() -> None: if op.get_bind().scalar(sa.text("SELECT count(*) FROM model_update_watches")): raise RuntimeError("Model update history exists; restore the pre-migration backup instead.") op.drop_table("model_update_notices") op.drop_table("model_update_watches")