ab63d94249
MLSettings gains presentation_auto_apply_enabled / _threshold (default 0.90) + presentation_conflict_threshold (default 0.50): banner/editor auto-hide with a FLAT threshold (decoupled from content-head graduation), plus the "also looks like content" conflict cut. New presentation_review table (image, presentation tag, conflict tag + score, created/resolved_at) records auto-hides flagged for review. Migration 0082 (columns + table), ml_admin API (editable + get_settings + _validate bounds), settings roundtrip/bounds test. The sweep that reads these knobs + the Settings UI land in step 4. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CDgx8bQS5YrGRK76v8HUnM
41 lines
1.7 KiB
Python
41 lines
1.7 KiB
Python
"""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 <conflict tag>")
|
|
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
|
|
)
|