Skip to content

feat(mister): classify arcade hardware systems#1094

Merged
wizzomafizzo merged 4 commits into
mainfrom
feat/1050-mister-arcade-systems
Jul 13, 2026
Merged

feat(mister): classify arcade hardware systems#1094
wizzomafizzo merged 4 commits into
mainfrom
feat/1050-mister-arcade-systems

Conversation

@wizzomafizzo

@wizzomafizzo wizzomafizzo commented Jul 13, 2026

Copy link
Copy Markdown
Member

Summary

  • preserve complete MiSTer Arcade indexing while duplicating ArcadeDB-classified games into granular hardware systems
  • add CPS, PGM, Sega, Taito, Namco, Irem, and Jaleco arcade system definitions with Arcade fallbacks
  • duplicate Neo Geo media as NeoGeoMVS with an independent MiSTer setname configuration
  • resolve fallback systems in order instead of combining primary and fallback result pools

Closes #1050

Summary by CodeRabbit

  • New Features
    • Added system metadata for additional arcade platforms and reclassified CPS1, CPS2, and CPS3 as Arcade.
    • Expanded MiSTer arcade support with curated platform detection, per-system launchers, and NeoGeo MVS launcher support.
  • Improvements
    • Enhanced random launch and search to try the selected system tier first, then fall back tier-by-tier only when needed.
  • Tests
    • Added coverage for tiered fallback behavior and MiSTer arcade scanner caching/retry semantics.

@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a5034cb6-3d7f-41e1-b92f-0faa4fe48ee7

📥 Commits

Reviewing files that changed from the base of the PR and between 6f83d2c and b0d07fb.

📒 Files selected for processing (1)
  • pkg/platforms/mister/arcade_systems_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • pkg/platforms/mister/arcade_systems_test.go

📝 Walkthrough

Walkthrough

Adds curated arcade system metadata and MiSTer launchers, then changes random and search commands to resolve primary systems and fallbacks in ordered tiers.

Changes

Arcade system definitions and MiSTer launchers

