feat(migrations): canonicalize socials twitter.com → x.com + merge twin rows

Merged
SW
4mo ago
+147-0

Summary

Data-migration companion to api#755: rewrites all socials.profile_url twitter.com/* keys to the canonical x.com/* domain and merges rows where both spellings exist, so X scrape write-backs land on the rows artists are actually connected to.

Tracking issue: recoupable/chat#1851 (PR #2 of 2 required). Canonical-domain decision (x.com) recorded there 2026-07-06.

What it does

  1. Twin merge (403 pairs, measured 2026-07-06 prod): the x.com row is the keeper. Backfills any fresher scrape fields from the loser, repoints all 7 FK columns referencing socials.id (account_socials.social_id, social_posts.social_id, post_comments.social_id, social_fans.artist_social_id, social_fans.fan_social_id, fan_segments.fan_social_id, agent_status.social_id) with delete-guards on each table's unique/logical key, then deletes the loser.
  2. In-place rename (23,622 twinless rows): twitter.com/<handle> → x.com/<handle>.
  3. Post-condition: raises if any twitter.com/* key survives, so a partial run cannot commit silently.

Verification (dry-run against prod inside a rolled-back transaction, 2026-07-06)

CheckResult
All statements execute, no constraint violations✅
twitter.com/* rows remaining0
x.com/* rows after76,072 (= 52,450 existing + 23,622 renamed — exact)
Issue's Done-when fixture: the 3 artist-connected rows from chat#1851all 3 repointed to x.com/* keepers
x.com/disclosure keeper carries the fresh scrape483,103 followers (was orphaned; connected row showed 0)
DB state after rollbackuntouched (24,025 / 52,450 — confirmed)

Merge sequencing

api#755 merges first (stops new twitter.com keys being written), then this migration cleans up existing rows. Running this first would also work but re-drift until the api change deploys.

🤖 Generated with Claude Code


Summary by cubic

Canonicalizes socials from twitter.com to x.com by merging duplicate rows and repointing foreign keys so X scraper write-backs attach to artist-connected records. Twinless twitter rows are renamed in place, and the migration fails if any twitter.com keys remain.

  • Migration
    • Run after recoupable/api#755 (normalizes new writes to x.com) to complete chat#1851.
    • Post-check aborts if any twitter.com rows survive to prevent partial application.