The v26.05.26.1 deploy hit IntegrityError: duplicate key (source_id, external_post_id)=(42, 6166997) during alembic 0022. Same gallery-dl post had been ingested via two different sidecar paths, planting two Post rows with identical external_post_id under different per-post Sources. My migration's "merge collisions" step was placed after the bulk UPDATE post SET source_id = canonical, but Postgres fires uq_post_source_external_id row-by-row during the UPDATE — so the merge step never ran and the migration aborted.
Fix: detect colliding (keep, drop) Post pairs before the bulk reparent (JOIN post-with-post on external_post_id where keep.source = canonical and drop.source ∈ others), merge the drop into the keep (repoint ImageProvenance + ImageRecord.primary_post_id, dedupe ImageProvenance against alembic 0021's UNIQUE, delete the drop Post). Then the bulk reparent runs cleanly.
The migration runs in a transaction; the operator's failed v26.05.26.1 deploy rolled back cleanly to the post-0021 state. No partial-state damage.
7b0dd41 — ci.yml continue-on-error: true on Cache pip wheels
act_runner's cache backend hard-fails the action's JS bundle load (Cannot find module .../dist/restore/index.js) — not just a cache-miss warning, the step itself fails and tanks the whole job. The install step that follows handles cold caches natively (uv pip / pip both work), so disabling the cache here costs ~30s of wheel downloads per job and unblocks CI until the runner-side cache backend gets fixed.
Test plan
Deploy :latest. Alembic should apply 0022 cleanly this time.
Verify Atole's artist page collapses to 1 Source under Management → Subscriptions.
Confirm SELECT id, platform, url, enabled FROM source WHERE artist_id = (SELECT id FROM artist WHERE slug='atole') returns one https://www.patreon.com/cw/Atole row.
## Summary
Hotfix for v26.05.26.1. Two commits.
### `0f7cd3c` — alembic 0022 Post-collision pre-merge (DEPLOY BLOCKER FIX)
The v26.05.26.1 deploy hit `IntegrityError: duplicate key (source_id, external_post_id)=(42, 6166997)` during alembic 0022. Same gallery-dl post had been ingested via two different sidecar paths, planting two Post rows with identical `external_post_id` under different per-post Sources. My migration's "merge collisions" step was placed *after* the bulk `UPDATE post SET source_id = canonical`, but Postgres fires `uq_post_source_external_id` row-by-row during the UPDATE — so the merge step never ran and the migration aborted.
Fix: detect colliding `(keep, drop)` Post pairs *before* the bulk reparent (JOIN post-with-post on `external_post_id` where keep.source = canonical and drop.source ∈ others), merge the drop into the keep (repoint ImageProvenance + ImageRecord.primary_post_id, dedupe ImageProvenance against alembic 0021's UNIQUE, delete the drop Post). Then the bulk reparent runs cleanly.
The migration runs in a transaction; the operator's failed v26.05.26.1 deploy rolled back cleanly to the post-0021 state. No partial-state damage.
### `7b0dd41` — ci.yml `continue-on-error: true` on Cache pip wheels
act_runner's cache backend hard-fails the action's JS bundle load (`Cannot find module .../dist/restore/index.js`) — not just a cache-miss warning, the step itself fails and tanks the whole job. The install step that follows handles cold caches natively (uv pip / pip both work), so disabling the cache here costs ~30s of wheel downloads per job and unblocks CI until the runner-side cache backend gets fixed.
## Test plan
- [ ] Deploy `:latest`. Alembic should apply 0022 cleanly this time.
- [ ] Verify Atole's artist page collapses to 1 Source under Management → Subscriptions.
- [ ] Confirm `SELECT id, platform, url, enabled FROM source WHERE artist_id = (SELECT id FROM artist WHERE slug='atole')` returns one `https://www.patreon.com/cw/Atole` row.
🤖 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.
Summary
Hotfix for v26.05.26.1. Two commits.
0f7cd3c— alembic 0022 Post-collision pre-merge (DEPLOY BLOCKER FIX)The v26.05.26.1 deploy hit
IntegrityError: duplicate key (source_id, external_post_id)=(42, 6166997)during alembic 0022. Same gallery-dl post had been ingested via two different sidecar paths, planting two Post rows with identicalexternal_post_idunder different per-post Sources. My migration's "merge collisions" step was placed after the bulkUPDATE post SET source_id = canonical, but Postgres firesuq_post_source_external_idrow-by-row during the UPDATE — so the merge step never ran and the migration aborted.Fix: detect colliding
(keep, drop)Post pairs before the bulk reparent (JOIN post-with-post onexternal_post_idwhere keep.source = canonical and drop.source ∈ others), merge the drop into the keep (repoint ImageProvenance + ImageRecord.primary_post_id, dedupe ImageProvenance against alembic 0021's UNIQUE, delete the drop Post). Then the bulk reparent runs cleanly.The migration runs in a transaction; the operator's failed v26.05.26.1 deploy rolled back cleanly to the post-0021 state. No partial-state damage.
7b0dd41— ci.ymlcontinue-on-error: trueon Cache pip wheelsact_runner's cache backend hard-fails the action's JS bundle load (
Cannot find module .../dist/restore/index.js) — not just a cache-miss warning, the step itself fails and tanks the whole job. The install step that follows handles cold caches natively (uv pip / pip both work), so disabling the cache here costs ~30s of wheel downloads per job and unblocks CI until the runner-side cache backend gets fixed.Test plan
:latest. Alembic should apply 0022 cleanly this time.SELECT id, platform, url, enabled FROM source WHERE artist_id = (SELECT id FROM artist WHERE slug='atole')returns onehttps://www.patreon.com/cw/Atolerow.🤖 Generated with Claude Code