v26.05.26.2's pre-merge only looked for collisions where keep.source_id = canonical AND drop_.source_id ∈ others. It missed the case where two non-canonical Sources both have Posts with the same external_post_id, and canonical has none. Bulk UPDATE moves the first one onto canonical cleanly, then collides on the second.
Fix
Group ALL Posts in the (artist, platform) by external_post_id (across canonical AND all others). For any group with count > 1:
Pick the keep: prefer a Post already under canonical; else the lowest-id Post in the group
Merge the rest into keep (repoint ImageProvenance + ImageRecord.primary_post_id, dedupe ImageProvenance, delete drop Posts)
This now handles both:
(A) canonical has Post P, "other" has Post Q with same epid — keep canonical's P
(B) two "others" both have Posts with same epid (canonical has none) — keep the lowest-id one; the bulk reparent then moves it to canonical safely
Plus the (rare) case where canonical and multiple "others" all share the same epid — keep canonical's, drop all others.
Bonus: ci.yml cache steps removed entirely
1803a09 was already on dev — removed the four Cache pip wheels steps. act_runner's cache backend has been broken for 11+ days; the cached path wasn't even uv's actual cache dir. ~30s/job cost, simpler ci.yml. Riding along with this hotfix.
Test plan
Deploy :latest. Alembic should apply 0022 cleanly this time.
## Summary
Second hotfix for the v26.05.26.1 alembic 0022 migration. v26.05.26.2 fixed one collision case but missed another.
### What broke this time
```
IntegrityError: duplicate key (source_id, external_post_id)=(42, 6166997)
```
v26.05.26.2's pre-merge only looked for collisions where `keep.source_id = canonical` AND `drop_.source_id ∈ others`. It missed the case where **two non-canonical Sources both have Posts with the same `external_post_id`, and canonical has none**. Bulk UPDATE moves the first one onto canonical cleanly, then collides on the second.
### Fix
Group ALL Posts in the `(artist, platform)` by `external_post_id` (across canonical AND all others). For any group with count > 1:
- Pick the keep: prefer a Post already under canonical; else the lowest-id Post in the group
- Merge the rest into keep (repoint ImageProvenance + ImageRecord.primary_post_id, dedupe ImageProvenance, delete drop Posts)
This now handles both:
- (A) canonical has Post P, "other" has Post Q with same epid — keep canonical's P
- (B) two "others" both have Posts with same epid (canonical has none) — keep the lowest-id one; the bulk reparent then moves it to canonical safely
Plus the (rare) case where canonical and multiple "others" all share the same epid — keep canonical's, drop all others.
### Bonus: ci.yml cache steps removed entirely
`1803a09` was already on dev — removed the four `Cache pip wheels` steps. act_runner's cache backend has been broken for 11+ days; the cached path wasn't even uv's actual cache dir. ~30s/job cost, simpler ci.yml. Riding along with this hotfix.
## Test plan
- [ ] Deploy `:latest`. Alembic should apply 0022 cleanly this time.
- [ ] Verify Atole's artist page collapses to 1 Source.
🤖 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
Second hotfix for the v26.05.26.1 alembic 0022 migration. v26.05.26.2 fixed one collision case but missed another.
What broke this time
v26.05.26.2's pre-merge only looked for collisions where
keep.source_id = canonicalANDdrop_.source_id ∈ others. It missed the case where two non-canonical Sources both have Posts with the sameexternal_post_id, and canonical has none. Bulk UPDATE moves the first one onto canonical cleanly, then collides on the second.Fix
Group ALL Posts in the
(artist, platform)byexternal_post_id(across canonical AND all others). For any group with count > 1:This now handles both:
Plus the (rare) case where canonical and multiple "others" all share the same epid — keep canonical's, drop all others.
Bonus: ci.yml cache steps removed entirely
1803a09was already on dev — removed the fourCache pip wheelssteps. act_runner's cache backend has been broken for 11+ days; the cached path wasn't even uv's actual cache dir. ~30s/job cost, simpler ci.yml. Riding along with this hotfix.Test plan
:latest. Alembic should apply 0022 cleanly this time.🤖 Generated with Claude Code