Skip to content

Fix metadata IDs not persisting when handler is disabled or game not found#3085

Merged
gantoine merged 4 commits intomasterfrom
copilot/fix-launchbox-id-persistence
Mar 8, 2026
Merged

Fix metadata IDs not persisting when handler is disabled or game not found#3085
gantoine merged 4 commits intomasterfrom
copilot/fix-launchbox-id-persistence

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 8, 2026

When a user manually sets a metadata source ID (e.g. LaunchBox, IGDB, MobyGames, ScreenScraper, RetroAchievements, Flashpoint) via "Edit Game", the ID is silently overwritten with None before being saved to the DB.

Root cause: After calling get_rom_by_id() for any metadata source, the result is unconditionally merged into cleaned_data. When the handler is disabled or the game isn't found, it returns a Rom object with id=None, clobbering the user-provided value.

Fix:

# Before — always overwrites cleaned_data["<source>_id"]
source_rom = await meta_source_handler.get_rom_by_id(cleaned_data["source_id"])
cleaned_data.update(source_rom)

# After — only merges when metadata fetch actually resolved an ID
source_rom = await meta_source_handler.get_rom_by_id(cleaned_data["source_id"])
if source_rom.get("source_id"):
    cleaned_data.update(source_rom)

This preserves the user-supplied ID when the handler can't enrich it with metadata, while still applying full metadata updates when the remote lookup succeeds. The fix is applied consistently to all six metadata sources: LaunchBox, IGDB, MobyGames, ScreenScraper, RetroAchievements, and Flashpoint.

Tests: Added _persists_when_handler_disabled tests for each metadata source to cover the get_rom_by_id → id=None path.

Original prompt

This section details on the original issue you should resolve

<issue_title>[Bug] LaunchBox game ID don't persist on DB</issue_title>
<issue_description>RomM version
4.7.0

Describe the bug
LaunchBox game ID don't persist on DB in PUT /api/roms/id endpoint

To Reproduce
Steps to reproduce the behavior:

  1. Go to 'Edit Game.'
  2. Add LaunchBox ID
  3. Save
  4. After reload page, ID are void again
    </issue_description>

Comments on the Issue (you are @copilot in this section)


🔒 GitHub Advanced Security automatically protects Copilot coding agent pull requests. You can protect all pull requests by enabling Advanced Security for your repositories. Learn more about Advanced Security.

Copilot AI changed the title [WIP] Fix LaunchBox game ID not persisting in database Fix LaunchBox ID not persisting when metadata handler is disabled or game not found Mar 8, 2026
cleaned_data.update({"launchbox_id": None, "launchbox_metadata": {}})

if cleaned_data["ra_id"] and int(cleaned_data["ra_id"]) != rom.ra_id:
ra_rom = await meta_ra_handler.get_rom_by_id(rom, ra_id=cleaned_data["ra_id"])
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@copilot this issue might also be present for the other metadata sources, can you check if that's the case, fix it and update tests?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Already fixed for all metadata sources in aac4614 — the same if <source>_rom.get("<source>_id"): guard was applied to IGDB, MobyGames, ScreenScraper, RetroAchievements, and Flashpoint, along with a _persists_when_handler_disabled test for each.

Copilot AI changed the title Fix LaunchBox ID not persisting when metadata handler is disabled or game not found Fix metadata IDs not persisting when handler is disabled or game not found Mar 8, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 8, 2026

Test Results

930 tests  +6   929 ✅ +6   2m 6s ⏱️ -8s
  1 suites ±0     1 💤 ±0 
  1 files   ±0     0 ❌ ±0 

Results for commit 27fb339. ± Comparison against base commit 055e973.

♻️ This comment has been updated with latest results.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 8, 2026

☂️ Python Coverage

current status: ✅

Overall Coverage

Lines Covered Coverage Threshold Status
13585 9042 67% 0% 🟢

New Files

No new covered files...

Modified Files

File Coverage Status
backend/endpoints/rom.py 50% 🟢
TOTAL 50% 🟢

updated for commit: 27fb339 by action🐍

@gantoine gantoine marked this pull request as ready for review March 8, 2026 13:58
@greptile-apps
Copy link
Copy Markdown

greptile-apps bot commented Mar 8, 2026

Greptile Summary

This PR fixes a bug where user-supplied metadata source IDs (IGDB, MobyGames, ScreenScraper, RetroAchievements, LaunchBox, Flashpoint) were silently overwritten with None when the corresponding handler was disabled or the remote lookup returned no match.

Key changes:

  • In backend/endpoints/rom.py, each unconditional cleaned_data.update(source_rom) call is guarded by a check on the returned source ID (e.g., if igdb_rom.get("igdb_id"):). The update is only applied when the handler actually resolved metadata, leaving the user-supplied value intact otherwise.
  • Six new unit tests in backend/tests/endpoints/test_rom.py cover the handler disabled → id=None → ID preserved path for every affected metadata source, mirroring the pattern of the existing "happy path" tests.

The fix is minimal, targeted, and applied consistently across all six sources.

Confidence Score: 5/5

  • This PR is safe to merge — the fix is a minimal, well-tested guard that prevents data loss without altering any happy-path behaviour.
  • The change is a targeted one-line guard per metadata source with no side effects on the success path. All six affected sources are handled consistently, the existing tests for the success path continue to pass, and six new tests directly cover the regression scenario. No edge cases (e.g., valid id=0) are realistically reachable for these external metadata systems.
  • No files require special attention.

Important Files Changed

Filename Overview
backend/endpoints/rom.py Adds guard checks before merging handler results into cleaned_data, preserving user-provided metadata IDs when a handler is disabled or returns no match. Logic is correct and applied consistently across all six sources.
backend/tests/endpoints/test_rom.py Adds six _persists_when_handler_disabled tests that mock each handler to return id=None and verify the user-supplied ID is preserved in the response. Tests follow the same pattern as existing passing tests and correctly exercise the new conditional branch.

Sequence Diagram

sequenceDiagram
    participant Client
    participant update_rom as update_rom (rom.py)
    participant Handler as Metadata Handler
    participant DB

    Client->>update_rom: PUT /api/roms/{id} (source_id=X)
    update_rom->>update_rom: cleaned_data["source_id"] = X

    update_rom->>Handler: get_rom_by_id(X)

    alt Handler enabled AND game found
        Handler-->>update_rom: SourceRom(source_id=X, metadata=...)
        update_rom->>update_rom: source_rom.get("source_id") → truthy
        update_rom->>update_rom: cleaned_data.update(source_rom) ✅ full metadata applied
    else Handler disabled OR game not found
        Handler-->>update_rom: SourceRom(source_id=None)
        update_rom->>update_rom: source_rom.get("source_id") → None (falsy)
        update_rom->>update_rom: skip update ✅ cleaned_data["source_id"] stays = X
    end

    update_rom->>DB: save(cleaned_data)
    DB-->>update_rom: saved rom
    update_rom-->>Client: 200 OK (source_id=X preserved)
Loading

Last reviewed commit: 27fb339

@gantoine gantoine merged commit 4618bc5 into master Mar 8, 2026
9 checks passed
@gantoine gantoine deleted the copilot/fix-launchbox-id-persistence branch March 8, 2026 14:07
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] LaunchBox game ID don't persist on DB

2 participants