feat(ml): stricter auto-apply defaults to cut misfires (milestone 139)
head_auto_apply_precision 0.97→0.98, head_auto_apply_min_positives 30→50, ccip_auto_apply_threshold 0.92→0.95 (operator-asked). Model defaults change for fresh installs; migration 0081 bumps the existing singleton row IFF still at the old default (won't clobber a deliberate operator change). ml_admin bounds already permit these. Fixed a stale comment in the auto-apply test. 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:
@@ -0,0 +1,50 @@
|
||||
"""stricter auto-apply defaults (milestone 139) — cut graduate/auto-apply misfires
|
||||
|
||||
head_auto_apply_precision 0.97→0.98, head_auto_apply_min_positives 30→50,
|
||||
ccip_auto_apply_threshold 0.92→0.95 (operator-asked 2026-07-06). The model
|
||||
defaults change for fresh installs; here we bump the existing singleton row IFF
|
||||
it is still at the previous default, so a deliberate operator change is NOT
|
||||
clobbered.
|
||||
|
||||
Revision ID: 0081
|
||||
Revises: 0080
|
||||
Create Date: 2026-07-06
|
||||
"""
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
|
||||
revision: str = "0081"
|
||||
down_revision: Union[str, None] = "0080"
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
op.execute(
|
||||
"UPDATE ml_settings SET head_auto_apply_precision = 0.98 "
|
||||
"WHERE head_auto_apply_precision = 0.97"
|
||||
)
|
||||
op.execute(
|
||||
"UPDATE ml_settings SET head_auto_apply_min_positives = 50 "
|
||||
"WHERE head_auto_apply_min_positives = 30"
|
||||
)
|
||||
op.execute(
|
||||
"UPDATE ml_settings SET ccip_auto_apply_threshold = 0.95 "
|
||||
"WHERE ccip_auto_apply_threshold = 0.92"
|
||||
)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.execute(
|
||||
"UPDATE ml_settings SET head_auto_apply_precision = 0.97 "
|
||||
"WHERE head_auto_apply_precision = 0.98"
|
||||
)
|
||||
op.execute(
|
||||
"UPDATE ml_settings SET head_auto_apply_min_positives = 30 "
|
||||
"WHERE head_auto_apply_min_positives = 50"
|
||||
)
|
||||
op.execute(
|
||||
"UPDATE ml_settings SET ccip_auto_apply_threshold = 0.92 "
|
||||
"WHERE ccip_auto_apply_threshold = 0.95"
|
||||
)
|
||||
@@ -51,7 +51,10 @@ class MLSettings(Base):
|
||||
Integer, nullable=False, default=8
|
||||
)
|
||||
head_auto_apply_precision: Mapped[float] = mapped_column(
|
||||
Float, nullable=False, default=0.97
|
||||
# Stricter graduation bar (was 0.97) to cut auto-apply misfires
|
||||
# (operator-asked 2026-07-06): a higher precision target → fewer heads
|
||||
# graduate and those that do get a higher per-head auto_apply_threshold.
|
||||
Float, nullable=False, default=0.98
|
||||
)
|
||||
# Earned auto-apply (#114). A graduated head fires (tags images without a
|
||||
# human) when this master switch is on AND the head has at least
|
||||
@@ -63,7 +66,9 @@ class MLSettings(Base):
|
||||
Boolean, nullable=False, default=True
|
||||
)
|
||||
head_auto_apply_min_positives: Mapped[int] = mapped_column(
|
||||
Integer, nullable=False, default=30
|
||||
# Support floor raised 30→50 (operator-asked 2026-07-06): a head needs
|
||||
# more human labels before it may fire without a human.
|
||||
Integer, nullable=False, default=50
|
||||
)
|
||||
# CCIP character-match cosine cut (#114). 0.85 default — the v1 flat 0.75
|
||||
# over-fired (high-reference characters matched a scatter of images); 0.85
|
||||
@@ -78,7 +83,9 @@ class MLSettings(Base):
|
||||
Boolean, nullable=False, default=True
|
||||
)
|
||||
ccip_auto_apply_threshold: Mapped[float] = mapped_column(
|
||||
Float, nullable=False, default=0.92
|
||||
# Raised 0.92→0.95 (operator-asked 2026-07-06) so only very confident
|
||||
# character matches auto-tag.
|
||||
Float, nullable=False, default=0.95
|
||||
)
|
||||
# Default = SigLIP 2 (so400m, 512px) for new installs (migration 0069);
|
||||
# existing libraries keep their stored value until the operator re-embeds.
|
||||
|
||||
@@ -88,7 +88,7 @@ def test_sweep_dry_run_counts_but_writes_nothing(db_sync):
|
||||
|
||||
|
||||
def test_sweep_skips_under_supported_head(db_sync):
|
||||
# n_pos below head_auto_apply_min_positives (default 30) → a precise-looking
|
||||
# n_pos below head_auto_apply_min_positives (default 50) → a precise-looking
|
||||
# but under-supported head never fires.
|
||||
img = _img(db_sync, "c" * 64, _emb(0))
|
||||
tag = Tag(name="weaktag", kind=TagKind.general)
|
||||
|
||||
Reference in New Issue
Block a user