Operator feedback on the prior unification commit (7473e98d):
1. NewForYou should daily-rotate alongside Rediscover and FirstListens.
The 'newest album first regardless of day' intent was the wrong
call - operator wants visible day-over-day movement on every
deterministic mix surface. Spec flipped to dailyRotate: true.
2. Diversity caps (<=2 per album / <=3 per artist) on every mix, not
just the historically-diverse ones. The 2-per-album limit has
helped a lot on the operator's library; extending it to NewForYou
and FirstListens (previously album-coherent / no cap) surfaces
more distinct albums per day. Spec flipped to diversify: true on
all five.
3. Fallback when diversity caps strip the pool below the 100-track
target: finishMix now calls topUpFromRaw, which appends non-capped
tracks from the raw SQL pool (preserving original ranked order +
skipping duplicates) until the target is hit or the pool runs out.
On rich libraries the cap yields >= 100 and top-up never runs; on
thin / album-heavy libraries we ship a partly-diversified 100
instead of a strictly-diversified 40.
Net effect: every deterministic mix now rotates day-over-day, every
mix gets the same diversity treatment (with graceful degradation),
and the producer surface stays a single factory over a spec list.
The five discovery-mix producers (Deep Cuts, Rediscover, New for you,
On this day, First listens) were near-identical boilerplate that
differed only in (a) which SQL query they ran and (b) whether to
diversity-cap the result. Folded into one produceDiscoveryMix(spec)
factory + a per-mix discoveryMixSpec slice. The registry composes the
factory over the spec list so adding a new mix is one struct literal
+ a SQL query, never a new func.
Also fixes the user-reported bug that several mixes 'show the same
content from yesterday'. Audit of the SQL queries:
- Deep Cuts: ORDER BY md5(t.id::text || $2::text) → day-keyed
- On this day: ORDER BY w.c DESC, md5(...) → day-keyed
- Rediscover: ORDER BY tier, c DESC, id → invariant
- New for you: ORDER BY al.created_at DESC, disc, track → invariant
- First listens: ORDER BY tier, al.id, disc, track → invariant
The three invariant ones produced identical content day-over-day. The
unified spec carries a dailyRotate bool: when set, the producer
applies a daily-deterministic offset rotate-left of the candidate
pool BEFORE diversify+truncate. Rotation (not shuffle) preserves
contiguous-block ordering inside each day's slice — matters for First
listens which is album-coherent.
Set on Rediscover + First listens (where same-content-every-day is
clearly a bug). Left off New for you because 'newest album first
regardless of day' is the intended UX for that surface — daily
rotation there would feel wrong.
Daily rotation seed: rand.New(NewSource(int64(userIDHash(userID,
dateStr)))) — same primitive used by For-You's pickHeadAndTail
sampling so behavior is consistent across the system playlist family.
No test file referenced the deleted produceXxx functions directly,
only the registry, so this is a closed refactor.
Each is one candidate query + one registry entry; zero client work
(R2 made tiles/refresh/shuffle generic, all are singleton kinds so
web's server `refreshable` flag and Flutter's derived getter both
light up automatically).
- deep_cuts (#419): <=2-play tracks from liked / heavily-played
artists; diversity-capped.
- rediscover (#420): >=5-play tracks not heard in 6 months, by
historical affection.
- new_for_you (#421): tracks from albums added <=30d whose artist
the user likes/plays; album-coherent (no cap).
- on_this_day (#422): tracks played within ±7 day-of-year in prior
windows (>60d ago), weighted by play count.
- first_listens (#423): never-played albums, tiered liked-artist →
played-artist → rest; album-coherent.
system_mixes.go producers mirror the Discover model (SQL gives the
ranking; finishMix caps+truncates to 100 to match For-You/Discover
shuffle depth; album-coherent mixes skip the cap). Builder query
failure is non-fatal (logged, yields no playlist) like Discover.
Existing system_test existence checks are unaffected.
Closes the #411 system-playlists-v2 umbrella's new-types thread.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>