feat: retire the sketch/doodle WIP title tier, and the review strip asks "Is this a WIP?" (milestone 430)
CI and images / lint (push) Successful in 2s
CI and images / extension-version (push) Successful in 3s
CI and images / extension-test (push) Successful in 20s
CI and images / frontend-build (push) Successful in 23s
CI and images / backend-lint-and-test (push) Successful in 32s
CI and images / integration (push) Successful in 2m24s
CI and images / sign-extension (push) Successful in 3s
CI and images / build-agent (push) Successful in 5s
CI and images / build-web (push) Successful in 1m35s
CI and images / smoke-web (push) Successful in 56s
CI and images / promote (push) Successful in 1s
CI and images / lint (push) Successful in 2s
CI and images / extension-version (push) Successful in 3s
CI and images / extension-test (push) Successful in 20s
CI and images / frontend-build (push) Successful in 23s
CI and images / backend-lint-and-test (push) Successful in 32s
CI and images / integration (push) Successful in 2m24s
CI and images / sign-extension (push) Successful in 3s
CI and images / build-agent (push) Successful in 5s
CI and images / build-web (push) Successful in 1m35s
CI and images / smoke-web (push) Successful in 56s
CI and images / promote (push) Successful in 1s
The soft tier (#1474) tagged `wip` on any post titled sketch, doodle or scribble: 6,096 of the library's 8,876 wip tags. Its conflict audit flagged most of them, because finished art scores >= 0.5 on some content head, which filled the Gallery strip with 2,086 cards. A "sketch" is usually finished work, so the operator retired the tier. The artist's own "WIP" / "work in progress" title rule and human wip tags stay. - Removed: the soft matcher, source and prefilter; the importer and backfill soft branches; soft_wip_conflict_audit with its task and beat; the wip_soft_title_tagging_enabled setting, API field and toggle; and wip_title_soft from _AUTO_SOURCES. - Migration 0112: a soft tag the operator confirmed, or kept from the strip, becomes `manual`. Every other soft tag is deleted, along with the open review cards whose tag is gone. The column is dropped. - Review strip (#4424): each card asks "Is this a WIP?" (or banner, and so on), and the buttons read "Is a WIP" / "Is not a WIP". The content tag it also scored on is shown as the reason it was flagged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LVjrnpQjRgHdvq95rASoiR
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
"""Migration 0112 (milestone 430, #4428): retiring the sketch/doodle WIP title tier.
|
||||
|
||||
Runs the migration's data step against real rows. The soft tags the operator stood
|
||||
behind (confirmed, or kept through the review strip) survive as `manual`; the rest go,
|
||||
and so do the unresolved review cards whose tag went with them. Hard title tags and
|
||||
their flags are untouched.
|
||||
"""
|
||||
import importlib.util
|
||||
from datetime import UTC, datetime
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
from sqlalchemy import select
|
||||
|
||||
from backend.app.models import PresentationReview, TagPositiveConfirmation
|
||||
from backend.app.models.tag import image_tag
|
||||
from backend.app.services.wip_title import resolve_wip_tag_id
|
||||
from tests.factories import make_image as _img
|
||||
|
||||
pytestmark = pytest.mark.integration
|
||||
|
||||
_MIGRATION = (
|
||||
Path(__file__).resolve().parents[1]
|
||||
/ "alembic" / "versions" / "0112_retire_soft_wip_title.py"
|
||||
)
|
||||
|
||||
|
||||
def _retire():
|
||||
spec = importlib.util.spec_from_file_location("m0112", _MIGRATION)
|
||||
mod = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(mod)
|
||||
return mod.retire_soft_wip_tags
|
||||
|
||||
|
||||
def _source(db, image_id, tag_id):
|
||||
return db.execute(
|
||||
select(image_tag.c.source)
|
||||
.where(image_tag.c.image_record_id == image_id)
|
||||
.where(image_tag.c.tag_id == tag_id)
|
||||
).scalar_one_or_none()
|
||||
|
||||
|
||||
def _review(db, image_id, tag_id):
|
||||
return db.execute(
|
||||
select(PresentationReview)
|
||||
.where(PresentationReview.image_record_id == image_id)
|
||||
.where(PresentationReview.tag_id == tag_id)
|
||||
).scalar_one_or_none()
|
||||
|
||||
|
||||
def _flag(db, image_id, tag_id, *, resolved):
|
||||
db.add(PresentationReview(
|
||||
image_record_id=image_id, tag_id=tag_id, conflict_score=0.8, mode="process",
|
||||
resolved_at=datetime.now(UTC) if resolved else None,
|
||||
))
|
||||
|
||||
|
||||
def test_retire_soft_wip_keeps_human_judged_and_clears_the_rest(db_sync):
|
||||
wip = resolve_wip_tag_id(db_sync)
|
||||
plain = _img(db_sync, "a" * 64) # soft, never looked at → removed
|
||||
confirmed = _img(db_sync, "b" * 64) # soft + confirmed → kept as manual
|
||||
kept = _img(db_sync, "c" * 64) # soft + "Keep tag" in the strip → manual
|
||||
pending = _img(db_sync, "d" * 64) # soft + open card → tag and card removed
|
||||
hard = _img(db_sync, "e" * 64) # hard title tag + open card → untouched
|
||||
for img in (plain, confirmed, kept, pending):
|
||||
db_sync.execute(image_tag.insert().values(
|
||||
image_record_id=img.id, tag_id=wip, source="wip_title_soft"))
|
||||
db_sync.execute(image_tag.insert().values(
|
||||
image_record_id=hard.id, tag_id=wip, source="wip_title"))
|
||||
db_sync.add(TagPositiveConfirmation(image_record_id=confirmed.id, tag_id=wip))
|
||||
_flag(db_sync, kept.id, wip, resolved=True)
|
||||
_flag(db_sync, pending.id, wip, resolved=False)
|
||||
_flag(db_sync, hard.id, wip, resolved=False)
|
||||
db_sync.flush()
|
||||
|
||||
_retire()(db_sync.connection())
|
||||
db_sync.expire_all()
|
||||
|
||||
assert _source(db_sync, plain.id, wip) is None
|
||||
assert _source(db_sync, confirmed.id, wip) == "manual"
|
||||
assert _source(db_sync, kept.id, wip) == "manual"
|
||||
assert _source(db_sync, pending.id, wip) is None
|
||||
assert _source(db_sync, hard.id, wip) == "wip_title"
|
||||
|
||||
assert _review(db_sync, pending.id, wip) is None
|
||||
assert _review(db_sync, kept.id, wip) is not None # resolved history stays
|
||||
assert _review(db_sync, hard.id, wip) is not None # its tag is still on
|
||||
assert db_sync.execute(
|
||||
select(image_tag.c.image_record_id).where(image_tag.c.source == "wip_title_soft")
|
||||
).first() is None
|
||||
Reference in New Issue
Block a user