Unused-tag fandom fix + ML-worker logging/tuning + unified dropdown Enter #86

Merged
bvandeusen merged 5 commits from dev into main 2026-06-08 17:27:56 -04:00
Owner

Operator-flagged fixes and a DRY refactor. CI green (run #750, 408fcd4). No schema change (alembic head stays 0042).

Fixes

  • fix(cleanup) — fandoms no longer flagged "unused" (fb05c5e). find_unused_tags only checked image_tag + series_page references, so every fandom (never applied to an image — a character carries it via fandom_id) looked unused, and the FK is ondelete=SET NULL, so deleting one would strip the fandom off all its characters. Now excludes tags referenced as a character's fandom_id and tags referenced by a series_chapter (all-placeholder series). Genuinely orphaned fandoms still sweep.

Observability + tuning (video ML)

  • obs(ml)tag_and_embed logging (b1778ca). The task logged nothing and SoftTimeLimitExceeded stringifies to empty, so a timeout gave zero clue which file or why. Now logs start (id/path/mime/bytes/video?), per-phase timing, and re-raises a timeout WITH context so the activity names the file + phase. Other errors are logged then re-raised unchanged (preserves autoretry).
  • tweak(ml) — video frame samples 10→6 (f2fbe2a). Fewer frames into the max-pool = less noisy video tags + smaller sampling budget. Deeper quality/perf review tracked in Scribe #747.

DRY

  • refactor(ui) — unified confirm-dropdown Enter (408fcd4). New useAcceptOnEnter composable: Enter on an open menu picks; Enter on a closed menu triggers the modal's primary action instead of re-opening the dropdown. Applied to the tag-merge picker (the reported one), alias picker, post→add-to-series, and the two fandom dialogs (refactored off their copy-pasted handlers). One behavior, one place.

🤖 Generated with Claude Code

Operator-flagged fixes and a DRY refactor. CI green (run #750, `408fcd4`). No schema change (alembic head stays 0042). ## Fixes - **`fix(cleanup)` — fandoms no longer flagged "unused" (`fb05c5e`).** `find_unused_tags` only checked image_tag + series_page references, so every fandom (never applied to an image — a character carries it via `fandom_id`) looked unused, and the FK is `ondelete=SET NULL`, so deleting one would strip the fandom off all its characters. Now excludes tags referenced as a character's `fandom_id` and tags referenced by a `series_chapter` (all-placeholder series). Genuinely orphaned fandoms still sweep. ## Observability + tuning (video ML) - **`obs(ml)` — `tag_and_embed` logging (`b1778ca`).** The task logged nothing and `SoftTimeLimitExceeded` stringifies to empty, so a timeout gave zero clue which file or why. Now logs start (id/path/mime/bytes/video?), per-phase timing, and re-raises a timeout WITH context so the activity names the file + phase. Other errors are logged then re-raised unchanged (preserves autoretry). - **`tweak(ml)` — video frame samples 10→6 (`f2fbe2a`).** Fewer frames into the max-pool = less noisy video tags + smaller sampling budget. Deeper quality/perf review tracked in Scribe #747. ## DRY - **`refactor(ui)` — unified confirm-dropdown Enter (`408fcd4`).** New `useAcceptOnEnter` composable: Enter on an open menu picks; Enter on a closed menu triggers the modal's primary action instead of re-opening the dropdown. Applied to the tag-merge picker (the reported one), alias picker, post→add-to-series, and the two fandom dialogs (refactored off their copy-pasted handlers). One behavior, one place. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
bvandeusen added 5 commits 2026-06-08 17:27:50 -04:00
fix(cleanup): don't flag a character's fandom (or a chaptered series) as unused
CI / lint (push) Failing after 3s
CI / frontend-build (push) Successful in 23s
CI / backend-lint-and-test (push) Successful in 26s
CI / integration (push) Successful in 3m7s
fb05c5eef7
find_unused_tags only excluded tags with image_tag or series_page references, so
it flagged every fandom as 'unused' — fandoms are NEVER applied to images (a
character carries its fandom via tag.fandom_id), and the FK is ondelete=SET NULL,
so deleting one silently strips the fandom off all its characters
(operator-flagged 2026-06-08: artist-OC fandoms showing as unused).

Exclude tags referenced as a character's fandom_id, and (same class of gap) tags
referenced by a series_chapter (an all-placeholder series has chapters but no
pages yet). A genuinely orphaned fandom with no characters is still swept.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
test: drop unused binding in find_unused_tags test (ruff F841)
CI / lint (push) Successful in 3s
CI / frontend-build (push) Successful in 17s
CI / backend-lint-and-test (push) Successful in 26s
CI / integration (push) Successful in 3m6s
fe0ed52595
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
obs(ml): tag_and_embed logs file + phase + timing; failures name them
CI / lint (push) Successful in 2s
CI / frontend-build (push) Successful in 18s
CI / backend-lint-and-test (push) Successful in 25s
CI / integration (push) Successful in 3m6s
b1778ca9f2
The task logged nothing and SoftTimeLimitExceeded stringifies to empty, so a
timeout surfaced as a bare 'SoftTimeLimitExceeded()' with no clue which file or
why (operator-flagged 2026-06-08).

- Log start (id/path/mime/bytes/video?), per-phase timing (load_models, video
  probe/sample/infer, tag, embed, persist), and a success summary.
- Track a  + file ; on SoftTimeLimitExceeded log it and re-raise
  SoftTimeLimitExceeded WITH that context (keeps the 'timeout' task_run status
  but gives the activity a real error_message: which file, which phase, elapsed).
- On other exceptions, log context then re-raise the ORIGINAL (preserves
  autoretry for OSError/DBAPIError/OperationalError).

Now a stuck run names the culprit — most likely a slow video (frame sampling is
up to 10x60s ffmpeg) or a huge image; the phase log will say which.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
tweak(ml): default video frame samples 10 to 6
CI / backend-lint-and-test (push) Failing after 3s
CI / lint (push) Successful in 4s
CI / frontend-build (push) Successful in 23s
CI / integration (push) Successful in 3m6s
f2fbe2ae6e
Operator: 10-frame max-pooled tagging on video produces a lot of noisy tags, and
the sampling burns time/GPU. Drop the VIDEO_ML_FRAMES default to 6 (still env-
overridable). Fewer frames = less per-frame noise into the max-pool and a smaller
frame-sampling budget. Quality/perf of the whole video path is being reviewed
separately.
refactor(ui): unify confirm-dropdown Enter behavior via useAcceptOnEnter
CI / lint (push) Successful in 2s
CI / backend-lint-and-test (push) Successful in 27s
CI / frontend-build (push) Successful in 1m44s
CI / integration (push) Successful in 3m8s
408fcd488a
Operator-flagged (again) on the tag-merge picker: Enter on the dropdown re-opens
it instead of accepting the selection. I'd already patched this twice (fandom
picker + fandom set dialog) with copy-pasted capture-phase handlers, so DRY it.

New composable useAcceptOnEnter(accept): tracks the menu state and, on a
capture-phase Enter, lets Vuetify pick when the menu is open but calls accept()
(and blocks the re-open) when it's closed. Applied to every confirm-style picker:
- TagsView merge-into picker (the reported one)
- AliasPickerDialog
- PostSeriesMenu add-to-existing
- FandomPicker + FandomSetDialog (refactored off their bespoke handlers)

One behavior, one place to change it.
bvandeusen merged commit dc1083b5e0 into main 2026-06-08 17:27:56 -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#86