feat(playlists): expand For You to 100 tracks (Discover parity)

Closes Fable #414. forYouHeadN/forYouTailN go 12/13 → 50/50 so the
For-You snapshot is 100 tracks, matching Discover. Motivated by the
shuffle-on-play default that just shipped (#413): a 25-track shuffle
pool repeats fast; 100 makes re-plays within a day feel varied.

pickHeadAndTail already degrades gracefully when the candidate pool
is too thin for a full head/tail split (returns top-N-by-score),
mirroring how Discover returns <100 when its buckets are thin — no
new edge-case handling needed. No build-path test asserts the
For-You total; pickHeadAndTail unit tests pass their own head/tail
values so they're unaffected.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-15 07:32:55 -04:00
parent 45c72993f3
commit 69569a5c2b
+12 -4
View File
@@ -151,14 +151,22 @@ var systemMixWeights = recommendation.ScoringWeights{
// forYouHeadN is the number of top-scored tracks that anchor the For-You
// playlist; forYouTailN is the number sampled from positions 2*headN
// onward, daily-deterministic via tieBreakHash. The 12 + 13 split
// onward, daily-deterministic via tieBreakHash. The 50 + 50 split
// (~50% from the tail) gives the user a substantially different mix
// day-to-day while preserving a recognizable anchor of strong
// similarity matches. Songs-like-X keeps simple pickTopN (the
// similarity matches.
//
// Sized to 100 to match Discover so the shuffle-on-play default
// (system playlists shuffle when launched from a tile) has a deep
// enough pool that re-plays within a day feel varied. Libraries with
// a thin For-You candidate pool degrade gracefully: pickHeadAndTail
// returns top-N-by-score when the capped pool can't support a full
// head/tail split, exactly as Discover returns fewer than 100 when
// its buckets are thin. Songs-like-X keeps simple pickTopN (the
// seed-artist context already frames the "you'll like this" promise).
const (
forYouHeadN = 12
forYouTailN = 13
forYouHeadN = 50
forYouTailN = 50
)
// scoreAndSortCandidates scores every candidate with recommendation.Score