@@ -29,18 +29,21 @@ WHERE group_size > 1;
2929CREATE INDEX ON repo_merge_members (repo_id);
3030ANALYZE repo_merge_members;
3131
32- -- Keep one link per (package, group): the keeper's if it exists, else the most
33- -- recently verified. ROW_NUMBER instead of an EXISTS check against the keeper
34- -- because 3-variant groups exist: two losers linking the same package would
35- -- collide on UNIQUE (package_id, repo_id) after the re-point below.
32+ -- Keep one link per (package, group), ranked the way consumers pick links
33+ -- (sqlFragments bestRepoLink: confidence DESC, declared-on-ties) so the merge
34+ -- preserves the strongest provenance; keeper status only breaks full ties.
35+ -- ROW_NUMBER instead of an EXISTS check against the keeper because 3-variant
36+ -- groups exist: two losers linking the same package would collide on
37+ -- UNIQUE (package_id, repo_id) after the re-point below.
3638DELETE FROM package_repos
3739WHERE id IN (
3840 SELECT id
3941 FROM (
4042 SELECT pr .id ,
4143 ROW_NUMBER() OVER (
4244 PARTITION BY m .keeper_id , pr .package_id
43- ORDER BY m .is_keeper DESC , pr .verified_at DESC , pr .id
45+ ORDER BY pr .confidence DESC , (pr .source = ' declared' ) DESC ,
46+ m .is_keeper DESC , pr .verified_at DESC , pr .id
4447 ) AS rn
4548 FROM package_repos pr
4649 JOIN repo_merge_members m ON m .repo_id = pr .repo_id
@@ -65,6 +68,18 @@ USING repo_merge_members m
6568WHERE c .repo_id = m .repo_id
6669 AND NOT m .is_keeper ;
6770
71+ -- packages.repository_url is denormalized and must keep matching the
72+ -- canonical repos.url (the maven backfill updates the two atomically for the
73+ -- same reason). Match against member urls while the loser rows still exist;
74+ -- last_synced_at is the packages watermark, bumping it ships the correction
75+ -- to Tinybird.
76+ UPDATE packages p
77+ SET repository_url = LOWER (p .repository_url ), last_synced_at = NOW()
78+ FROM repo_merge_members m
79+ JOIN repos r ON r .id = m .repo_id
80+ WHERE p .repository_url = r .url
81+ AND p .repository_url <> LOWER (p .repository_url );
82+
6883-- Cascades security_contacts and repo_activity_snapshot on losers.
6984DELETE FROM repos r
7085USING repo_merge_members m
@@ -81,12 +96,6 @@ WHERE r.id = m.repo_id
8196 AND m .is_keeper
8297 AND r .url <> LOWER (r .url );
8398
84- -- Recurrence guard; also fails the migration if any duplicate survived the
85- -- merge. GitHub-only: it is the only host with both confirmed duplicates and
86- -- guaranteed lowercase-on-write today (CASE_INSENSITIVE_HOSTS in
87- -- canonicalizeRepoUrl also covers gitlab.com, whose merge is a follow-up).
88- -- On other hosts case can be significant and writers do not normalize, so a
89- -- wider index could reject legitimately distinct repos.
90- CREATE UNIQUE INDEX IF NOT EXISTS repos_github_lower_url_uq
91- ON repos (LOWER (url))
92- WHERE host = ' github' ;
99+ -- The recurrence-guard unique index lives in the next migration: it must be
100+ -- built CONCURRENTLY (repos takes continuous worker writes), which cannot run
101+ -- inside this transaction.
0 commit comments