Skip to content

refactor(enrichment): unify the duplicated/divergent fuzzy-match scorer (one best-match fn) #551

Description

@thewrz

Why

Surfaced by the #541 search→queue consistency audit. The same "best fuzzy match" decision is implemented twice, and the copies have drifted:

  • app/services/sync/enrichment_pipeline.py::_find_best_match (the request/master-store path) — has a min_artist_score floor (0.35), a BPM-consensus tiebreaker (+0.01), version bonus/penalty (±0.1, min_score 0.4), and structured logging.
  • The inline matcher in app/services/recommendation/enrichment.py (enrich_from_beatport / enrich_from_tidal, ~:31/:121) — same core scoring (fuzzy_match_score + artist_match_score + version bonus) but missing the min_artist_score floor, the BPM-consensus tiebreaker, and the logging.

Same decision in 3+ call sites with behavioral drift → meets the DRY-extraction bar. The recommendation copy can accept a worse-artist match the request path would reject.

What

  • Extract ONE shared best-match function (e.g. app/services/track_normalizer.py or a small match.py) with the request-path behavior (incl. min_artist_score + BPM-consensus tiebreaker), and route both the enrichment pipeline and the recommendation engine through it.
  • This also sets up feat(setbuilder): pool reads global store + pool→builder contract & build coverage gate #542 (pool→master-store), which will want the identical matcher when pool imports funnel into the same tracks row.

Notes / context

Source: #541 search→queue consistency audit (MEDIUM-3).

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    Status
    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions