#6685·beets

Refactor Candidate Resolution into `Candidates` Collections

Author: snejusCreated May 29, 2026Updated Sep 6, 2026

Summary

Refactor album and singleton candidate handling into dedicated Candidates collection types that share orchestration behavior.

This includes:

  • owning candidate storage keyed by provider+id
  • deduplication
  • sorting by distance
  • recommendation calculation
  • search orchestration (resolve, search_ids, search, fallback strategy)

Why

  • Replace separate tag_album / tag_item orchestration with one pattern.
  • Keep recommendation logic in one place.
  • Let importer/session interact with a unified API (task.candidates).

Scope

  • Introduce base Candidates collection contract.
  • Implement AlbumCandidates and TrackCandidates provider-specific fetch hooks.
  • Move recommendation logic into Candidates.recommendation.
  • Update manual search/manual ID flows to mutate and reuse the same candidate collection.

Acceptance Criteria

  • task.lookup_candidates(...) delegates to task.candidates.resolve(...).
  • Manual search/manual ID reuse the same candidate collection object.
  • Album and singleton candidate lists are sorted and deduplicated consistently.
  • Recommendation behavior remains equivalent to previous thresholds/gap logic.
  • Tests cover multi-source candidate dedup/sorting for album and singleton paths.