@@ -77,7 +77,15 @@ LEFT JOIN packages p ON p.purl = s.purl
7777ON CONFLICT (advisory_id, ecosystem, package_name) DO NOTHING
7878`
7979
80- // Separate statement — must execute after ADVISORY_PACKAGES_MERGE_SQL so advisory_packages rows exist
80+ // Separate statement — must execute after ADVISORY_PACKAGES_MERGE_SQL so advisory_packages rows exist.
81+ // Skips any advisory_package that already has a live OSV-owned range: OSV is the
82+ // source of truth over deps.dev for overlapping advisory_packages (ADR-0001
83+ // §advisory_affected_ranges delete/dedup strategy), and this merge runs on its own
84+ // BQ-driven schedule, independent of and potentially after an OSV sync — the
85+ // per-tuple ON CONFLICT DO NOTHING below can't see that, since a NULL-bounds raw
86+ // tuple has a different key than OSV's structured tuple and would insert as a new
87+ // live duplicate. The NOT EXISTS guard makes the ownership rule package-level
88+ // instead of tuple-level, so deps.dev never adds a live row once OSV owns the package.
8189const ADVISORY_AFFECTED_RANGES_MERGE_SQL = `
8290INSERT INTO advisory_affected_ranges (advisory_package_id, range_raw, unaffected_raw, introduced_version, created_at, updated_at)
8391SELECT
@@ -91,6 +99,13 @@ JOIN advisories adv ON adv.osv_id = s.osv_id
9199JOIN advisory_packages ap ON ap.advisory_id = adv.id
92100 AND ap.ecosystem = s.ecosystem
93101 AND ap.package_name = s.package_name
102+ WHERE NOT EXISTS (
103+ SELECT 1 FROM advisory_affected_ranges live
104+ WHERE live.advisory_package_id = ap.id
105+ AND live.deleted_at IS NULL
106+ AND live.range_raw IS NULL
107+ AND live.unaffected_raw IS NULL
108+ )
94109ON CONFLICT (advisory_package_id, COALESCE(introduced_version, ''), COALESCE(fixed_version, ''), COALESCE(last_affected, '')) DO NOTHING
95110`
96111
0 commit comments