fix(db): repair the two things the scanner quietly undid

Both migrations exist because of scanner behaviour fixed in this branch,
and both are idempotent.

31 tracks the listener had disliked were sitting back in LIBRARY,
restored by successive library scans, and were being served again. They
return to HIDDEN unless the dislike was deliberately reverted.

740 tracks had artist tags but no edge in the claim graph, which put
them out of reach of every Vibe generator but the fallback. Their
credits are written from track_artists, the same shape the scanner now
produces at scan time.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KENqSChfyqWnor6ud2WWH6
This commit is contained in:
kami
2026-08-10 14:00:32 +04:00
parent 5a019bd35c
commit a75d36b821
+36
View File
@@ -851,4 +851,40 @@ export const MIGRATIONS: Migration[] = [
);
`,
},
{
// Every library scan used to reset a disliked track from HIDDEN back to
// LIBRARY, so tracks the listener had rejected kept returning in the Vibe.
// The scanner no longer does that; this puts the tracks it already undid
// back where the dislike left them. A track whose dislike was deliberately
// restored has no `dislikes` row and is untouched here.
// `20260707_backfill_claims` wrote tag-derived credits once, and nothing
// wrote them afterwards: the scanner filled `track_artists` but left the
// claim spine to MusicBrainz. Every track added since, and every track
// MusicBrainz does not know, therefore had no edge in `claim_fusion` and
// was unreachable by all but one Vibe generator. The scanner now writes
// these itself; this catches up the tracks it already missed.
id: '20260810_backfill_tag_credits_since_first_scan',
sql: `
INSERT INTO claims (subject_type, subject_id, predicate, object_type, object_id, source, confidence)
SELECT 'track', ta.track_id,
CASE WHEN ta.role = 'main' THEN 'credited_main_on' ELSE 'featured_on' END,
'artist', ta.artist_id, 'tag', 1.0
FROM track_artists ta
JOIN tracks t ON t.id = ta.track_id
WHERE t.state IN ('LIBRARY', 'RECOMMENDED')
ON CONFLICT (subject_type, subject_id, predicate, object_type, object_id, source, user_id)
DO NOTHING;
`,
},
{
id: '20260810_rehide_resurrected_dislikes',
sql: `
UPDATE tracks t
SET state = 'HIDDEN'
FROM dislikes d
WHERE d.track_id = t.id
AND d.deleted_at IS NULL
AND t.state IN ('LIBRARY', 'RECOMMENDED');
`,
},
];