"""finance_finding_acks — triage state for cost-governance findings. Revision ID: 305 Revises: 304 Create Date: 2026-06-18 PR3 of the finance closed-loop theme: governance findings (wasted/idle seats, contract renewals, movers, orphan cost centres, expense-hygiene) are recomputed every read, so a decision has nowhere to live and they re-nag forever. This table records one triage row per (kind, ref) — acknowledged / snoozed / resolved — so the findings wall becomes a managed work queue. Standalone, no FK. Idempotent / re-runnable. """ from __future__ import annotations import sqlalchemy as sa from alembic import op revision = "305" down_revision = "304" branch_labels = None depends_on = None TABLE = "finance_finding_acks" def _table_exists(bind, name: str) -> bool: return bind.execute( sa.text( "SELECT 1 FROM information_schema.TABLES " "WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = :n" ), {"n": name}, ).scalar() is not None def upgrade() -> None: bind = op.get_bind() if _table_exists(bind, TABLE): return op.create_table( TABLE, sa.Column("id", sa.BigInteger(), autoincrement=True, nullable=False), sa.Column("kind", sa.String(length=32), nullable=False), sa.Column("ref", sa.String(length=255), nullable=False), sa.Column("status", sa.String(length=16), nullable=False), sa.Column("snooze_until", sa.DateTime(timezone=True), nullable=True), sa.Column("note", sa.Text(), nullable=True), sa.Column("actor_person_id", sa.String(length=36), nullable=True), sa.Column( "created_at", sa.DateTime(timezone=True), server_default=sa.text("CURRENT_TIMESTAMP"), nullable=False, ), sa.Column( "updated_at", sa.DateTime(timezone=True), server_default=sa.text("CURRENT_TIMESTAMP"), nullable=False, ), sa.PrimaryKeyConstraint("id"), sa.UniqueConstraint("kind", "ref", name="uq_finance_finding_ack_kind_ref"), mysql_engine="InnoDB", mysql_charset="utf8mb4", mysql_collate="utf8mb4_unicode_ci", ) def downgrade() -> None: bind = op.get_bind() if _table_exists(bind, TABLE): op.drop_table(TABLE)