feat(worker): per-seed discovery contributions so score sums across chunks/sweeps
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -96,6 +96,75 @@ def test_config_from_config_parses_and_defaults():
|
||||
d.albums_per_artist, d.min_score) == (False, 168, 5, 20, 1, 0.0)
|
||||
|
||||
|
||||
def _artist_score(conn, mbid):
|
||||
with conn.cursor() as cur:
|
||||
cur.execute('SELECT score, "seedCount" FROM "DiscoverySuggestion" WHERE "artistMbid" = %s', (mbid,))
|
||||
return cur.fetchone()
|
||||
|
||||
|
||||
def test_score_sums_across_separate_chunks(conn):
|
||||
# Two seeds, both eligible, forced into separate one-seed chunks by chunk_size=1.
|
||||
insert_watched_artist(conn, mbid="s1", name="Seed One",
|
||||
last_discovered_sql="now() - interval '200 hours'")
|
||||
insert_watched_artist(conn, mbid="s2", name="Seed Two",
|
||||
last_discovered_sql="now() - interval '190 hours'")
|
||||
src = FakeSimilaritySource(similar={
|
||||
"s1": [SimilarArtist("c1", "Shared", 0.6)],
|
||||
"s2": [SimilarArtist("c1", "Shared", 0.5)],
|
||||
})
|
||||
cfg = DiscoveryConfig(chunk_size=1)
|
||||
run_discovery(conn, [src], FakeMbBrowser(), cfg) # processes s1 (older)
|
||||
run_discovery(conn, [src], FakeMbBrowser(), cfg) # processes s2
|
||||
# replace-not-accumulate would leave 0.5/seedCount1; contributions give the sum.
|
||||
assert _artist_score(conn, "c1") == (1.1, 2)
|
||||
|
||||
|
||||
def test_partial_sweep_preserves_other_seeds_contribution(conn):
|
||||
# Full sweep: c1 gets s1(0.6)+s2(0.5)=1.1. Then only s1 is due again with a new
|
||||
# score; s2's contribution must survive untouched.
|
||||
insert_watched_artist(conn, mbid="s1", name="Seed One",
|
||||
last_discovered_sql="now() - interval '200 hours'")
|
||||
insert_watched_artist(conn, mbid="s2", name="Seed Two",
|
||||
last_discovered_sql="now() - interval '200 hours'")
|
||||
src = FakeSimilaritySource(similar={
|
||||
"s1": [SimilarArtist("c1", "Shared", 0.6)],
|
||||
"s2": [SimilarArtist("c1", "Shared", 0.5)],
|
||||
})
|
||||
run_discovery(conn, [src], FakeMbBrowser(), DiscoveryConfig()) # both -> 1.1/2
|
||||
assert _artist_score(conn, "c1") == (1.1, 2)
|
||||
|
||||
# s1 due again (older than interval), s2 fresh; s1 now scores c1 at 0.7.
|
||||
with conn.cursor() as cur:
|
||||
cur.execute('UPDATE "WatchedArtist" SET "lastDiscoveredAt" = now() - interval \'200 hours\' WHERE mbid = %s', ("s1",))
|
||||
cur.execute('UPDATE "WatchedArtist" SET "lastDiscoveredAt" = now() WHERE mbid = %s', ("s2",))
|
||||
conn.commit()
|
||||
src2 = FakeSimilaritySource(similar={"s1": [SimilarArtist("c1", "Shared", 0.7)]})
|
||||
run_discovery(conn, [src2], FakeMbBrowser(), DiscoveryConfig())
|
||||
assert _artist_score(conn, "c1") == (1.2, 2) # 0.7 (new s1) + 0.5 (kept s2)
|
||||
|
||||
|
||||
def test_seed_dropoff_lowers_seedcount(conn):
|
||||
insert_watched_artist(conn, mbid="s1", name="Seed One",
|
||||
last_discovered_sql="now() - interval '200 hours'")
|
||||
insert_watched_artist(conn, mbid="s2", name="Seed Two",
|
||||
last_discovered_sql="now() - interval '200 hours'")
|
||||
src = FakeSimilaritySource(similar={
|
||||
"s1": [SimilarArtist("c1", "Shared", 0.6)],
|
||||
"s2": [SimilarArtist("c1", "Shared", 0.5)],
|
||||
})
|
||||
run_discovery(conn, [src], FakeMbBrowser(), DiscoveryConfig())
|
||||
assert _artist_score(conn, "c1") == (1.1, 2)
|
||||
|
||||
# s1 re-swept but no longer finds c1 -> its contribution is removed, c1 recomputed.
|
||||
with conn.cursor() as cur:
|
||||
cur.execute('UPDATE "WatchedArtist" SET "lastDiscoveredAt" = now() - interval \'200 hours\' WHERE mbid = %s', ("s1",))
|
||||
cur.execute('UPDATE "WatchedArtist" SET "lastDiscoveredAt" = now() WHERE mbid = %s', ("s2",))
|
||||
conn.commit()
|
||||
src2 = FakeSimilaritySource(similar={"s1": [SimilarArtist("c9", "Other", 0.9)]})
|
||||
run_discovery(conn, [src2], FakeMbBrowser(), DiscoveryConfig())
|
||||
assert _artist_score(conn, "c1") == (0.5, 1) # only s2 remains
|
||||
|
||||
|
||||
def test_run_discovery_processes_at_most_chunk_size_seeds(conn):
|
||||
from lyra_worker.discovery import DiscoveryConfig, run_discovery
|
||||
from lyra_worker.adapters.fakes import FakeMbBrowser, FakeSimilaritySource
|
||||
|
||||
Reference in New Issue
Block a user