fix(cleanup): unused-tags delete must use the same predicate as the preview #87

Merged
bvandeusen merged 2 commits from dev into main 2026-06-08 18:17:50 -04:00
Owner

Why

The unused-tags cleanup tool deleted fandom tags the preview correctly excluded — real operator data loss (2026-06-08). Root cause: the unused-tag predicate was written twice — once in the preview (find_unused_tags) and again inline in prune_unused_tags (its COUNT and DELETE). An earlier fix patched only the preview; the delete kept the narrower predicate (image_tag/series_page only, missing the fandom + series_chapter exclusions), so it removed fandoms the preview had hidden. Deleting a fandom SET-NULLs its characters' fandom_id.

What

  • Extract _unused_tag_conditions() as the single source of truth; the preview sample, the dry-run count, and the live DELETE all consume it. No second copy left to drift.
  • Add a regression test that exercises the delete path (not just the preview): asserts dry-run count == committed delete count == 1 and that a fandom referenced by a used character + a chaptered series both survive. This is the gap that let the broken delete pass green CI before.

Notes

  • The deployed instance still has the broken delete until redeployed; don't run the cleanup tool on it until then.
  • Lesson banked: preview/dry-run and the destructive apply must share one predicate, and the apply path must be tested directly.

🤖 Generated with Claude Code

## Why The unused-tags cleanup tool deleted fandom tags the preview correctly excluded — real operator data loss (2026-06-08). Root cause: the unused-tag predicate was written **twice** — once in the preview (`find_unused_tags`) and again inline in `prune_unused_tags` (its COUNT and DELETE). An earlier fix patched only the preview; the delete kept the narrower predicate (image_tag/series_page only, missing the fandom + series_chapter exclusions), so it removed fandoms the preview had hidden. Deleting a fandom SET-NULLs its characters' `fandom_id`. ## What - Extract `_unused_tag_conditions()` as the single source of truth; the preview sample, the dry-run count, **and** the live DELETE all consume it. No second copy left to drift. - Add a regression test that exercises the **delete** path (not just the preview): asserts dry-run count == committed delete count == 1 and that a fandom referenced by a used character + a chaptered series both survive. This is the gap that let the broken delete pass green CI before. ## Notes - The deployed instance still has the broken delete until redeployed; don't run the cleanup tool on it until then. - Lesson banked: preview/dry-run and the destructive apply must share one predicate, and the apply path must be tested directly. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
bvandeusen added 2 commits 2026-06-08 18:17:44 -04:00
fix(cleanup): live prune uses the same predicate as the preview (data loss)
CI / lint (push) Successful in 3s
CI / frontend-build (push) Successful in 22s
CI / backend-lint-and-test (push) Successful in 34s
CI / integration (push) Failing after 3m10s
de4ef6ae74
The fandom/chapter exclusions added in fb05c5e only touched find_unused_tags
(the preview SAMPLE). prune_unused_tags re-implemented the predicate inline for
the dry-run COUNT and the live DELETE with only the image_tag + series_page
checks — so the preview showed a safe list of names while the delete removed
every fandom (and chaptered series). Operator-flagged 2026-06-08: real data loss
— assigned fandoms deleted, their characters SET-NULLed.

Extract _unused_tag_conditions() as the single source of truth and use it for
the preview, the count, AND the delete, so they can never diverge again. Added a
prune-commit test asserting the LIVE delete spares a character's fandom and a
chaptered series.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
test(cleanup): fix prune-spares-fandom fixture — used character keeps fandom alive
CI / lint (push) Successful in 2s
CI / frontend-build (push) Successful in 22s
CI / backend-lint-and-test (push) Successful in 34s
CI / integration (push) Successful in 3m8s
df76bc0f58
The character pointing at the fandom had no image associations, so it was
itself unused and inflated the dry-run count to 2. Tag it on a real image so
it is used (the real-world shape) — the fandom survives via a live character.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
bvandeusen merged commit bb47e80b3e into main 2026-06-08 18:17:50 -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#87