Ship: title-based WIP auto-tagging (#1458) #222

Merged
bvandeusen merged 3 commits from dev into main 2026-07-12 19:45:03 -04:00
Owner

Ships title-based WIP auto-tagging from dev to main (task #1458). CI-green on dev head 0da0e47 (run 2175: lint/backend/frontend/integration).

What ships

When a freshly-imported post's TITLE explicitly declares work-in-progress ("WIP", "[WIP]", "W.I.P", "work in progress"), the importer auto-applies the wip system tag to its images — a deterministic, precision-first complement to the ML wip head. WIP images are excluded from Explore/training, so this honours the artist's own label at import.

  • Matcher (services/wip_title.py): token-anchored — swipe/wiped/wiping never match. source="wip_title" stamped on the tag.
  • Live hook: importer, fresh-import only (never deep-scan/supersede) — a manually-removed WIP tag is never re-applied. Gated by ImportSettings.wip_title_tagging_enabled (default on).
  • Backfill: POST /settings/wip-title/scantasks.maintenance.backfill_wip_title_tags (operator-triggered, idempotent; deliberately not a beat). Settings UI: toggle + "Scan existing posts for WIP titles" button.
  • Migration 0085 (one ImportSettings column). Tests: test_wip_title.py (matcher) + test_wip_title_tagging.py (integration).

Foundation for the follow-up system-tag behavior refactor (editor→process group, WIP provisional auto-apply): wip_title is the trusted, non-self-training label source that bootstraps the wip head.

Post-deploy

New imports tag live. To catch the existing library, press "Scan existing posts for WIP titles" once in Settings → Maintenance → Ingestion & filters.

🤖 Generated with Claude Code

Ships title-based WIP auto-tagging from `dev` to `main` (task #1458). CI-green on dev head `0da0e47` (run 2175: lint/backend/frontend/integration). ## What ships When a freshly-imported post's TITLE explicitly declares work-in-progress ("WIP", "[WIP]", "W.I.P", "work in progress"), the importer auto-applies the `wip` system tag to its images — a deterministic, precision-first complement to the ML `wip` head. WIP images are excluded from Explore/training, so this honours the artist's own label at import. - **Matcher** (`services/wip_title.py`): token-anchored — `swipe`/`wiped`/`wiping` never match. `source="wip_title"` stamped on the tag. - **Live hook**: importer, fresh-import only (never deep-scan/supersede) — a manually-removed WIP tag is never re-applied. Gated by `ImportSettings.wip_title_tagging_enabled` (default on). - **Backfill**: `POST /settings/wip-title/scan` → `tasks.maintenance.backfill_wip_title_tags` (operator-triggered, idempotent; deliberately not a beat). Settings UI: toggle + "Scan existing posts for WIP titles" button. - Migration 0085 (one ImportSettings column). Tests: `test_wip_title.py` (matcher) + `test_wip_title_tagging.py` (integration). Foundation for the follow-up system-tag behavior refactor (editor→process group, WIP provisional auto-apply): `wip_title` is the trusted, non-self-training label source that bootstraps the wip head. ## Post-deploy New imports tag live. To catch the existing library, press "Scan existing posts for WIP titles" once in Settings → Maintenance → Ingestion & filters. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
bvandeusen added 3 commits 2026-07-12 19:44:57 -04:00
feat(tagging): title-based WIP auto-tagging (#1458)
CI / lint (push) Failing after 2s
CI / frontend-build (push) Successful in 19s
CI / backend-lint-and-test (push) Successful in 34s
CI / integration (push) Failing after 3m50s
571938781a
Auto-apply the `wip` system tag to posts whose TITLE explicitly declares
work-in-progress ("WIP" / "work in progress") — a deterministic, high-precision
complement to the image-based ML `wip` head. WIP images are excluded from the
Explore/gallery browse, so honouring the artist's own label keeps unfinished
pieces out of the main browse.

- services/wip_title.py: precision-first token-anchored matcher (swipe/wiped
  never trip it) + sync apply helpers (source='wip_title', ON CONFLICT DO
  NOTHING, chunked under the psycopg param ceiling).
- importer: live hook on FRESH import only (never on deep-scan/supersede), so a
  manually-removed WIP tag is never re-applied by a routine re-scan.
- maintenance.backfill_wip_title_tags: operator-triggered back-catalogue sweep
  (coarse SQL prefilter + regex confirm, keyset-paginated). Deliberately NOT a
  beat — a periodic re-run would silently undo manual removals.
- ImportSettings.wip_title_tagging_enabled (default ON, migration 0085) gating
  the live hook; GET/PATCH + POST /settings/wip-title/scan.
- Settings UI: toggle + "Scan existing posts" button.
- Tests: pure matcher unit tests + integration (apply idempotency, backfill
  precision).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
style(importer): sort wip_title import into the local-import block
CI / lint (push) Successful in 3s
CI / integration (push) Failing after 3m49s
CI / frontend-build (push) Successful in 20s
CI / backend-lint-and-test (push) Successful in 34s
503c8854bc
Ruff I001 fixup for 5719387 — the new .wip_title import belongs after
.thumbnailer (alphabetical), not after .archive_extractor.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
fix(wip-title): count inserts via pre-SELECT, not driver rowcount
CI / lint (push) Successful in 3s
CI / frontend-build (push) Successful in 18s
CI / backend-lint-and-test (push) Successful in 29s
CI / integration (push) Successful in 3m51s
0da0e47784
apply_wip_image_tags relied on result.rowcount, but psycopg reports -1 for a
multi-row INSERT ... ON CONFLICT DO NOTHING (executemany path), so the return
count (and the backfill's reported total) was wrong. Compute the count from a
pre-SELECT of already-tagged ids within the same transaction; keep ON CONFLICT
DO NOTHING as a race-safety belt.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
bvandeusen merged commit 31d400ab0a into main 2026-07-12 19:45:03 -04:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: bvandeusen/FabledCurator#222