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
|
Integer, nullable=False, default=8
|
||||||
)
|
)
|
||||||
head_auto_apply_precision: Mapped[float] = mapped_column(
|
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
|
# 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
|
# 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
|
Boolean, nullable=False, default=True
|
||||||
)
|
)
|
||||||
head_auto_apply_min_positives: Mapped[int] = mapped_column(
|
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
|
# 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
|
# over-fired (high-reference characters matched a scatter of images); 0.85
|
||||||
@@ -78,7 +83,9 @@ class MLSettings(Base):
|
|||||||
Boolean, nullable=False, default=True
|
Boolean, nullable=False, default=True
|
||||||
)
|
)
|
||||||
ccip_auto_apply_threshold: Mapped[float] = mapped_column(
|
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);
|
# Default = SigLIP 2 (so400m, 512px) for new installs (migration 0069);
|
||||||
# existing libraries keep their stored value until the operator re-embeds.
|
# 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):
|
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.
|
# but under-supported head never fires.
|
||||||
img = _img(db_sync, "c" * 64, _emb(0))
|
img = _img(db_sync, "c" * 64, _emb(0))
|
||||||
tag = Tag(name="weaktag", kind=TagKind.general)
|
tag = Tag(name="weaktag", kind=TagKind.general)
|
||||||
|
|||||||
Reference in New Issue
Block a user