From d3bec2ee10364eef8a4cab0bce5afa98c6709e00 Mon Sep 17 00:00:00 2001 From: Jonathan Date: Fri, 10 Jul 2026 19:07:58 +0200 Subject: [PATCH] refactor: make adapter .tier the single source of truth for ranking Co-Authored-By: Claude Opus 4.8 (1M context) --- worker/lyra_worker/adapters/fakes.py | 1 + worker/lyra_worker/pipeline.py | 2 +- worker/lyra_worker/quality.py | 11 ++--------- worker/lyra_worker/types.py | 1 + worker/tests/test_quality.py | 13 +++++-------- worker/tests/test_ranker.py | 5 ++++- 6 files changed, 14 insertions(+), 19 deletions(-) diff --git a/worker/lyra_worker/adapters/fakes.py b/worker/lyra_worker/adapters/fakes.py index 2c2c7fe..be47239 100644 --- a/worker/lyra_worker/adapters/fakes.py +++ b/worker/lyra_worker/adapters/fakes.py @@ -31,6 +31,7 @@ class _BaseFake: matched_album=target.album, quality=_QUALITIES.get(self.name, _QUALITIES["youtube"]), track_count=tracks, + source_tier=self.tier, ) ] diff --git a/worker/lyra_worker/pipeline.py b/worker/lyra_worker/pipeline.py index ee63857..17c4bba 100644 --- a/worker/lyra_worker/pipeline.py +++ b/worker/lyra_worker/pipeline.py @@ -127,7 +127,7 @@ def run_pipeline( found: list[Candidate] = [] for adapter in adapters: for c in adapter.search(target): - found.append(replace(c, confidence=score_confidence(target, c))) + found.append(replace(c, source_tier=adapter.tier, confidence=score_confidence(target, c))) _persist_candidates(conn, job_id, found) # 3. rank diff --git a/worker/lyra_worker/quality.py b/worker/lyra_worker/quality.py index e40db1d..5304c55 100644 --- a/worker/lyra_worker/quality.py +++ b/worker/lyra_worker/quality.py @@ -1,7 +1,5 @@ from lyra_worker.types import Candidate, Quality -_SOURCE_TIERS = {"qobuz": 0, "soulseek": 1, "youtube": 2} - def quality_class(q: Quality) -> int: """3 = hi-res lossless, 2 = CD lossless, 1 = lossy.""" @@ -13,11 +11,6 @@ def quality_class(q: Quality) -> int: return 1 -def source_tier(source: str) -> int: - """Lower is better. Unknown sources rank worst.""" - return _SOURCE_TIERS.get(source, 99) - - def rank_key(c: Candidate) -> tuple[int, int]: - """Sort key; larger is better. Quality class first, then source tier.""" - return (quality_class(c.quality), -source_tier(c.source)) + """Sort key; larger is better. Quality class first, then source tier (from the adapter).""" + return (quality_class(c.quality), -c.source_tier) diff --git a/worker/lyra_worker/types.py b/worker/lyra_worker/types.py index cac640e..a67708a 100644 --- a/worker/lyra_worker/types.py +++ b/worker/lyra_worker/types.py @@ -26,6 +26,7 @@ class Candidate: matched_album: str quality: Quality track_count: int + source_tier: int = 99 confidence: float = 0.0 diff --git a/worker/tests/test_quality.py b/worker/tests/test_quality.py index 8a45be2..7c91aec 100644 --- a/worker/tests/test_quality.py +++ b/worker/tests/test_quality.py @@ -1,14 +1,17 @@ -from lyra_worker.quality import quality_class, source_tier, rank_key +from lyra_worker.quality import quality_class, rank_key from lyra_worker.types import Candidate, Quality HIRES = Quality(fmt="FLAC", lossless=True, bit_depth=24, sample_rate=96000) CD = Quality(fmt="FLAC", lossless=True, bit_depth=16, sample_rate=44100) MP3 = Quality(fmt="MP3", lossless=False, bitrate_kbps=320) +_TIERS = {"qobuz": 0, "soulseek": 1, "youtube": 2} + def _cand(source, quality): return Candidate(source=source, source_ref="x", matched_artist="A", - matched_album="B", quality=quality, track_count=10) + matched_album="B", quality=quality, track_count=10, + source_tier=_TIERS[source]) def test_quality_class_tiers(): @@ -17,12 +20,6 @@ def test_quality_class_tiers(): assert quality_class(MP3) == 1 -def test_source_tier_order(): - assert source_tier("qobuz") == 0 - assert source_tier("soulseek") == 1 - assert source_tier("youtube") == 2 - - def test_design_ranking_order(): # Qobuz hi-res > Qobuz lossless > Soulseek FLAC > Soulseek MP3 > YouTube ordered = [ diff --git a/worker/tests/test_ranker.py b/worker/tests/test_ranker.py index 5b91e0c..65f3e25 100644 --- a/worker/tests/test_ranker.py +++ b/worker/tests/test_ranker.py @@ -6,11 +6,14 @@ CD = Quality(fmt="FLAC", lossless=True, bit_depth=16, sample_rate=44100) MP3 = Quality(fmt="MP3", lossless=False, bitrate_kbps=320) TARGET = MBTarget(artist="Radiohead", album="In Rainbows", track_count=10) +_TIERS = {"qobuz": 0, "soulseek": 1, "youtube": 2} + def _cand(source, quality, artist="Radiohead", album="In Rainbows", tracks=10): return Candidate(source=source, source_ref=f"{source}:{quality.fmt}", matched_artist=artist, matched_album=album, - quality=quality, track_count=tracks) + quality=quality, track_count=tracks, + source_tier=_TIERS[source]) def test_returns_empty_for_no_candidates():