feat(taste): household co-play similarity — #1533
test-go / test (push) Successful in 29s
test-go / integration (push) Successful in 4m48s

Milestone #160 Opt 5. A collaborative candidate arm: tracks by artists
co-played across the instance with the seed's artist.

Minstrel is a single shared-library, multi-user server (no per-user
library ACL — verified: no owner/share/group model), so the "household"
is the whole instance's user set; the rule #47 scoping is satisfied by
the shared-library boundary. Single-user servers produce no edges.

- No migration: source='user_cooccurrence' was pre-whitelisted in the
  0009 similarity CHECK from day one.
- internal/db/queries/coplay.sql: Delete + Insert artist co-play edges.
  Score = Jaccard of the two artists' distinct-player sets (controls for
  globally-popular artists); >= 2 co-players AND Jaccard >= floor kept
  (the floor also self-limits hub artists). Completed plays, 365d window.
- internal/coplay: periodic worker (6h) that atomic-replaces the
  user_cooccurrence edge set from play_events — pure local SQL, no
  external calls. Wired in main.go alongside the similarity worker.
- LoadRadioCandidatesV2: new coplay_artists arm (source='user_cooccurrence',
  seed-artist based, 0.5 damp like similar_artists) + $11 limit;
  CandidateSourceLimits.UserCoplay (default 20, For-You 40).
- Integration tests: perfect-overlap Jaccard=1.0 edge + single-user
  empty-set gate.

Device axis and AcousticBrainz (Opt 4) are separately tracked; this
closes the milestone-#160 sequential options.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-14 10:07:19 -04:00
parent 65dd132b3d
commit 199fec2058
9 changed files with 441 additions and 2 deletions
+7
View File
@@ -15,6 +15,7 @@ import (
"github.com/jackc/pgx/v5/pgxpool"
"git.fabledsword.com/bvandeusen/minstrel/internal/config"
"git.fabledsword.com/bvandeusen/minstrel/internal/coplay"
"git.fabledsword.com/bvandeusen/minstrel/internal/coverart"
"git.fabledsword.com/bvandeusen/minstrel/internal/db"
"git.fabledsword.com/bvandeusen/minstrel/internal/eventbus"
@@ -206,6 +207,12 @@ func run() error {
similarityWorker := similarity.NewWorker(pool, listenbrainz.NewClient(), logger.With("component", "similarity"))
go similarityWorker.Run(ctx)
// Start the household co-play worker (#1533). Recomputes artistartist
// co-occurrence edges (source='user_cooccurrence') from play_events every
// 6h — a collaborative candidate arm for the radio/mix pools. Pure local
// SQL, no external calls; empty on single-user servers.
go coplay.NewWorker(pool, logger.With("component", "coplay")).Run(ctx)
// Start the tag-enrichment worker (#1490). Reconciles the compiled-in
// tag providers with tag_provider_settings, bumps the sources version if
// the provider set changed (re-opening settled rows), then drains tracks