"""PresentationReview — an auto-hidden presentation tag that ALSO looked like real content, flagged for operator review (milestone 141). When the auto-apply sweep hides an image as chrome (banner / editor screenshot) but the image ALSO scores highly on a content head, it still hides it but records this row so the Hidden view can surface it ("⚠ also looks like ") for a keep-hidden / un-hide decision. Resolved rows are pruned by retention. """ from datetime import datetime from sqlalchemy import DateTime, Float, ForeignKey, func from sqlalchemy.orm import Mapped, mapped_column from .base import Base class PresentationReview(Base): __tablename__ = "presentation_review" image_record_id: Mapped[int] = mapped_column( ForeignKey("image_record.id", ondelete="CASCADE"), primary_key=True ) # The presentation tag that was auto-applied (banner / editor screenshot). tag_id: Mapped[int] = mapped_column( ForeignKey("tag.id", ondelete="CASCADE"), primary_key=True ) # The content tag the image ALSO scored high on — the "concerning" signal. # SET NULL (not CASCADE): losing the conflict tag shouldn't erase the flag. conflict_tag_id: Mapped[int | None] = mapped_column( ForeignKey("tag.id", ondelete="SET NULL"), nullable=True ) conflict_score: Mapped[float] = mapped_column(Float, nullable=False) created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), nullable=False, server_default=func.now() ) # Set when the operator keeps-hidden or un-hides; retention prunes resolved. resolved_at: Mapped[datetime | None] = mapped_column( DateTime(timezone=True), nullable=True )