Rewrites the internal/db/queries comments to rule 32 and regenerates
dbq, whose doc comments and embedded SQL carry them. The bugs behind the
tiered mixes, the md5 order seed, the score bands and the round-robin
arms are restated as the constraint each one enforces; counts from one
library and stale cross-references are gone.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
LB's similarity scores are counts (16 to 1445 for recordings, to 10,875
for artists), and they reached a scorer that reads similarity as 0 to 1.
One edge added 64 to 5,800 points under Songs-like, so likes, skips and
recency stopped mattering for any candidate with an edge.
- ResolveListenBrainzTrackEdges divides each edge by the seed's best
score in its whole cached answer. The cache keeps the raw answer.
- The worker stores matched and unmatched artist rows over the seed's
top artist.
- Migration 0096 rescales the rows already stored.
- The candidate arms hold sim_score bands so tier 1 stays above tier 2:
lb_similar 0.5 + 0.5 x edge, tag_overlap halved, likes_overlap 0.3.
Otherwise a seed's weaker LB edges fell below a shared genre tag.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The worker kept only the similar recordings already in the library, at most
20 of ListenBrainz's 50, and judged freshness by the edges it had written.
Two failures followed, both measured on the operator's library (#3879):
- A seed whose answer matched nothing wrote nothing, so it was never fresh.
With the queue ordered by id, 25 such seeds held its head and were
re-asked every hour; 17 of 2,466 played seeds had any edges.
- A recording that reached the library after its seed was fetched (a
Lidarr import, an MBID from the AcoustID lookup) was never linked until
a refetch, which for the stuck seeds never came.
Now every answer is cached whole in listenbrainz_similar_recordings and
every answer, an empty one or a permanent 4xx included, is recorded in
track_similarity_fetches. The queue reads the fetch record: never-fetched
first, then the oldest, refreshed after 30 days. The listenbrainz edges are
derived in SQL from the cache, one present track per recording and no cap,
for the seed just fetched and for every seed once per tick, so new arrivals
link within the hour without asking ListenBrainz again.
Artists get the same queue fix via artist_similarity_fetches; their answer
was already kept in artist_similarity and artist_similarity_unmatched.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
GET /api/artists/{id}/similar — in-library artists ranked by similarity
score (deduped across sources), ArtistRef list with cover + album count.
GET /api/artists/{id}/top-tracks — current user's most-played tracks for
the artist (skips excluded, quarantine filtered).