Layer / File(s) Summary
Arcade system metadata and fallback definitions
pkg/assets/systems/*, pkg/database/systemdefs/systemdefs.go
Adds metadata for nine arcade systems, changes CPS1–3 categories to Arcade, and registers system definitions with Arcade fallbacks.
MiSTer arcade classification and cache
pkg/platforms/mister/arcade_systems.go, pkg/platforms/mister/arcade_systems_test.go
Maps arcade database and MRA set names to systems, scans arcade files, caches results, and tests classification, filtering, and retry behavior.
MiSTer launcher integration
pkg/platforms/mister/arcade_systems.go, pkg/platforms/mister/platform.go, pkg/platforms/mister/arcade_systems_test.go
Adds NeoGeo MVS and granular arcade launchers while preserving the base Arcade launcher configuration.

Tiered random and search resolution

Layer / File(s) Summary
System tier resolution helpers
pkg/zapscript/launch.go, pkg/zapscript/launch_test.go
Builds ordered, deduplicated system tiers and queries random or search results tier by tier.
Random and search command integration
pkg/zapscript/launch.go, pkg/zapscript/launch_test.go
Routes random and search commands through primary systems and fallback tiers instead of combined fallback lists.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant PlatformLaunchers
  participant arcadeSystemCache
  participant ArcadeDatabase
  participant MRAFiles
  PlatformLaunchers->>arcadeSystemCache: load arcade classifications
  arcadeSystemCache->>ArcadeDatabase: read arcade set names
  arcadeSystemCache->>MRAFiles: scan and read MRA files
  arcadeSystemCache-->>PlatformLaunchers: cache per-system scan results
Loading
sequenceDiagram
  participant LaunchCommands
  participant orderedSystemTiers
  participant TieredMediaLookup
  participant gamesdb
  LaunchCommands->>orderedSystemTiers: resolve primary and fallback systems
  orderedSystemTiers-->>TieredMediaLookup: return ordered tiers
  TieredMediaLookup->>gamesdb: query current tier
  gamesdb-->>TieredMediaLookup: return results or no rows
  TieredMediaLookup-->>LaunchCommands: return first matching tier
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 6.90% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the PR’s main change: classifying MiSTer arcade hardware systems.
Linked Issues check ✅ Passed The changes satisfy #1050 by exposing CPS, PGM, Sega, Taito, Namco, Irem, and Jaleco systems as selectable arcade targets with Arcade fallbacks.
Out of Scope Changes check ✅ Passed No clearly unrelated changes are visible; the launcher, tiered fallback, and asset updates all support arcade system classification.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/1050-mister-arcade-systems

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pkg/platforms/mister/arcade_systems_test.go`:
- Around line 18-28: Extend the arcadeSetSystems test data with a CPS-3 entry
and assert that its normalized set name maps to systemdefs.SystemCPS3. Keep the
existing CPS-1, CPS-1.5, PGM, and unknown-platform assertions unchanged.

In `@pkg/platforms/mister/arcade_systems.go`:
- Around line 175-247: Add unit-test coverage for addNeoGeoMVSLauncher using a
stub base Scanner: invoke the updated NeoGeo scanner to populate the cache, then
invoke the NeoGeoMVS Scanner and verify it returns the same entries without
calling the stub again. Also verify the expected scanner results and errors
while exercising the shared cache behavior.
- Around line 52-75: Update scanArcadeFiles and its walk callback to check ctx
and stop with ctx.Err() on cancellation. Make load propagate cancellation
without marking the cache loaded or retaining partial results, and have
captureScanner and scanner return the context error instead of success. Add
tests covering cancellation during scanning and ensuring a later scan reloads
rather than reusing partial results.
- Around line 27-39: Add a CPS-3 entry to misterArcadeSystemSpecs using
systemdefs.SystemCPS3 and the platform label “Capcom CPS-3”, so CPS-3 titles are
classified correctly and receive a dedicated launcher.

In `@pkg/zapscript/launch_test.go`:
- Around line 1281-1308: The test
TestSearchMediaBySystemTier_DoesNotCombineFallback currently returns a primary
result and skips the fallback loop. Update or add a focused test where the
primary AmigaCD32 search returns an empty result, the Amiga fallback search is
invoked and returns a result, and the assertions verify that fallback result is
returned without combining tiers. Ensure both mock expectations are configured
and asserted.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 1531be65-a456-4662-94e5-f784101fac8b

📥 Commits

Reviewing files that changed from the base of the PR and between ce35511 and bafad5d.

📒 Files selected for processing (18)
  • pkg/assets/systems/CPS1.json
  • pkg/assets/systems/CPS2.json
  • pkg/assets/systems/CPS3.json
  • pkg/assets/systems/IremM72.json
  • pkg/assets/systems/IremM92.json
  • pkg/assets/systems/JalecoMegaSystem1.json
  • pkg/assets/systems/NamcoSystem1.json
  • pkg/assets/systems/PGM.json
  • pkg/assets/systems/SegaSTV.json
  • pkg/assets/systems/SegaSystem16.json
  • pkg/assets/systems/SegaSystem18.json
  • pkg/assets/systems/TaitoF2.json
  • pkg/database/systemdefs/systemdefs.go
  • pkg/platforms/mister/arcade_systems.go
  • pkg/platforms/mister/arcade_systems_test.go
  • pkg/platforms/mister/platform.go
  • pkg/zapscript/launch.go
  • pkg/zapscript/launch_test.go

Comment thread pkg/platforms/mister/arcade_systems_test.go
Comment thread pkg/platforms/mister/arcade_systems.go
Comment thread pkg/platforms/mister/arcade_systems.go
Comment on lines +175 to +247
func addNeoGeoMVSLauncher(
platform *Platform,
neoGeo *platforms.Launcher,
) (updatedNeoGeo, neoGeoMVS platforms.Launcher) {
updatedNeoGeo = *neoGeo
baseScanner := updatedNeoGeo.Scanner
var mu syncutil.Mutex
var cached []platforms.ScanResult
var loaded bool

updatedNeoGeo.Scanner = func(
ctx context.Context,
cfg *config.Instance,
systemID string,
results []platforms.ScanResult,
) ([]platforms.ScanResult, error) {
scanned, err := baseScanner(ctx, cfg, systemID, results)
if err == nil {
mu.Lock()
cached = append([]platforms.ScanResult(nil), scanned...)
loaded = true
mu.Unlock()
}
return scanned, err
}

neoGeoMVS = platforms.Launcher{
ID: systemdefs.SystemNeoGeoMVS,
SystemID: systemdefs.SystemNeoGeoMVS,
Folders: []string{"NEOGEO"},
Extensions: []string{".neo", ".zip"},
Test: func(_ *config.Instance, path string) bool {
return filepath.Ext(path) == ""
},
SkipFilesystemScan: true,
Launch: launchNeoGeoMVS(platform),
Scanner: func(
ctx context.Context,
cfg *config.Instance,
_ string,
_ []platforms.ScanResult,
) ([]platforms.ScanResult, error) {
mu.Lock()
wasLoaded := loaded
results := append([]platforms.ScanResult(nil), cached...)
mu.Unlock()
if wasLoaded {
return results, nil
}
return baseScanner(ctx, cfg, systemdefs.SystemNeoGeo, nil)
},
}
return updatedNeoGeo, neoGeoMVS
}

func launchNeoGeoMVS(platform *Platform) func(
*config.Instance, string, *platforms.LaunchOptions,
) (*os.Process, error) {
baseLaunch := launch(platform, systemdefs.SystemNeoGeo)
return func(cfg *config.Instance, path string, opts *platforms.LaunchOptions) (*os.Process, error) {
launchOpts := platforms.LaunchOptions{}
if opts != nil {
launchOpts = *opts
}
if launchOpts.SetName == "" {
launchOpts.SetName = systemdefs.SystemNeoGeoMVS
}
if launchOpts.SetNameSameDir == "" {
launchOpts.SetNameSameDir = "true"
}
return baseLaunch(cfg, path, &launchOpts)
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Add direct NeoGeo MVS scanner coverage.

No supplied test exercises the new split scanner/cache behavior. Add a unit test with a stub base scanner that verifies the NeoGeo scan populates the cache and the MVS scanner returns the same entries without rescanning.

As per coding guidelines, “Write tests for all new code.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/platforms/mister/arcade_systems.go` around lines 175 - 247, Add unit-test
coverage for addNeoGeoMVSLauncher using a stub base Scanner: invoke the updated
NeoGeo scanner to populate the cache, then invoke the NeoGeoMVS Scanner and
verify it returns the same entries without calling the stub again. Also verify
the expected scanner results and errors while exercising the shared cache
behavior.

Source: Coding guidelines

Comment thread pkg/zapscript/launch_test.go
@codecov

codecov Bot commented Jul 13, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 85.40773% with 34 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
pkg/platforms/mister/arcade_systems.go 86.58% 13 Missing and 9 partials ⚠️
pkg/zapscript/launch.go 80.95% 9 Missing and 3 partials ⚠️

📢 Thoughts on this report? Let us know!

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
pkg/platforms/mister/arcade_systems_test.go (2)

18-34: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

CPS-3 gap resolved; consider covering remaining granular systems too.

The previously flagged missing CPS-3 case is now covered. Since the PR extends classification to Sega, Taito, Namco, Irem, and Jaleco systems as well, consider adding at least one entry per remaining misterArcadeSystemSpecs platform group to this table so a typo in any curated platform name (not just CPS/PGM) would be caught.

♻️ Example extension
 		{Setname: "CPS1GAME", Platform: "Capcom CPS-1"},
 		{Setname: "cps15game", Platform: "Capcom CPS-1.5"},
 		{Setname: "CPS3GAME", Platform: "Capcom CPS-3"},
 		{Setname: "pgmgame", Platform: "IGS PGM"},
+		{Setname: "segasystem16game", Platform: "Sega System 16"},
+		{Setname: "taitof2game", Platform: "Taito F2"},
+		{Setname: "namcosystem1game", Platform: "Namco System 1"},
+		{Setname: "iremm72game", Platform: "Irem M72"},
+		{Setname: "jalecomegasystem1game", Platform: "Jaleco Mega System 1"},
 		{Setname: "unknown", Platform: "Unique hardware"},

(Adjust platform strings to match the actual curated values in misterArcadeSystemSpecs.)

As per coding guidelines, "Write tests for all new code."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/platforms/mister/arcade_systems_test.go` around lines 18 - 34, Extend
TestArcadeSetSystemsMapsCuratedPlatforms with representative entries and
assertions for each remaining platform group defined in misterArcadeSystemSpecs,
including Sega, Taito, Namco, Irem, and Jaleco. Use the exact curated platform
strings and expected systemdefs values, and retain the existing CPS/PGM and
unknown-platform coverage.

Source: Coding guidelines


66-111: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Cache sharing is only tested in one call order (NeoGeo before MVS).

Per addNeoGeoMVSLauncher (arcade_systems.go:204-258), only updatedNeoGeo.Scanner populates cached/loaded; neoGeoMVS.Scanner reads the cache but, when not yet loaded, calls baseScanner directly without populating it. This test only exercises updated.Scanner first then mvs.Scanner, so it can't catch the reverse order (MVS scanned before NeoGeo), where the cache would never be shared and every MVS scan would redundantly re-invoke baseScanner.

Consider adding a subtest that calls mvs.Scanner first, then updated.Scanner, to confirm whether the "shared cache" contract holds regardless of call order — or confirm elsewhere that random/search resolution always scans the base NeoGeo system before NeoGeoMVS.

🧪 Suggested additional subtest
t.Run("mvs scanned before neogeo does not share cache", func(t *testing.T) {
    t.Parallel()

    expected := []platforms.ScanResult{{Path: "mslug.neo", Name: "Metal Slug"}}
    calls := 0
    neoGeo := platforms.Launcher{Scanner: func(
        context.Context, *config.Instance, string, []platforms.ScanResult,
    ) ([]platforms.ScanResult, error) {
        calls++
        return expected, nil
    }}

    _, mvs := addNeoGeoMVSLauncher(NewPlatform(), &neoGeo)
    _, err := mvs.Scanner(context.Background(), &config.Instance{}, systemdefs.SystemNeoGeoMVS, nil)
    require.NoError(t, err)
    _, err = mvs.Scanner(context.Background(), &config.Instance{}, systemdefs.SystemNeoGeoMVS, nil)
    require.NoError(t, err)
    // Documents current behavior: cache is never populated from the MVS side alone.
    assert.Equal(t, 2, calls)
})
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/platforms/mister/arcade_systems_test.go` around lines 66 - 111, Add a
reverse-order subtest to TestAddNeoGeoMVSLauncherSharesScannerCache that invokes
mvs.Scanner before updated.Scanner, then repeats the MVS scan and verifies the
intended cache-sharing behavior and base scanner call count. If the contract
requires sharing regardless of order, update addNeoGeoMVSLauncher so the MVS
scanner populates the shared cache; otherwise document and assert the current
non-sharing behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@pkg/platforms/mister/arcade_systems_test.go`:
- Around line 18-34: Extend TestArcadeSetSystemsMapsCuratedPlatforms with
representative entries and assertions for each remaining platform group defined
in misterArcadeSystemSpecs, including Sega, Taito, Namco, Irem, and Jaleco. Use
the exact curated platform strings and expected systemdefs values, and retain
the existing CPS/PGM and unknown-platform coverage.
- Around line 66-111: Add a reverse-order subtest to
TestAddNeoGeoMVSLauncherSharesScannerCache that invokes mvs.Scanner before
updated.Scanner, then repeats the MVS scan and verifies the intended
cache-sharing behavior and base scanner call count. If the contract requires
sharing regardless of order, update addNeoGeoMVSLauncher so the MVS scanner
populates the shared cache; otherwise document and assert the current
non-sharing behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 644f85b0-265f-4970-a970-37dd5d6881c6

📥 Commits

Reviewing files that changed from the base of the PR and between bafad5d and 50956e4.

📒 Files selected for processing (3)
  • pkg/platforms/mister/arcade_systems.go
  • pkg/platforms/mister/arcade_systems_test.go
  • pkg/zapscript/launch_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • pkg/platforms/mister/arcade_systems.go

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
pkg/platforms/mister/arcade_systems_test.go (1)

246-268: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Exercise the base Arcade scanner behavior.

The test verifies launcher configuration but does not prove that the base Arcade launcher still returns all classified and unclassified results. Add a mixed-input scan assertion to protect the “complete arcade indexing” requirement.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/platforms/mister/arcade_systems_test.go` around lines 246 - 268, Extend
TestArcadeSystemLaunchersPreserveArcadeAndAddGranularSystems to invoke the base
Arcade launcher’s Scanner with mixed classified and unclassified arcade inputs,
then assert that all results are returned. Preserve the existing launcher
configuration checks and use the scanner behavior exposed by the arcade launcher
rather than testing only metadata.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pkg/platforms/mister/arcade_systems_test.go`:
- Around line 76-84: Create a separate copy of input before calling
cache.captureScanner, then compare unchanged against that pre-call copy instead
of the original slice. Keep the existing captureScanner invocation and error
assertion unchanged.

---

Nitpick comments:
In `@pkg/platforms/mister/arcade_systems_test.go`:
- Around line 246-268: Extend
TestArcadeSystemLaunchersPreserveArcadeAndAddGranularSystems to invoke the base
Arcade launcher’s Scanner with mixed classified and unclassified arcade inputs,
then assert that all results are returned. Preserve the existing launcher
configuration checks and use the scanner behavior exposed by the arcade launcher
rather than testing only metadata.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 17608211-5460-48ea-a682-9dbb51ef8412

📥 Commits

Reviewing files that changed from the base of the PR and between 50956e4 and 6f83d2c.

📒 Files selected for processing (3)
  • pkg/platforms/mister/arcade_systems.go
  • pkg/platforms/mister/arcade_systems_test.go
  • pkg/zapscript/launch_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • pkg/platforms/mister/arcade_systems.go

Comment thread pkg/platforms/mister/arcade_systems_test.go Outdated
@wizzomafizzo wizzomafizzo merged commit 6c4c22d into main Jul 13, 2026
15 checks passed
@wizzomafizzo wizzomafizzo deleted the feat/1050-mister-arcade-systems branch July 13, 2026 07: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.

Clarify if specific arcade systems are considered "systems" or "arcade games" for random game…

1 participant