soulsync/tests/matching
Broque Thomas 0aa18b0180 Cross-script artist aliases: include canonical name + non-strict fallback
Closes #586. Follow-up to #442 — Cyrillic / kanji canonical names
weren't bridging cross-script comparisons. Reporter case: "Dmitry
Yablonsky" tracks quarantined as audio mismatch with file identified
as "Русская филармония, Дмитрий Яблонский" (4% artist sim) even
though the Cyrillic spelling is just the Russian transliteration.

Codex diagnosed three layered bugs in the alias resolution chain.
This fixes all three.

Bug 1 — fetch_artist_aliases ignores canonical name + sort-name

`core/musicbrainz_service.py:fetch_artist_aliases` only read
`data['aliases']`. For artists where MB's canonical `name` IS the
cross-script form (and the Latin spelling lives only in aliases —
or vice versa), the missing direction never made it into the
returned list. Fix: include both `data['name']` and `data['sort-name']`
alongside the explicit alias entries (deduped, also pulls each
alias entry's sort-name when present).

Bug 2 — lookup_artist_aliases ran search in strict mode only

Strict mode queries `artist:"..."` only and skips MB's alias and
sortname indexes. Cross-script searches found nothing under strict
because the user's Latin input never matches a Cyrillic canonical
name in the artist index. Fix: lifted the search-and-score logic
to a private helper `_search_and_score_artists(name, strict=)` and
fall back to non-strict when strict returns empty OR all results
fail the trust gate. Non-strict (bare query) hits all indexes.

Bug 3 — trust gate weighted local similarity 70%

Combined score = local_sim * 0.7 + mb_score/100 * 0.3. Cross-script
pairs have local sim ~0 → combined ~0.30 → below the 0.85 threshold
→ cached as empty even when MB's own confidence was 100. Fix: added
an MB-only escape — when MB score is >= 95 AND the result is
unambiguous (top result's MB score leads the runner-up by >= 5),
accept regardless of local similarity. The existing combined-score
path stays intact for same-script matches (#442 Hiroyuki Sawano
case still passes via that path).

12 new tests pin every layer:
- fetch_artist_aliases canonical-name inclusion + dedup against
  alias entries + missing-canonical handling + exception path
- strict-then-non-strict fallback (empty-strict + low-strict-score)
- trust gate MB-only escape + low-confidence rejection + ambiguity
  rejection (two artists same MB score) + same-script regression
- end-to-end reporter scenario with the real `artist_names_match`
  helper proving the bridge works for "Русская филармония, Дмитрий
  Яблонский" vs expected "Dmitry Yablonsky"

Existing alias tests in `test_artist_alias_service.py` updated to
reflect: canonical name now appears in `fetch_artist_aliases`
output, lookup makes 2 search calls (strict + non-strict fallback)
on first cache miss instead of 1.

Full suite: 3065 passed.
2026-05-14 13:07:15 -07:00
..
__init__.py Add pure artist-name comparison helper with alias awareness 2026-05-10 16:08:38 -07:00
test_acoustid_verification_aliases.py Tighten alias-lookup trust + add ambiguity gate + diagnostic log 2026-05-10 17:38:03 -07:00
test_album_context_title.py Fix MTV Unplugged & live-album false-quarantine pipeline 2026-05-14 12:14:31 -07:00
test_artist_alias_lookup_586.py Cross-script artist aliases: include canonical name + non-strict fallback 2026-05-14 13:07:15 -07:00
test_artist_alias_service.py Cross-script artist aliases: include canonical name + non-strict fallback 2026-05-14 13:07:15 -07:00
test_artist_aliases.py AcoustID scanner: handle multi-value artist credits 2026-05-10 19:17:59 -07:00