Skip to content

fix(igdb): don't match series games to their base title#3817

Merged
gantoine merged 1 commit into
masterfrom
fix/igdb-sgdb-series-prefix-matching
Jul 19, 2026
Merged

fix(igdb): don't match series games to their base title#3817
gantoine merged 1 commit into
masterfrom
fix/igdb-sgdb-series-prefix-matching

Conversation

@gantoine

Copy link
Copy Markdown
Member

Description
Explain the changes or enhancements you are proposing with this pull request.

Fixes #3805 (a recurrence of #3309, only partially addressed by #3400).

Series titles like Metal Gear Solid: Portable Ops Plus / Portable Ops and the Pokémon Ranger games were resolved to the same IGDB id, and therefore the same SteamGridDB id, as their base game, so distinct ROMs ended up as siblings. Hasheous and RetroAchievements (hash-based) matched them correctly; only the name-search providers were wrong.

Root cause

IGDBHandler._search_rom runs a first pass filtered by game_type (MAIN_GAME, EXPANDED_GAME, PORT, REMAKE, REMASTER, STANDALONE_EXPANSION), which excludes types like EXPANSION. So a more specific variant is frequently absent from that pass's candidates. Jaro-Winkler scores the base title against the searched variant very high for prefix/superset titles (measured with the repo's own matcher: portable ops plus vs portable ops = 0.9928; Pokémon Ranger variants ≈ 0.90–0.91), all far above the 0.75 match threshold. The base was therefore accepted and returned before the broader search passes ever ran. SteamGridDB then inherited the wrong title because fetch_sgdb_details seeds its search from the IGDB name first.

Fix

  • Add _is_prefix_superset_match() to detect when one title's words are a proper prefix of the other's.
  • Only trust a first-pass hit outright when it's an exact match or not a prefix/superset near-miss. Otherwise widen the search: re-query without the game_type filter (the reliable recovery, since the variant is often an excluded type) alongside the existing expanded /search pass, then re-rank across the union so an exact variant (score 1.0) outranks the base near-miss (0.99). The base stays in the candidate pool, so it remains the fallback when no better match exists.

The gate keeps this cheap: exact matches and ordinary fuzzy matches still return on the first pass with no extra API calls; only genuine prefix ambiguity triggers widening.

AI assistance disclosure

Per CONTRIBUTING.md: this change was written with AI assistance (Claude Code / Opus 4.8). The diagnosis, implementation, and tests were AI-generated and human-reviewed.

Checklist
Please check all that apply.

  • I've tested the changes locally
  • I've updated relevant comments
  • I've assigned reviewers for this PR
  • I've added unit tests that cover the changes

Full metadata test suite (321 tests) passes, including 9 new tests covering the prefix heuristic and the _search_rom widening/no-widen paths. trunk check (ruff/black/isort/mypy) clean.

Screenshots (if applicable)

N/A (backend metadata-matching change)

🤖 Generated with Claude Code

Series titles like "Metal Gear Solid: Portable Ops Plus" and the Pokemon
Ranger games were resolved to the same IGDB (and, downstream, SteamGridDB)
entry as their base game, so distinct ROMs became siblings.

The first `_search_rom` pass filters by game_type, which excludes types like
EXPANSION, so a more specific variant is often absent from its candidates.
Jaro-Winkler scores the base title against the searched variant at ~0.99
(well above the 0.75 threshold), so the base was accepted and returned before
the broader search passes ran.

Only trust a first-pass hit outright when it is an exact match or not a
prefix/superset near-miss of the search term. Otherwise widen the search:
re-query without the game_type filter (the reliable recovery for excluded
types) alongside the existing expanded search, then re-rank across the union
so an exact variant outranks the base near-miss. The base stays in the pool,
so it remains the fallback when no better match exists.

Fixes #3805

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 18, 2026 23:48

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@greptile-apps

greptile-apps Bot commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR broadens IGDB matching when a first-pass result is a prefix near-match. The main changes are:

  • Detect proper title-prefix relationships after normalization.
  • Retry without the game-type filter for ambiguous first-pass matches.
  • Re-rank candidates from all search passes together.
  • Add tests for variant recovery and first-pass short-circuiting.

Confidence Score: 5/5

This looks safe to merge.

  • No blocking issues found in the changed code.
  • Platform filters remain applied during widening.
  • Existing candidates remain available as fallbacks during re-ranking.
  • Focused tests cover the new matching paths.

Important Files Changed

Filename Overview
backend/handler/metadata/igdb_handler.py Adds prefix-aware widening and re-ranks the combined IGDB candidate set.
backend/tests/handler/metadata/test_igdb_handler.py Covers prefix detection, excluded-type recovery, exact matches, and ordinary fuzzy matches.

Reviews (1): Last reviewed commit: "fix(igdb): don't match series games to t..." | Re-trigger Greptile

@gantoine
gantoine merged commit b1b7347 into master Jul 19, 2026
11 checks passed
@gantoine
gantoine deleted the fix/igdb-sgdb-series-prefix-matching branch July 19, 2026 01:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] Games from the same series are matched as the original title with Steamgriddb & IGDB scraping

2 participants