feat(ml): auto-applied tags don't train a head unless confirmed (milestone 139)
Makes auto-apply truly "soft" for heads: _ids_with_tag (head positives) and _eligible_tag_ids (graduation count) now count human-applied + operator-confirmed tags only, via a shared _AUTO_SOURCES (head_auto/ccip_auto/ml_auto) exclusion. Unconfirmed auto-applied tags no longer train the head that judges them, so a misfire can't reinforce itself and the retraction sweep can actually drop it. Confirming a tag (TagPositiveConfirmation) promotes it to a positive AND protects it from retraction. sklearn-free tests. CCIP reference exclusion is the companion piece, next. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CDgx8bQS5YrGRK76v8HUnM
This commit is contained in:
@@ -17,9 +17,20 @@ from typing import Any
|
||||
from sqlalchemy import func, select
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from ...models import ImageRecord, Tag, TagSuggestionRejection
|
||||
from ...models import (
|
||||
ImageRecord,
|
||||
Tag,
|
||||
TagPositiveConfirmation,
|
||||
TagSuggestionRejection,
|
||||
)
|
||||
from ...models.tag import image_tag
|
||||
|
||||
# Auto-apply sources whose tags are PROVISIONAL: they never train a head (or seed
|
||||
# a CCIP reference) unless the operator confirms them (milestone 139). Keeping
|
||||
# auto-applied predictions out of training is what makes them "soft" — a misfire
|
||||
# can't reinforce itself, so the retraction sweep can actually drop it.
|
||||
_AUTO_SOURCES = ("head_auto", "ccip_auto", "ml_auto")
|
||||
|
||||
|
||||
def _hygiene_excluded_ids(session: Session) -> set[int]:
|
||||
"""Ids of images carrying ANY system tag (wip / banner / editor
|
||||
@@ -45,9 +56,23 @@ def _hygiene_excluded_ids(session: Session) -> set[int]:
|
||||
|
||||
|
||||
def _ids_with_tag(session: Session, tag_id: int) -> list[int]:
|
||||
"""Image ids that count as POSITIVES for this tag's head: human-applied
|
||||
(manual / accepted) tags PLUS any auto-applied tag the operator explicitly
|
||||
confirmed (TagPositiveConfirmation). Unconfirmed auto-applied tags are
|
||||
EXCLUDED — they are provisional and must not train the head that judges
|
||||
them (milestone 139)."""
|
||||
confirmed = (
|
||||
select(TagPositiveConfirmation.image_record_id)
|
||||
.where(TagPositiveConfirmation.tag_id == tag_id)
|
||||
)
|
||||
return [
|
||||
r[0] for r in session.execute(
|
||||
select(image_tag.c.image_record_id).where(image_tag.c.tag_id == tag_id)
|
||||
select(image_tag.c.image_record_id)
|
||||
.where(image_tag.c.tag_id == tag_id)
|
||||
.where(
|
||||
image_tag.c.source.not_in(_AUTO_SOURCES)
|
||||
| image_tag.c.image_record_id.in_(confirmed)
|
||||
)
|
||||
).all()
|
||||
]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user