Commit Graph

4 Commits

Author SHA1 Message Date
bvandeusen 9e02878b61 feat(playlists): For You composition v2 — multi-seed blend + weighted fresh tail
test-go / test (push) Successful in 29s
test-go / integration (push) Successful in 4m37s
Two approved composition changes (#1269), mechanism only — the
taste/fresh share stays data-decided (#1252) and pick_kind
attribution is unchanged.

Multi-seed blending: each day's build now seeds from up to 3 of the
user's top-5 tracks (pickDailySeeds, the generalized daily shuffle)
instead of one rotating anchor, so the mix spans neighborhoods within
a day and stops feeling bipolar as the rotation swings between
dissimilar seeds. Per-seed pools merge first-seen-deduped; the head
is filled best-first under 50/30/20 per-seed quotas (60/40 for two
seeds) so one neighborhood can't monopolize it, with thin-seed quota
spilling best-first.

Score-weighted fresh tail: the tail sample (rank 2*headN onward) was
uniform — the 380th-best candidate as likely as the 101st. It now
uses deterministic Efraimidis-Spirakis keys with weight halving every
50 ranks, so freshness keeps its "you'll probably enjoy this" half
while still rotating daily.

The retired single-seed picker's one other caller, You-might-like,
moves to pickDailySeeds(n=1) — a single neighborhood per day is right
for a short shelf, and the behavior note is inline.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TsF3cNoKrqCYsU78cXC8U6
2026-07-03 09:02:35 -04:00
bvandeusen a670840114 fix(playlists): Songs-like mixes no longer vanish after a quiet week
test-go / test (push) Successful in 29s
test-go / integration (push) Successful in 4m30s
PickSeedArtists had a hard 7-day window with no fallback: a week
without listening emptied the seed pool, produceSeedMixes returned
zero playlists, and the daily atomic-replace build deleted every
existing "Songs like X" mix until the user played something again
(#1255).

The query now falls back through widening engagement windows — 7d →
30d → all-time → liked artists — the same tiered shape that fixed the
identical vanish for For You's seeds (PickTopPlayedTracksForUser).
Like-boost scoring is preserved in every tier.

All returned rows share the winning tier, and produceSeedMixes maps it
onto the rule-#131 pick-kind ladder (7d = tier1 exact, 30d = tier2,
all-time/liked = tier3) and stamps the built tracks — the #1270
provenance pipeline then attributes plays and skips to seed freshness,
so the metrics card can say whether stale-seeded mixes actually
perform worse.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TsF3cNoKrqCYsU78cXC8U6
2026-07-03 08:38:54 -04:00
bvandeusen 5cd342d521 feat(playlists): daily seed rotation + jitter + 12+13 split for system playlists
Five diversity mechanics — applied to both For-You and Songs-Like-X.

1. For-You seed rotates daily across the user's top-5 most-played
   tracks. pickForYouSeedForDay uses userIDHash(user, day) mod
   len(seeds) so today's mix uses an entirely different similarity
   pool than tomorrow's. Within-day determinism preserved.
2. JitterMagnitude bumped 0.0 → 0.1. The scoring RNG is now seeded
   by userIDHash(user, day) rather than the no-op, so near-tied
   candidates shuffle daily without breaking within-day stability.
3. Head/tail split moves from 20+5 to 12+13. Roughly half the
   playlist comes from the tail now (daily-deterministic via
   tieBreakHash), giving the user substantially different content
   while a 12-track anchor of strong similarity matches keeps the
   mix recognizable.
4. Songs-Like-X seed artists shuffle daily across the user's top-5
   played artists. pickSeedArtistsForDay applies a userIDHash-seeded
   Fisher-Yates and takes 3.
5. scoreAndSortCandidates / pickTopN / pickHeadAndTail gain a userID
   parameter so the RNG can be seeded per-user; existing call sites
   updated; noopRNG removed.

Test fixtures widened similarity gaps (e.g. float64(50-i) instead of
(50-i)/50) so the new jitter (±0.1) doesn't perturb head ordering in
assertions about the head/tail mechanism. New seed_selection_test
coverage for userIDHash + pickForYouSeedForDay + pickSeedArtistsForDay
spans deterministic-within-day, varies-across-days, and graceful
degradation with small candidate pools.

PickTopPlayedTrackForUser replaced by PickTopPlayedTracksForUser
:many in the prior commit (b4801c2). The For-You seed lookup now
goes through pickForYouSeedForDay over the returned slice.
PickSeedArtists's LIMIT widened to 5 in the same prior commit.

For #392 Half A — system playlist content diversity. Half B
(per-user timezone scheduling) is a separate spec.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 10:19:49 -04:00
bvandeusen ef478778ef feat(server/m7-352): system mix helpers (tieBreakHash, pickSeedArtists) 2026-05-04 08:24:39 -04:00