Skip to content

fix(ra): let a failed disc hash explain itself in the log - #415

Merged
androosio merged 1 commit into
mainfrom
fix/ra-disc-hash-logging
Aug 23, 2026
Merged

fix(ra): let a failed disc hash explain itself in the log#415
androosio merged 1 commit into
mainfrom
fix/ra-disc-hash-logging

Conversation

@androosio

Copy link
Copy Markdown
Collaborator

Description

A user reported that no PlayStation 2 disc in their library matched RetroAchievements and sent an app.log. The only trace of the problem in it was the pass's own summary:

RA re-match (hashMissing): 50 candidate ROMs
RA re-match finished: 50 processed, 38 hashed, 28 matched, 12 skipped

Everything explaining those 12 was lost. Hashing runs under compute(), and a spawned isolate gets its own copy of the LoggerService singleton which never runs init() — so its output is ConsoleOutput alone. CHD: could not open, RA disc: no usable track, RA disc: could not locate primary executable all went to logcat, which a user does not have. The isolate cannot simply open the log file too: two isolates holding a FileOutput on one path interleave writes and race the rotation rename, which is exactly why the secondary display's engine deliberately skips init().

So the isolate hands its lines back instead. LoggerService gains a per-isolate capture (startCapture / takeCapture / replayCaptured), _generateHashForSystemIsolate returns what it collected alongside the hash, and the main isolate replays it into the file-backed logger. Replaying goes through log() like any other line, so RedactingPrinter still strips credentials before anything is written. A capture is capped at 64 lines — it exists to explain a single failure, and an unbounded list in a background isolate is a leak waiting for a pathological image.

The skip count now says why, per run and across the library:

RA re-match finished: 50 processed, 38 hashed, 28 matched, 12 skipped (error 12)
RA re-match: 12 ROM(s) parked (error 12)

The second line is what finally gives getRaHashSkipCounts() a caller, and it earns its place: a pass over a settled library walks none of the parked ROMs, so on the run where a user notices the gap the per-run line reads as a clean sweep.

No behaviour changes — this only makes an existing failure legible. The underlying PS2 report is still open and gets its own PR once a log names the cause.

Steps to Verify

Preconditions: any platform, a library with at least one disc-based system, RetroAchievements signed in.

  1. Put a file the disc reader cannot open where a PS2/PSX ROM would go — a .chd of zeroes is enough (head -c 8192 /dev/zero > "Broken (USA).chd").
  2. Scan so it is picked up, then run the RetroAchievements match pass (Tools → re-match, or launch with match-on-startup enabled).
  3. Open app.log in the user-data folder.
  4. Before this change the file holds only the ... N skipped summary. After it, the two warnings that used to reach logcat only are in the file:
    [W]  CHD: ChdException(open): .../Broken (USA).chd
    [W]  RA disc: could not open .../Broken (USA).chd
    
  5. The summary line now carries a reason breakdown, followed by the library-wide parked count.

Tested on

  • Android — device:
  • Linux — device: CachyOS desktop (flutter test, plus a real failing container through RaDiscHash.compute)
  • Windows
  • macOS
  • Not runtime-tested — why: Android not yet exercised. The capture is platform-independent (it sits in LoggerService.log, above every I/O path), and the isolate boundary it crosses is the same on every platform, so the risk of a device-only difference here is low. Happy to smoke it on the Thor before merge if preferred.

Checklist

  • dart format . — no diff
  • flutter analyze — clean (no errors or warnings)
  • flutter test — all passing (1423)
  • Tests added or updated — test/logger_isolate_capture_test.dart, 8 cases: per-level tagging, the error object, the 64-line cap, take-clears-capture, replay round-trip, malformed lines, and an unknown tag from a newer build
  • No secrets, credentials, or personal data in the diff (including tests and fixtures)
  • New assets have compatible licenses — n/a

A user reporting that no PlayStation 2 disc in their library matched sent
an app.log whose only trace of the problem was the pass's own summary:

  RA re-match finished: 50 processed, 38 hashed, 28 matched, 12 skipped

Every diagnostic behind that count was lost. Hashing runs under compute(),
and a spawned isolate gets its own copy of the LoggerService singleton
which never runs init() — so its output is ConsoleOutput alone. "CHD:
could not open", "RA disc: no usable track", "RA disc: could not locate
primary executable": all of it went to logcat, which a user does not have.
It cannot simply open the file too, because two isolates holding a
FileOutput on one path interleave writes and race the rotation rename.

So the isolate hands its lines back instead. LoggerService gains a
per-isolate capture — startCapture/takeCapture/replayCaptured — the hash
isolate returns what it collected alongside the hash, and the main isolate
replays it into the file-backed logger. Replaying goes through log() like
any other line, so RedactingPrinter still strips credentials. A capture is
capped at 64 lines: it exists to explain one failure, and an unbounded
list in a background isolate is a leak waiting for a pathological image.

The skip count now says why, per run and across the library:

  RA re-match finished: 50 processed, 38 hashed, 28 matched, 12 skipped (error 12)
  RA re-match: 12 ROM(s) parked (error 12)

The second line is what finally gives getRaHashSkipCounts() a caller, and
it matters because a pass over a settled library walks none of the parked
ROMs — so on the run where a user notices the gap, the per-run line reads
as a clean sweep.

Verified against a container the reader cannot open: the two warnings that
used to vanish now reach the log.

AI-Assisted: Claude:Opus-5

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@github-project-automation github-project-automation Bot moved this to Backlog in NeoStation Aug 23, 2026
@androosio androosio added the bug Something isn't working label Aug 23, 2026
@androosio
androosio merged commit 3a89b1a into main Aug 23, 2026
2 checks passed
@github-project-automation github-project-automation Bot moved this from Backlog to Done in NeoStation Aug 23, 2026
@androosio
androosio deleted the fix/ra-disc-hash-logging branch August 23, 2026 14:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working RetroAchievements

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant