a0470b5_supersede() now applies the new (larger) file's gallery-dl sidecar. Operator-flagged: scanning a GS download dir with smaller IR-migrated images on the receiving end used to swap files but lose the GS sidecar's post metadata entirely. _apply_sidecar is additive (find-or-create Post / Source / ImageProvenance, NULL-only primary_post_id update), so any pre-existing IR-migration provenance survives and the new GS-sidecar ImageProvenance is added alongside. Sidecar parsing is try/except-guarded so malformed JSON can't unwind the file-swap commit.
UI
5666fd5 Quick-scan trigger now produces visible feedback: immediate "Scan triggered" toast + a 2s follow-up status refresh that shows "Scan complete — no new files" when scan_directory quick-finalizes (every file in /import already has a non-failed ImportTask row, so files_seen=0). Operator was clicking the button thinking it was broken because the button worked but the scan was a near-instant no-op with no visible result.
CI
b0bb7aeactions/cache@v4 on ~/.cache/pip keyed by requirements.txt hash + uv pip install --system when available (falls back to pip on older runners). ~2 min saved on warm runs. pytest-xdist parallelization is OUT OF SCOPE for this PR — tests/conftest.py uses a global TRUNCATE ALL TABLES RESTART IDENTITY CASCADE autouse fixture that's incompatible with parallel workers on a shared DB.
1bbe478pytest --durations=25 on the integration job so the next run reports its slowest tests. Pure instrumentation; data drives the targeted-slow-test-vs-parallelization decision.
Schema changes
None.
Migration recovery
The supersede fix matters most for operators who:
Have IR-migrated images already in FC (smaller versions)
Just remapped /import to point at their GS download dir (which has larger versions + gallery-dl sidecars)
Want a deep scan to swap in the larger files AND wire up the GS post metadata
In that workflow, a single /api/migrate/trigger?mode=deep (or via UI) after deploy is enough.
Four follow-up patches on top of v26.05.25.1.
## Importer
- **`a0470b5`** `_supersede()` now applies the new (larger) file's gallery-dl sidecar. Operator-flagged: scanning a GS download dir with smaller IR-migrated images on the receiving end used to swap files but lose the GS sidecar's post metadata entirely. `_apply_sidecar` is additive (find-or-create Post / Source / ImageProvenance, NULL-only `primary_post_id` update), so any pre-existing IR-migration provenance survives and the new GS-sidecar `ImageProvenance` is added alongside. Sidecar parsing is try/except-guarded so malformed JSON can't unwind the file-swap commit.
## UI
- **`5666fd5`** Quick-scan trigger now produces visible feedback: immediate "Scan triggered" toast + a 2s follow-up status refresh that shows "Scan complete — no new files" when `scan_directory` quick-finalizes (every file in `/import` already has a non-failed ImportTask row, so `files_seen=0`). Operator was clicking the button thinking it was broken because the button worked but the scan was a near-instant no-op with no visible result.
## CI
- **`b0bb7ae`** `actions/cache@v4` on `~/.cache/pip` keyed by `requirements.txt` hash + `uv pip install --system` when available (falls back to pip on older runners). ~2 min saved on warm runs. pytest-xdist parallelization is OUT OF SCOPE for this PR — `tests/conftest.py` uses a global `TRUNCATE ALL TABLES RESTART IDENTITY CASCADE` autouse fixture that's incompatible with parallel workers on a shared DB.
- **`1bbe478`** `pytest --durations=25` on the integration job so the next run reports its slowest tests. Pure instrumentation; data drives the targeted-slow-test-vs-parallelization decision.
## Schema changes
None.
## Migration recovery
The supersede fix matters most for operators who:
1. Have IR-migrated images already in FC (smaller versions)
2. Just remapped `/import` to point at their GS download dir (which has larger versions + gallery-dl sidecars)
3. Want a deep scan to swap in the larger files AND wire up the GS post metadata
In that workflow, a single `/api/migrate/trigger?mode=deep` (or via UI) after deploy is enough.
🤖 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.
Four follow-up patches on top of v26.05.25.1.
Importer
a0470b5_supersede()now applies the new (larger) file's gallery-dl sidecar. Operator-flagged: scanning a GS download dir with smaller IR-migrated images on the receiving end used to swap files but lose the GS sidecar's post metadata entirely._apply_sidecaris additive (find-or-create Post / Source / ImageProvenance, NULL-onlyprimary_post_idupdate), so any pre-existing IR-migration provenance survives and the new GS-sidecarImageProvenanceis added alongside. Sidecar parsing is try/except-guarded so malformed JSON can't unwind the file-swap commit.UI
5666fd5Quick-scan trigger now produces visible feedback: immediate "Scan triggered" toast + a 2s follow-up status refresh that shows "Scan complete — no new files" whenscan_directoryquick-finalizes (every file in/importalready has a non-failed ImportTask row, sofiles_seen=0). Operator was clicking the button thinking it was broken because the button worked but the scan was a near-instant no-op with no visible result.CI
b0bb7aeactions/cache@v4on~/.cache/pipkeyed byrequirements.txthash +uv pip install --systemwhen available (falls back to pip on older runners). ~2 min saved on warm runs. pytest-xdist parallelization is OUT OF SCOPE for this PR —tests/conftest.pyuses a globalTRUNCATE ALL TABLES RESTART IDENTITY CASCADEautouse fixture that's incompatible with parallel workers on a shared DB.1bbe478pytest --durations=25on the integration job so the next run reports its slowest tests. Pure instrumentation; data drives the targeted-slow-test-vs-parallelization decision.Schema changes
None.
Migration recovery
The supersede fix matters most for operators who:
/importto point at their GS download dir (which has larger versions + gallery-dl sidecars)In that workflow, a single
/api/migrate/trigger?mode=deep(or via UI) after deploy is enough.🤖 Generated with Claude Code