PR #20's merge_when_checks_succeed: true fired at the original PR HEAD (06a2f60), NOT at dev's current head. The 8 dev commits that landed AFTER PR #20's queue but BEFORE auto-merge fired never made it into main. v26.05.25.6's release notes claimed they did — they didn't. This PR fixes that.
What's actually in this PR (and therefore v26.05.25.7)
Worker no longer hangs on animated WebPs (c0c9e56)
_transparency_pct and compute_phash short-circuit is_animated. Was triggering 5+ min PIL multi-frame decode → Celery 300s soft / 360s hard timeout → SIGKILL.
FC-Cleanup backend (Tasks 1-6 of 17)
Migration 0020_library_audit_run — new table for async transparency/single_color audit lifecycle
LibraryAuditRun SQLAlchemy model
backend/app/services/audits/transparency.py — evaluate(pil_image, *, threshold) -> bool with is_animated short-circuit
## Context — fixing v26.05.25.6's mislabeled release notes
PR #20's `merge_when_checks_succeed: true` fired at the original PR HEAD (`06a2f60`), NOT at dev's current head. The 8 dev commits that landed AFTER PR #20's queue but BEFORE auto-merge fired never made it into main. v26.05.25.6's release notes claimed they did — they didn't. This PR fixes that.
## What's actually in this PR (and therefore v26.05.25.7)
### Worker no longer hangs on animated WebPs (`c0c9e56`)
- `_transparency_pct` and `compute_phash` short-circuit `is_animated`. Was triggering 5+ min PIL multi-frame decode → Celery 300s soft / 360s hard timeout → SIGKILL.
### FC-Cleanup backend (Tasks 1-6 of 17)
- Migration `0020_library_audit_run` — new table for async transparency/single_color audit lifecycle
- `LibraryAuditRun` SQLAlchemy model
- `backend/app/services/audits/transparency.py` — `evaluate(pil_image, *, threshold) -> bool` with `is_animated` short-circuit
- `backend/app/services/audits/single_color.py` — downsample + dominant-color tolerance algorithm
- `cleanup_service.py` extensions:
- `project_min_dimension_violations` (synchronous SQL preview)
- `delete_min_dimension_violations` (synchronous SQL delete routed through FC-3k's `delete_images`)
- `start_audit_run` (creates LibraryAuditRun, dispatches Celery task, concurrent-runs guard)
- `apply_audit_run` (Tier-C typed-token confirm, routes through `delete_images`)
- `cancel_audit_run` (flips status, scan task checks between batches)
- Exception classes: `AuditAlreadyRunning`, `AuditNotReady`, `ConfirmTokenMismatch`
- `backend/app/tasks/library_audit.py::scan_library_for_rule` — keyset-paginated PIL inspection task on `maintenance` queue, soft_time_limit=7200, time_limit=7500, 50k matched-IDs cap, cancellation check between batches
- celery_app.py registration + maintenance-queue routing
### Test fixes (`2d4bfa4`)
- sha256 fixtures use `ljust(64, ...)[:64]` so they stay within `image_record.sha256` varchar(64)
- Registration import in test_tasks_library_audit.py moved to the first-party group, isort-sorted
## Dead-code status
The Cleanup backend has no API or UI surface yet (Tasks 7-16 ship in v26.05.25.8). From a user perspective, this release is purely:
- Animated-WebP worker stability fix
- New empty `library_audit_run` table on disk
- New Celery task that nothing calls
Safe to deploy. After deploy:
1. Workers stop SIGKILL-looping on animated WebPs
2. Operator can deep-scan their GS download dir to populate the post table via the gallery-dl sidecar fix that shipped in v26.05.25.6
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Context — fixing v26.05.25.6's mislabeled release notes
PR #20's
merge_when_checks_succeed: truefired at the original PR HEAD (06a2f60), NOT at dev's current head. The 8 dev commits that landed AFTER PR #20's queue but BEFORE auto-merge fired never made it into main. v26.05.25.6's release notes claimed they did — they didn't. This PR fixes that.What's actually in this PR (and therefore v26.05.25.7)
Worker no longer hangs on animated WebPs (
c0c9e56)_transparency_pctandcompute_phashshort-circuitis_animated. Was triggering 5+ min PIL multi-frame decode → Celery 300s soft / 360s hard timeout → SIGKILL.FC-Cleanup backend (Tasks 1-6 of 17)
0020_library_audit_run— new table for async transparency/single_color audit lifecycleLibraryAuditRunSQLAlchemy modelbackend/app/services/audits/transparency.py—evaluate(pil_image, *, threshold) -> boolwithis_animatedshort-circuitbackend/app/services/audits/single_color.py— downsample + dominant-color tolerance algorithmcleanup_service.pyextensions:project_min_dimension_violations(synchronous SQL preview)delete_min_dimension_violations(synchronous SQL delete routed through FC-3k'sdelete_images)start_audit_run(creates LibraryAuditRun, dispatches Celery task, concurrent-runs guard)apply_audit_run(Tier-C typed-token confirm, routes throughdelete_images)cancel_audit_run(flips status, scan task checks between batches)AuditAlreadyRunning,AuditNotReady,ConfirmTokenMismatchbackend/app/tasks/library_audit.py::scan_library_for_rule— keyset-paginated PIL inspection task onmaintenancequeue, soft_time_limit=7200, time_limit=7500, 50k matched-IDs cap, cancellation check between batchesTest fixes (
2d4bfa4)ljust(64, ...)[:64]so they stay withinimage_record.sha256varchar(64)Dead-code status
The Cleanup backend has no API or UI surface yet (Tasks 7-16 ship in v26.05.25.8). From a user perspective, this release is purely:
library_audit_runtable on diskSafe to deploy. After deploy:
🤖 Generated with Claude Code