feat(heads): surface system-tag suggestions at a flat 0.65 confidence floor
System tags (wip/banner/editor) already get heads (kind=general) and aren't filtered from suggestions, but they surfaced only at each head's precision-tuned suggest_threshold — high enough to hide the borderline/false-positive guesses the operator wants to SEE and REJECT (hard-negative mining: 'negatively reinforce what isn't a system tag'). score_image now uses a flat _SYSTEM_TAG_SUGGEST_FLOOR (0.65, operator-set) for system-tag heads instead of their auto threshold; content-tag heads keep their own, and the typed-dropdown threshold_override still overrides everything. _current_heads carries Tag.is_system into the head meta to drive it. 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:
@@ -111,6 +111,49 @@ async def test_threshold_override_surfaces_below_cut(db):
|
||||
assert any(s.canonical_tag_id == tag.id for s in flooded.by_category["general"])
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_system_tag_surfaces_at_flat_floor_despite_high_threshold(db):
|
||||
# A system tag's head uses the flat _SYSTEM_TAG_SUGGEST_FLOOR (0.65), not its
|
||||
# precision-tuned suggest_threshold — so a matching image (~0.73) surfaces it
|
||||
# for rejection even though its 0.9 auto threshold would hide it.
|
||||
from backend.app.services.ml.heads import _SYSTEM_TAG_SUGGEST_FLOOR
|
||||
assert _SYSTEM_TAG_SUGGEST_FLOOR == 0.65
|
||||
tag = await TagService(db).find_or_create("wip sketchy", TagKind.general)
|
||||
tag.is_system = True
|
||||
img = await _img(db, "1" * 64, _emb(0)) # matches head → ~0.73
|
||||
await _head(db, tag.id, slot=0, suggest_threshold=0.9)
|
||||
await db.commit()
|
||||
sl = await SuggestionService(db).for_image(img.id)
|
||||
assert any(
|
||||
s.canonical_tag_id == tag.id for s in sl.by_category.get("general", [])
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_system_tag_below_floor_stays_hidden(db):
|
||||
# Below the 0.65 floor (~0.5 on an orthogonal image) the system tag is not
|
||||
# surfaced — the floor still gates, it isn't "always show".
|
||||
tag = await TagService(db).find_or_create("wip faint", TagKind.general)
|
||||
tag.is_system = True
|
||||
img = await _img(db, "2" * 64, _emb(1)) # orthogonal → 0.5
|
||||
await _head(db, tag.id, slot=0, suggest_threshold=0.9)
|
||||
await db.commit()
|
||||
sl = await SuggestionService(db).for_image(img.id)
|
||||
assert not sl.by_category.get("general")
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_content_tag_ignores_system_floor(db):
|
||||
# A NON-system head with the same high threshold does NOT get the floor: the
|
||||
# ~0.73 match stays hidden below its 0.9 auto threshold (floor is system-only).
|
||||
tag = await TagService(db).find_or_create("glasses hi", TagKind.general)
|
||||
img = await _img(db, "3" * 64, _emb(0)) # matches head → ~0.73
|
||||
await _head(db, tag.id, slot=0, suggest_threshold=0.9)
|
||||
await db.commit()
|
||||
sl = await SuggestionService(db).for_image(img.id)
|
||||
assert not sl.by_category.get("general")
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_concept_region_surfaces_via_max_over_bag(db):
|
||||
# Max-over-bag: the whole-image vector is orthogonal to the head (scores the
|
||||
|
||||
Reference in New Issue
Block a user