Commit Graph

4 Commits

Author SHA1 Message Date
bvandeusen aff346c731 feat(taste): phase 2a — apply the taste profile via a TasteMatch scoring term (#796)
test-go / test (push) Successful in 39s
test-go / integration (push) Successful in 4m34s
The profile built in phase 1 now changes what gets surfaced. Adds a TasteMatch
term to the weighted-shuffle score so candidates are re-ranked by their fit to
the user's learned taste (positive draws toward it; negative reflects passive
avoidance; 0 at cold start).

- recommendation/score.go: ScoringInputs.TasteMatchScore ([-1,+1]) +
  ScoringWeights.TasteWeight + the term in Score.
- recommendation/taste.go: LoadTasteProfile reads the taste_profile_* tables;
  TasteProfile.Match blends the candidate's artist weight (0.7) and avg genre-tag
  weight (0.3), each tanh-squashed by a fixed scale so one outlier artist can't
  compress the rest. Unknown artist/tags and empty profiles → 0 (neutral).
- candidates.go: both candidate loaders set TasteMatchScore per candidate, so
  every Score caller (system playlists incl. You-might-like, radio) becomes
  taste-aware automatically.
- weights: systemMixWeights.TasteWeight = 1.5 (daily mixes are the primary
  taste surface); config.RecommendationConfig gains taste_weight (default 1.0,
  lighter — radio is seed-directed) wired into the radio handler.
- tests: pure (Match curve incl. saturation/clamp/empty-neutral, Score term
  add+subtract) + DB round-trip (seed taste rows → Match positive). All green
  vs real Postgres; existing playlist/radio tests unaffected (empty profile →
  zero taste effect).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-11 21:29:42 -04:00
bvandeusen 51811c9d35 feat(recommendation): add LoadCandidatesFromSimilarity (5-source candidate pool)
Implements M4c's similarity-driven candidate pool: CandidateSourceLimits,
DefaultCandidateSourceLimits, and LoadCandidatesFromSimilarity consuming
LoadRadioCandidatesV2 (5-way UNION + max-score dedup). Adds 10 integration
tests covering all sources, exclusions, dedup, and edge cases.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-29 08:30:53 -04:00
bvandeusen 5b79aa1047 feat(recommendation): LoadCandidates computes per-candidate ContextualMatchScore
Adds a 6th argument (currentVector SessionVector) to LoadCandidates,
bulk-fetches the user's active contextual_likes in one query, and sets
ContextualMatchScore on each candidate's ScoringInputs via max-similarity
over that candidate's like vectors. Adds helper + 6 integration tests
covering no-likes, single match, multi-like max, soft-delete filtering,
seed-like filtering, and seed-current short-circuit. Adds contextual_likes
to the TRUNCATE list in testPool to prevent cross-test leakage.

internal/api/radio.go is intentionally left broken (Task 6 fixes it).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 20:41:55 -04:00
bvandeusen b513c91520 feat(recommendation): add LoadCandidates DB-backed loader
Wraps the LoadRadioCandidates sqlc query, projects rows to
[]Candidate. Live-DB tests verify seed exclusion, recently-played
exclusion, stat-join correctness (likes + plays + skips +
last_played_at), and cross-user isolation.
2026-04-27 08:03:20 -04:00