Downloaded images stayed at thumbnail_path=NULL until a periodic
backfill sweep picked them up — gallery showed broken-thumbnail tiles
for hours after a download landed.
Importer.attach_in_place deliberately skips inline thumbnail
generation (importer.py:591-592) so the import queue stays moving;
the CALLING task is responsible. tasks/import_file.py:228-239
already does this. tasks/download.py / download_service did not.
Fix in download_service._phase3_persist: after each successful attach_in_place, fan out generate_thumbnail.delay() + tag_and_embed.delay() for each image_id. Lazy import to avoid
circular-import risk.
Test plan
CI green on bd06794
Operator confirms new downloads gain thumbnails without needing
the periodic backfill sweep
## Summary
Downloaded images stayed at `thumbnail_path=NULL` until a periodic
backfill sweep picked them up — gallery showed broken-thumbnail tiles
for hours after a download landed.
`Importer.attach_in_place` deliberately skips inline thumbnail
generation (importer.py:591-592) so the import queue stays moving;
the CALLING task is responsible. `tasks/import_file.py:228-239`
already does this. `tasks/download.py` / `download_service` did not.
Fix in `download_service._phase3_persist`: after each successful
`attach_in_place`, fan out `generate_thumbnail.delay()` +
`tag_and_embed.delay()` for each `image_id`. Lazy import to avoid
circular-import risk.
## Test plan
- [x] CI green on `bd06794`
- [ ] Operator confirms new downloads gain thumbnails without needing
the periodic backfill sweep
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Operator-flagged 2026-06-01: downloaded images stayed at
thumbnail_path=NULL until a periodic backfill sweep picked them up,
surfacing as broken-thumbnail tiles in the gallery for hours after
the download landed.
Importer.attach_in_place deliberately skips inline thumbnail
generation (importer.py:591-592) so the import queue stays moving —
the CALLING task is responsible for the enqueue. tasks/import_file.py
already did this (line 228-239). tasks/download.py / download_service
did not — every gallery-dl-attached image landed un-thumbnailed.
Fix in download_service._phase3_persist: after each
`attach_in_place` returning status in (imported, superseded), fan out
`generate_thumbnail.delay()` + `tag_and_embed.delay()` for each
image_id. Lazy import avoids circular-import risk between
download_service and the celery task modules that depend on it.
Mirrors the existing pattern verbatim — single source of truth for
"what fires after a successful attach" remains a comment in two
places (filesystem-import task, download orchestrator) rather than
a shared helper, because the contexts differ enough (sync session vs
async orchestrator) that abstracting would obscure more than it'd
share.
Test covers the happy-path with two attached files: both get the
thumbnail enqueue AND the ML enqueue, with image_ids drawn from
ImportResult (so future supersede-on-attach paths stay covered).
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.
Summary
Downloaded images stayed at
thumbnail_path=NULLuntil a periodicbackfill sweep picked them up — gallery showed broken-thumbnail tiles
for hours after a download landed.
Importer.attach_in_placedeliberately skips inline thumbnailgeneration (importer.py:591-592) so the import queue stays moving;
the CALLING task is responsible.
tasks/import_file.py:228-239already does this.
tasks/download.py/download_servicedid not.Fix in
download_service._phase3_persist: after each successfulattach_in_place, fan outgenerate_thumbnail.delay()+tag_and_embed.delay()for eachimage_id. Lazy import to avoidcircular-import risk.
Test plan
bd06794the periodic backfill sweep
🤖 Generated with Claude Code