The artists row showed only a couple of tiles because the fallback drew from
explicit artist-likes only. Broaden both fallbacks to entities you've shown
affinity for — artist fallback = explicit artist-likes ∪ artists of liked
albums ∪ artists of liked tracks; album fallback = liked albums ∪ albums of
liked tracks. Read-side, fills immediately.
Taste phase 2b — taste_overlap candidate arm (#796)
A 6th arm to the candidate union: in-library tracks by the user's top
positively-weighted taste-profile artists enter the pool (weight > 0,
deterministic order, pool-inclusion only — TasteMatch scores the fit). For-You
/ radio use it; You-might-like sets it to 0 (it wants NOT-engaged artists).
GET /api/me/recommendation-metrics: per-source plays / skips / skip-rate /
avg-completion so you can see which surfaces land and tune the taste weights. A
"Recommendation metrics" card on the Settings page renders it. (For-You /
Discover / mixes; You-might-like plays aren't source-tagged yet.)
Deferred: phase 3 (context) — design-heavy, payoff concentrated in radio; do it
later if the metrics show radio needs help.
Server + web. Three CI-green commits since v2026.06.11.
## You-might-like fallback broadened (#790)
The artists row showed only a couple of tiles because the fallback drew from
explicit artist-likes only. Broaden both fallbacks to entities you've shown
affinity for — artist fallback = explicit artist-likes ∪ artists of liked
albums ∪ artists of liked tracks; album fallback = liked albums ∪ albums of
liked tracks. Read-side, fills immediately.
## Taste phase 2b — taste_overlap candidate arm (#796)
A 6th arm to the candidate union: in-library tracks by the user's top
positively-weighted taste-profile artists enter the pool (weight > 0,
deterministic order, pool-inclusion only — TasteMatch scores the fit). For-You
/ radio use it; You-might-like sets it to 0 (it wants NOT-engaged artists).
## Taste phase 4 — recommendation observability (#796)
GET /api/me/recommendation-metrics: per-source plays / skips / skip-rate /
avg-completion so you can see which surfaces land and tune the taste weights. A
"Recommendation metrics" card on the Settings page renders it. (For-You /
Discover / mixes; You-might-like plays aren't source-tagged yet.)
Deferred: phase 3 (context) — design-heavy, payoff concentrated in radio; do it
later if the metrics show radio needs help.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
The fallback pulled artists only from explicit artist-likes (general_likes_artists),
but most users like albums and tracks far more than artists — so the artists row
still came up thin (a couple of tiles) even with a rich library, while the albums
row filled fine.
Broaden both fallbacks to "entities you've shown affinity for":
- artist fallback = explicit artist-likes ∪ artists of liked albums ∪ artists of
liked tracks.
- album fallback = explicit album-likes ∪ albums of liked tracks.
New dedicated queries (ListYouMightLike{Artist,Album}FallbackForUser) replace the
narrow Rediscover-fallback reuse; same projection so the Go layer still converts
directly. (Aliased + fully-qualified the UNION arms — sqlc merges UNION scopes,
so unqualified user_id was ambiguous across the three like tables.)
Test: 12 liked TRACKS by distinct artists, no artist-likes → the artist row now
fills from their artists (was empty before).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2a re-ranks the existing pool by TasteMatch; this ensures taste-relevant tracks
ARE in the pool. Adds a 6th arm to LoadRadioCandidatesV2: in-library tracks by
the user's top positively-weighted taste-profile artists ($10 K, weight > 0,
deterministic weight-DESC,id order so it doesn't reintroduce same-day
nondeterminism). Pool-inclusion only (sim_score 0) — TasteMatch already scores
the fit. Empty for cold-start users (no profile).
- CandidateSourceLimits.TasteOverlap; default 20 (radio), 80 for For-You via
systemForYouSourceLimits.
- You-might-like deliberately sets TasteOverlap=0: it surfaces NOT-actively-
engaged artists, so flooding its pool with top-taste (mostly already-played)
artists would just feed the read-time dedup.
- Test: positive-weight artist's track enters via the arm; negative-weight one
is excluded (weight > 0). Existing pool tests unaffected (no profile seeded).
Deferred within 2b: profile-seeded For-You — marginal given the arm + TasteMatch
already inject taste broadly (top-played seed ≈ top-taste artist).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Per-source play outcomes so the operator can see whether each recommendation
surface is landing and tune the now-operator-tunable taste weights.
Server:
- query RecommendationSourceMetricsForUser: groups the user's play_events by
source (system-playlist surface), reporting plays / skips / avg completion
over a window; NULL-source (library/radio) plays excluded.
- GET /api/me/recommendation-metrics?days=30 (default 30, capped 365) →
{window_days, sources:[{source, plays, skips, skip_rate, avg_completion}]}.
- handler test: 401 unauth; per-source aggregation + NULL-source exclusion +
skip_rate / avg_completion math.
Web:
- lib/api/metrics.ts: query + friendly source labels.
- settings page gains a "Recommendation metrics" card (table of surface / plays
/ skip rate / avg completion), with loading/error/empty states.
- settings tests mock the new query (manual subscribe-store, hoisting-safe).
Note: You-might-like plays aren't source-tagged (it's a Home row, not a system
playlist), so this covers For-You / Discover / the mixes. Tagging YML plays
would be a client follow-up.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Server + web. Three CI-green commits since v2026.06.11.
You-might-like fallback broadened (#790)
The artists row showed only a couple of tiles because the fallback drew from
explicit artist-likes only. Broaden both fallbacks to entities you've shown
affinity for — artist fallback = explicit artist-likes ∪ artists of liked
albums ∪ artists of liked tracks; album fallback = liked albums ∪ albums of
liked tracks. Read-side, fills immediately.
Taste phase 2b — taste_overlap candidate arm (#796)
A 6th arm to the candidate union: in-library tracks by the user's top
positively-weighted taste-profile artists enter the pool (weight > 0,
deterministic order, pool-inclusion only — TasteMatch scores the fit). For-You
/ radio use it; You-might-like sets it to 0 (it wants NOT-engaged artists).
Taste phase 4 — recommendation observability (#796)
GET /api/me/recommendation-metrics: per-source plays / skips / skip-rate /
avg-completion so you can see which surfaces land and tune the taste weights. A
"Recommendation metrics" card on the Settings page renders it. (For-You /
Discover / mixes; You-might-like plays aren't source-tagged yet.)
Deferred: phase 3 (context) — design-heavy, payoff concentrated in radio; do it
later if the metrics show radio needs help.
🤖 Generated with Claude Code
The fallback pulled artists only from explicit artist-likes (general_likes_artists), but most users like albums and tracks far more than artists — so the artists row still came up thin (a couple of tiles) even with a rich library, while the albums row filled fine. Broaden both fallbacks to "entities you've shown affinity for": - artist fallback = explicit artist-likes ∪ artists of liked albums ∪ artists of liked tracks. - album fallback = explicit album-likes ∪ albums of liked tracks. New dedicated queries (ListYouMightLike{Artist,Album}FallbackForUser) replace the narrow Rediscover-fallback reuse; same projection so the Go layer still converts directly. (Aliased + fully-qualified the UNION arms — sqlc merges UNION scopes, so unqualified user_id was ambiguous across the three like tables.) Test: 12 liked TRACKS by distinct artists, no artist-likes → the artist row now fills from their artists (was empty before). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>Per-source play outcomes so the operator can see whether each recommendation surface is landing and tune the now-operator-tunable taste weights. Server: - query RecommendationSourceMetricsForUser: groups the user's play_events by source (system-playlist surface), reporting plays / skips / avg completion over a window; NULL-source (library/radio) plays excluded. - GET /api/me/recommendation-metrics?days=30 (default 30, capped 365) → {window_days, sources:[{source, plays, skips, skip_rate, avg_completion}]}. - handler test: 401 unauth; per-source aggregation + NULL-source exclusion + skip_rate / avg_completion math. Web: - lib/api/metrics.ts: query + friendly source labels. - settings page gains a "Recommendation metrics" card (table of surface / plays / skip rate / avg completion), with loading/error/empty states. - settings tests mock the new query (manual subscribe-store, hoisting-safe). Note: You-might-like plays aren't source-tagged (it's a Home row, not a system playlist), so this covers For-You / Discover / the mixes. Tagging YML plays would be a client follow-up. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>