"""presentation-chrome auto-hide (#141) — settings knobs + review table MLSettings gains presentation_auto_apply_enabled / _threshold and presentation_conflict_threshold: banner + editor-screenshot auto-hide on the sweep with a FLAT threshold (decoupled from content-head graduation), and a conflict threshold that flags an auto-hide that "also looks like content". New table presentation_review records an auto-hidden chrome image that also scored high on a content head, surfaced in the Hidden view for a keep-hidden / un-hide decision. Resolved rows are pruned by retention. Revision ID: 0082 Revises: 0081 Create Date: 2026-07-07 """ from typing import Sequence, Union import sqlalchemy as sa from alembic import op revision: str = "0082" down_revision: Union[str, None] = "0081" branch_labels: Union[str, Sequence[str], None] = None depends_on: Union[str, Sequence[str], None] = None def upgrade() -> None: op.add_column( "ml_settings", sa.Column( "presentation_auto_apply_enabled", sa.Boolean(), nullable=False, server_default=sa.text("true"), ), ) op.add_column( "ml_settings", sa.Column( "presentation_auto_apply_threshold", sa.Float(), nullable=False, server_default=sa.text("0.90"), ), ) op.add_column( "ml_settings", sa.Column( "presentation_conflict_threshold", sa.Float(), nullable=False, server_default=sa.text("0.50"), ), ) op.create_table( "presentation_review", sa.Column( "image_record_id", sa.Integer(), sa.ForeignKey("image_record.id", ondelete="CASCADE"), primary_key=True, ), sa.Column( "tag_id", sa.Integer(), sa.ForeignKey("tag.id", ondelete="CASCADE"), primary_key=True, ), sa.Column( "conflict_tag_id", sa.Integer(), sa.ForeignKey("tag.id", ondelete="SET NULL"), nullable=True, ), sa.Column("conflict_score", sa.Float(), nullable=False), sa.Column( "created_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.func.now(), ), sa.Column("resolved_at", sa.DateTime(timezone=True), nullable=True), ) # The review list queries the unresolved flags (resolved_at IS NULL). op.create_index( "ix_presentation_review_resolved_at", "presentation_review", ["resolved_at"], ) def downgrade() -> None: op.drop_index( "ix_presentation_review_resolved_at", table_name="presentation_review" ) op.drop_table("presentation_review") op.drop_column("ml_settings", "presentation_conflict_threshold") op.drop_column("ml_settings", "presentation_auto_apply_threshold") op.drop_column("ml_settings", "presentation_auto_apply_enabled")