feat(wip): soft title tier — sketch/doodle vocab + ring-loud audit (#1474)
Extends WIP title-tagging to lower-precision cues (sketch/doodle/scribble) safely. - wip_title.py: soft matcher (word-anchored; sketchbook/kadoodle don't trip it); WIP_TITLE_SOFT_SOURCE + soft SQL prefilter; apply_wip_image_tags takes a source arg. - training_data._AUTO_SOURCES += 'wip_title_soft' → the soft tier is PROVISIONAL and never trains the wip head (a finished "sketch" can't pollute it). Only the hard tier (wip_title) + manual train. - ImportSettings.wip_soft_title_tagging_enabled (OFF by default, opt-in). Migration 0087. - importer: hard tier wins, soft is the fallback (source wip_title_soft). - backfill: refactored into a shared _backfill_wip_tier; hard always, soft when enabled. - heads.soft_wip_conflict_audit + daily beat: score soft-tagged images against content heads, flag ring-loud ones (PresentationReview mode=process) for the review strip — the operator's "measure if they got falsely tagged" safety. - api settings toggle; ImportFiltersForm soft toggle. - tests: soft matcher pos/neg; soft source not a training positive; audit flags ring-loud + spares quiet. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+28
-1
@@ -8,7 +8,7 @@ negative cases (substrings like ``swipe`` / ``wiped``) are the load-bearing ones
|
||||
"""
|
||||
import pytest
|
||||
|
||||
from backend.app.services.wip_title import matches_wip_title
|
||||
from backend.app.services.wip_title import matches_soft_wip_title, matches_wip_title
|
||||
|
||||
|
||||
@pytest.mark.parametrize("title", [
|
||||
@@ -44,6 +44,33 @@ def test_matches_positive(title):
|
||||
"finished at last",
|
||||
"Kawips diner", # 'wip' mid-word
|
||||
"swipright",
|
||||
"quick sketch of Nami", # soft cue — NOT a HARD WIP match
|
||||
])
|
||||
def test_matches_negative(title):
|
||||
assert matches_wip_title(title) is False
|
||||
|
||||
|
||||
@pytest.mark.parametrize("title", [
|
||||
"quick sketch",
|
||||
"Nami sketch",
|
||||
"morning doodle",
|
||||
"some doodles",
|
||||
"sketches from today",
|
||||
"a little scribble",
|
||||
"SKETCH",
|
||||
])
|
||||
def test_soft_matches_positive(title):
|
||||
assert matches_soft_wip_title(title) is True
|
||||
|
||||
|
||||
@pytest.mark.parametrize("title", [
|
||||
None,
|
||||
"",
|
||||
"sketchbook tour", # 'sketch' inside sketchbook — must NOT match
|
||||
"kadoodle mascot", # 'doodle' mid-word
|
||||
"the final piece",
|
||||
"WIP", # a HARD cue is not a SOFT cue
|
||||
"prescribed colours", # 'scrib' inside prescribed — must NOT match
|
||||
])
|
||||
def test_soft_matches_negative(title):
|
||||
assert matches_soft_wip_title(title) is False
|
||||
|
||||
Reference in New Issue
Block a user