fix(discover): compare against a baseline run, not a hardcoded score — #2377
TestSuggestArtists_UntaggedCandidateSurvivesAlongsideTagged asserted the untagged candidate's score was 0.9 — the raw similarity value I'd seeded. It's actually 1.61, because the pool score is signal-weighted by the seed query: ln(1+signal) x similarity, and a liked seed carries signal 5, so ln(6) x 0.9. The assertion was testing the seeding arithmetic, which is a different layer and not what the test is about. Rewritten to run the same request twice — once with the tag term disabled, once enabled — and assert the untagged candidate's score is IDENTICAL across both. That states the real property (the blend leaves untagged candidates alone) without depending on how the pool score is derived, so it survives future changes to seeding. Added a sanity assertion that the TAGGED candidate's score did move, so the comparison can't pass by both runs being trivially identical — the same "a test that cannot fail" trap recorded for this milestone. Exact-preservation at the arithmetic level is already covered where it belongs, by TestApplyTagOverlap_UntaggedCandidateScoreIsUnchanged. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -399,23 +399,57 @@ func TestSuggestArtists_UntaggedCandidateSurvivesAlongsideTagged(t *testing.T) {
|
||||
seedCandidateTag(t, pool, "match", "shoegaze", 1.0)
|
||||
// "loud" is deliberately left with NO cached tags at all.
|
||||
|
||||
out, err := SuggestArtists(context.Background(), pool, user.ID, 30, 12, 1.0)
|
||||
// Compared against the same request with the term disabled, rather than
|
||||
// against a literal. The pool score is signal-weighted by the seed query
|
||||
// (ln(1+signal) x similarity), so hardcoding a number here would assert
|
||||
// against the seeding maths — a different layer — and break whenever that
|
||||
// changes. The property under test is only that the blend leaves an
|
||||
// untagged candidate alone.
|
||||
blended, err := SuggestArtists(context.Background(), pool, user.ID, 30, 12, 1.0)
|
||||
if err != nil {
|
||||
t.Fatalf("SuggestArtists: %v", err)
|
||||
t.Fatalf("SuggestArtists(blended): %v", err)
|
||||
}
|
||||
if len(out) != 2 {
|
||||
t.Fatalf("len = %d, want 2 — the untagged candidate must still appear", len(out))
|
||||
baseline, err := SuggestArtists(context.Background(), pool, user.ID, 30, 12, 0)
|
||||
if err != nil {
|
||||
t.Fatalf("SuggestArtists(baseline): %v", err)
|
||||
}
|
||||
var loud *ArtistSuggestion
|
||||
for i := range out {
|
||||
if out[i].MBID == "loud" {
|
||||
loud = &out[i]
|
||||
if len(blended) != 2 {
|
||||
t.Fatalf("len = %d, want 2 — the untagged candidate must still appear", len(blended))
|
||||
}
|
||||
|
||||
scoreOf := func(out []ArtistSuggestion, mbid string) (float64, bool) {
|
||||
for _, s := range out {
|
||||
if s.MBID == mbid {
|
||||
return s.Score, true
|
||||
}
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
if loud == nil {
|
||||
t.Fatal("untagged candidate vanished from the deck")
|
||||
want, ok := scoreOf(baseline, "loud")
|
||||
if !ok {
|
||||
t.Fatal("untagged candidate missing from the baseline deck")
|
||||
}
|
||||
if loud.Score != 0.9 {
|
||||
t.Errorf("untagged score = %v, want 0.9 unchanged", loud.Score)
|
||||
got, ok := scoreOf(blended, "loud")
|
||||
if !ok {
|
||||
t.Fatal("untagged candidate vanished once the tag term was enabled")
|
||||
}
|
||||
if got != want {
|
||||
t.Errorf("untagged score = %v, want %v (identical to the term-disabled run)", got, want)
|
||||
}
|
||||
// Sanity: the tagged candidate DID move, so the comparison above is
|
||||
// meaningful rather than both runs being trivially identical.
|
||||
if tagged, _ := scoreOf(blended, "match"); tagged == mustScore(t, baseline, "match") {
|
||||
t.Error("the tagged candidate's score did not change — the term did nothing")
|
||||
}
|
||||
}
|
||||
|
||||
func mustScore(t *testing.T, out []ArtistSuggestion, mbid string) float64 {
|
||||
t.Helper()
|
||||
for _, s := range out {
|
||||
if s.MBID == mbid {
|
||||
return s.Score
|
||||
}
|
||||
}
|
||||
t.Fatalf("no candidate %q in %v", mbid, out)
|
||||
return 0
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user