diff --git a/alembic/versions/0022_source_per_artist_platform.py b/alembic/versions/0022_source_per_artist_platform.py index f85b96a..d3e75dd 100644 --- a/alembic/versions/0022_source_per_artist_platform.py +++ b/alembic/versions/0022_source_per_artist_platform.py @@ -109,7 +109,7 @@ def upgrade() -> None: by_epid: dict = {} for epid, post_id, src_id in all_posts: by_epid.setdefault(epid, []).append((post_id, src_id)) - for epid, posts in by_epid.items(): + for _epid, posts in by_epid.items(): if len(posts) <= 1: continue # Prefer a Post already under canonical as the keep. @@ -120,6 +120,25 @@ def upgrade() -> None: keep_id = posts[0][0] # already sorted by id ASC drop_ids = [p[0] for p in posts if p[0] != keep_id] for drop_id in drop_ids: + # Pre-delete image_provenance rows under drop_ whose + # image_record_id ALREADY has a provenance under keep — + # the UPDATE below would otherwise repoint them and + # trip uq_image_provenance_image_post (alembic 0021) + # row-by-row before any after-the-fact dedupe could + # run. Operator's v26.05.26.3 deploy 2026-05-26 tripped + # this at line 123. + conn.execute( + text(""" + DELETE FROM image_provenance + WHERE post_id = :drop_ + AND image_record_id IN ( + SELECT image_record_id FROM image_provenance + WHERE post_id = :keep + ) + """), + {"keep": keep_id, "drop_": drop_id}, + ) + # Now safe to repoint the survivors. conn.execute( text(""" UPDATE image_provenance SET post_id = :keep @@ -134,15 +153,6 @@ def upgrade() -> None: """), {"keep": keep_id, "drop_": drop_id}, ) - # Repointed provenance may now collide on - # uq_image_provenance_image_post (alembic 0021). Dedupe. - conn.execute(text(""" - DELETE FROM image_provenance ip1 - USING image_provenance ip2 - WHERE ip1.image_record_id = ip2.image_record_id - AND ip1.post_id = ip2.post_id - AND ip1.id > ip2.id - """)) conn.execute( text("DELETE FROM post WHERE id = :drop_"), {"drop_": drop_id},