Repository navigation
Core: identify ROMs for Spruce's game menu in a Cheevos helper - #25
Merged
Merged
Conversation
Spruce's "View achievement progress" identified unknown ROMs through an identify-rom command added to its bundled RAOfflineProxy. A Spruce OTA then mixed proxy versions and the proxy failed to import, and proxy updates replace its directory, erasing the command. Cheevos now owns the helper and leaves the installed proxy unmodified. - Ship identify-rom.sh: it sources Spruce's appEnv.sh and runs the headless cheevos.platform.identify_rom (no PyUI, SDL, screens, sync or proxy service), which prints one JSON result: matched, no_match or an error with a stable reason. config.json advertises it with "gameProgress": 2. - Answer saved path associations (rom-identifications.json, versions 1 and 2) without loading hashing, SQLite or network code. - Hash with the installed proxy's rom_hashing wrapper only, through an adapter that turns a missing or incompatible proxy into a "dependency" error and writes no bytecode into the proxy's package. Repeat the proxy's ZIP and 7z rules; stream single-ROM ZIPs to SD in 64 KB chunks and remove them on SIGTERM. - Look hashes up in the proxy's cache read-only, then with RA's credential-free r=gameid. Only an explicit zero is a miss; errors are never saved. Decode RA's virtual IDs for untested or incompatible hashes to the game's own ID. - Add scripts/check_proxy_compat.py (make proxy, make proxy-check): it checks a proxy bundle or checkout with the proxy's real modules (the adapter's API and imports, parity with rom_browser's archive rules on a simulated hasher, the cache schema) and the bundled libraries' ELF exports. CI checks the pinned bundle (proxy-tested-commit); the weekly drift job checks Spruce's latest. - Move default_user_agent to the transport, so the helper doesn't load the RA client. - Document the helper, its storage, device timings and the proxy-bump check. Tested on Miyoo Mini+ (SpruceOS 4.5.5, RAOfflineProxy 2.2.0-alpha1 nightly 54, unmodified).
This was referenced Oct 18, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Spruce's View achievement progress (spruceUI/spruceOS#1885) identified unknown ROMs through an
identify-romcommand added to Spruce's bundled RAOfflineProxy. That ownership broke twice:rom_browser.pyimported a helper the newernetwork.pyno longer had, so the proxy couldn't start or stop, and RetroArch stayed pointed at127.0.0.1:8099.Cheevos now owns identification, and the installed proxy is never modified.
What changed
Helper.
App/Cheevos/identify-rom.sh --path ROM --work-dir DIR --jsonsources Spruce'sappEnv.shand runspython -m cheevos.platform.identify_rom. It's headless: no PyUI, SDL, screens, sync or proxy service code. It prints one JSON object:{"status":"matched","game_id":1479} {"status":"no_match"} {"status":"error","reason":"offline"}Error reasons:
auth,offline,network,rate_limited,response,file,hash,dependency,unavailable. The exit status is 0 for a match or miss, 1 for an error.config.jsonadvertises the helper with"gameProgress": 2.Lookup order
Saves/cheevos/cache/rom-identifications.json(versions 1 and 2, 256 entries and 256 KB at most, atomic writes, misses expire after 7 days). Answered without loading hashing, SQLite or network code.rom_hashingwrapper is used, throughplatform/proxy_hasher.py. A missing or broken proxy is adependencyerror. The proxy's ZIP and 7z rules are repeated incore/identification/candidates.py. Single-ROM ZIPs stream to SD in 64 KB chunks and are removed afterwards, including on SIGTERM.mode=ro).r=gameid. RA answers it without credentials (RAWeb'sGetGameIdFromHashActionisn't authenticated, and rcheevos sends none), so no token, password or Web API key is read.{"Success":true,"GameID":0}is a miss; errors are never saved.The helper writes nothing to the proxy: no database writes, and no
__pycache__in its package.Compatibility check.
scripts/check_proxy_compat.py(make proxy,make proxy-check [PROXY=…]) checks a Spruce bundle or an upstream checkout using the proxy's real modules:rom_browser.hash_candidates_for_manual_cache, for 14 fixtures on a simulated native hasher;Storagewrites;libraproxy_rchash.so, which is never loaded off the device.It records the proxy's version and source commit. CI checks the pinned bundle (
proxy-tested-commit, nightly 54). The weekly drift job checks Spruce's latest Development.Also changed
default_user_agentmoved to the transport, so the helper doesn't load the RA client.Testing
make checkpasses (1,055 tests). The unit tests cover:ImportError;The device test ran on a Miyoo Mini+ with SpruceOS 4.5.5 and an unmodified RAOfflineProxy 2.2.0-alpha1 nightly 54, with the companion Spruce change installed:
.isothe proxy can't hashno_match/ Spruce's "hash" message, no launchoffline, not saved; a hash in the proxy's cache still matcheslogin2through it succeedsImportError)dependency; the real proxy keeps runningThe helper's RSS stays at 15 MB or less. MemAvailable stayed at 13 MB or more with PyUI, the proxy and the helper resident.
Not covered on the device: Spruce's own path mapping. The proxy there had no games cached from its menu, so the mapping was empty. That path was checked on a desktop against this helper.
Notes
gameProgress1), the new Spruce code hides the action.