fix: a duplicate fold never deletes a lossless copy for a lossy one, nor folds two versions (M498)
release / govulncheck (push) Successful in 14s
release / web (push) Successful in 1m21s
release / go (push) Successful in 1m31s
release / android (push) Successful in 4m58s
release / integration (push) Successful in 5m0s
release / Build signed APK (releases and dev) (push) Successful in 5m7s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 15s
release / Verify release artifacts (tag releases only) (push) Skipped

The first album-copy fold pass on 2026-10-20 removed five FLACs (Måneskin
Rush!, Weezer 2016) in favour of mp3s whose only edge was a recording MBID,
and an explicit "Suite-Pee" for its clean version. ProposeSurvivor now ranks
lossless before tag fit; tag fit still outranks file size, which is what the
Humanz rips needed. The fold keys copies by their version words (title and
file name), so a clean, live or instrumental copy holding the same title tag
is linked, not folded.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-20 12:36:55 -04:00
co-authored by Claude Opus 5.5
parent 16a152b862
commit f32abc974f
6 changed files with 102 additions and 21 deletions
+15 -6
View File
@@ -90,10 +90,11 @@ func TestProposeSurvivor_ReasonIsTheDecidingRule(t *testing.T) {
}
}
// M498 #5436: the copy whose tags fit the album outranks quality, which decides
// only between copies whose tags fit equally. Each case is built so the quality
// rules would choose the other copy, so a reorder that drops tag fit fails.
func TestProposeSurvivor_TagFitFirst(t *testing.T) {
// M498 #5436: the copy whose tags fit the album outranks every quality rule but
// lossless, which decides first: a deleted FLAC cannot be recovered, and on
// 2026-10-20 five went for mp3s whose only edge was a recording MBID. Each tag
// fit case is built so file size would choose the other copy.
func TestProposeSurvivor_LosslessThenTagFit(t *testing.T) {
at := time.Date(2025, 1, 1, 0, 0, 0, 0, time.UTC)
cases := []struct {
name string
@@ -102,10 +103,18 @@ func TestProposeSurvivor_TagFitFirst(t *testing.T) {
wantReason string
}{
{
name: "tag fit beats lossless",
name: "lossless beats tag fit",
cands: []SurvivorCandidate{
{TrackID: "flac", FileFormat: "flac", FileSize: 40_000_000, AddedAt: at, TagFit: 1},
{TrackID: "fits", FileFormat: "mp3", FileSize: 5_000_000, AddedAt: at, TagFit: 3},
{TrackID: "flac", FileFormat: "flac", FileSize: 40_000_000, AddedAt: at, TagFit: 1},
},
wantID: "flac", wantReason: "lossless (flac)",
},
{
name: "tag fit beats a larger file",
cands: []SurvivorCandidate{
{TrackID: "big", FileFormat: "mp3", FileSize: 9_000_000, AddedAt: at, TagFit: 1},
{TrackID: "fits", FileFormat: "m4a", FileSize: 5_000_000, AddedAt: at, TagFit: 3},
},
wantID: "fits", wantReason: "tags fit the album",
},