Fold stale missing tracks into their on-disk replacement (M485) #141

Merged
bvandeusen merged 2 commits from dev into main 2026-10-07 18:17:51 -04:00
2 Commits
Author SHA1 Message Date
bvandeusenandClaude Opus 5.5 865a3176c9 feat(library): fold a missing track into its on-disk replacement (M485 #5286 #5287)
release / web (push) Successful in 2m21s
release / go (push) Successful in 2m34s
release / govulncheck (push) Successful in 40s
release / integration (push) Successful in 6m17s
release / android (push) Successful in 6m36s
release / Build signed APK (releases and dev) (push) Successful in 6m6s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 1m19s
release / Verify release artifacts (tag releases only) (push) Skipped
A track marked missing whose replacement is already on disk under another
row — on the operator's library 355 of 451 missing tracks, nearly all Lidarr
mp3 -> flac upgrades — is folded into the replacement: likes, plays, playlist
entries and tags move across and the missing row goes. Move adoption could
not catch these: the replacements were re-encodes (no shared audio hash) with
no recording MBID at import.

Pairs (ListMissingTrackPairs): the same recording MBID within the album
group, or the same album row and title ignoring case. Each side must have
exactly one candidate; conflicting MBIDs refuse a pair. No duration or track
position gate: on the 142 pairs known to be one recording, 18% differed by
over 2s and the poorly tagged set is where numbering is broken (spike #5274).

Each pair folds in its own transaction after locking both rows and checking
the pair still holds. Runs automatically (operator, 2026-10-07) after a full
scan, after a watcher batch that added or updated tracks, and after an
AcoustID pass that matched any track. The first scan after deploy repairs the
existing rows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 17:23:32 -04:00
bvandeusenandClaude Opus 5.5 2df28345b4 refactor(library): the per-copy fold is a helper the duplicate merge calls (M485 #5285)
MergeDuplicateGroup's loop body — repoint and copy every FK from a removed
copy onto the survivor, inherit its MBID, delete its row, tidy an emptied
album — moves into foldTrackInto, so the missing-pair pass can fold a stale
missing row into its replacement with the same mechanics. The group lock,
file removal and group bookkeeping stay in the merge. No behaviour change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 17:23:32 -04:00