Skip to content

feat(accuracysnes): the ares host runs the battery — A2.10 is settled 3-vs-1 - #304

Merged
doublegate merged 1 commit into
mainfrom
feat/ares-host-works
Aug 1, 2026
Merged

feat(accuracysnes): the ares host runs the battery — A2.10 is settled 3-vs-1#304
doublegate merged 1 commit into
mainfrom
feat/ares-host-works

Conversation

@doublegate

@doublegate doublegate commented Aug 1, 2026

Copy link
Copy Markdown
Owner

The follow-up to #303, which established that the host builds and links. It now runs.

magic ACSN / done a5 / count 338 / passed 299 / failed 5 / skipped 1 / golden 33

Identical across two runs.

A2.10 is settled — 3 against 1, with Mesen2 the outlier

This is the point of the exercise. Several findings sat at 2-versus-1 with no tiebreaker, because this project's provenance rule counts ares and bsnes as one reference — so "RustySNES and snes9x against Mesen2" is only 2-vs-1 if ares is not already on RustySNES's side, and nobody could check.

ares passes A2.10 ("PEI does not page-wrap", catalogue index 11, status $01). With RustySNES and snes9x, that is three implementations against Mesen2. The caveat that kept this row open — a harness bug upstream of an implementation produces exactly this signature, as the $F8/$F9 retraction already cost this project once — is answered by a fourth host independent of all three.

The plan's A2.10 section is updated in place, keeping the original reasoning because it is why the row waited.

Three setup steps, all failing as the same segfault

Each cost a round, and each fails inside System::load with a backtrace pointing at memory setup rather than at what is actually missing:

  1. ares::Memory::FixedAllocator::get() before anything touches a core — Bus::reset() allocates its page tables from that bump allocator.
  2. ares::SuperFamicom::option("Pixel Accuracy", "true") before load()PPUBase::implementation is null until setAccurate picks one of the two PPUs, and Bus::reset() calls ppu.map()implementation->map(). "true" selects the accurate PPU, the only one worth cross-validating against.
  3. nall/main.hpp included by the host translation unit — without it the link fails with a bare undefined reference to 'main' from crt1.o.

ptrace is denied in this sandbox, so the host installs its own SIGSEGV handler and prints a backtrace; addr2line -Cfe resolves the frames.

Five rows ares disagrees about — recorded, not adjudicated

C7.05, C7.10, E8.02, E3.06, F1.10. The cart, snes9x and Mesen2 all pass these.

F1.10 is suspect of this host first. It is a PAD2_CONTRACT row and the port detection here (port->name().find("2") on the button's grandparent) is assumed to work, not verified.

Deliberately not wired into crossval.sh. Adding a third reference means an ARES_KNOWN_FAILURES constant, and that constant must not be written until these five are adjudicated — a known-failure count encoding unexamined disagreements is worse than no third reference at all.

Also

Results-block offsets corrected: R_COUNT is +$06, R_PASSED is +$0A. Reading the latter as the former reported "count 299" for a 338-test battery, which reads like a truncated run rather than a misread field.

Scope

scripts/accuracysnes/ares_host/ plus docs. Nothing in the emulator, the build, or any gate is touched; ref-proj/ is not modified; crossval.sh is unchanged.

🤖 Generated with Claude Code

Adds a reproducible headless Ares host for AccuracySNES.

  • The host reports 338 tests: 299 passed, 5 failed, 1 skipped, and 33 golden.
  • Ares passes A2.10, changing the dossier assertion to a 3-vs-1 result against Mesen2. The coverage denominator remains 338.
  • Ares disagrees on C7.05, C7.10, E8.02, E3.06, and F1.10. These rows remain unresolved, and F1.10 remains excluded from cross-validation.
  • The host requires allocator initialization, accurate PPU selection, and nall/main.hpp. It also corrects results-block offsets to R_COUNT = +$06 and R_PASSED = +$0A.

The claim is false if the host cannot reproduce these counts, does not pass A2.10, or requires a changed coverage denominator. The claim also fails if any of the five disagreements are treated as adjudicated or if Ares is integrated into crossval.sh without resolving the documented conditions.

… 3-vs-1

Three setup steps were missing, and all three fail as the SAME segfault inside
System::load with a backtrace pointing at memory setup rather than at what is
actually absent:

  1. ares::Memory::FixedAllocator::get() before anything touches a core --
     Bus::reset() allocates its page tables from that bump allocator;
  2. ares::SuperFamicom::option("Pixel Accuracy", "true") before load() --
     PPUBase::implementation is null until setAccurate picks one of the two
     PPUs, and Bus::reset() calls ppu.map() -> implementation->map();
  3. nall/main.hpp included by the host translation unit -- without it the
     LINK fails with a bare `undefined reference to main` from crt1.o.

It now reports magic ACSN / done a5 / count 338 / passed 299 / failed 5 /
skipped 1 / golden 33, identically across runs.

A2.10 IS SETTLED. Several findings sat at 2-versus-1 with no tiebreaker,
because this project's provenance rule counts ares and bsnes as one reference
-- so "RustySNES and snes9x against Mesen2" is only 2-vs-1 if ares is not
already on RustySNES's side, and nobody could check. ares passes A2.10
(catalogue index 11, status $01), making it 3 against 1 with Mesen2 the
outlier. The caveat that held the row open -- a harness bug upstream of an
implementation gives the same signature, as the $F8/$F9 retraction proved --
is answered by a fourth host independent of all three.

Five rows where ares disagrees with the cart (C7.05, C7.10, E8.02, E3.06,
F1.10) are recorded and deliberately NOT adjudicated. F1.10 is suspect of this
host first: it is a PAD2_CONTRACT row and the port detection here is assumed
rather than verified. Not wired into crossval.sh for that reason -- an
ARES_KNOWN_FAILURES constant encoding unexamined disagreements would be worse
than no third reference at all.

Also fixes the results-block offsets: R_COUNT is +$06 and R_PASSED is +$0A,
and reading the latter as the former reported "count 299" for a 338-test
battery, which looks like a truncated run rather than a misread field.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings August 1, 2026 10:37
@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

The headless ares host now runs the AccuracySNES battery reproducibly. It initializes required components, selects the accurate PPU, reports corrected result counts, captures crashes, and documents A2.10 validation and unresolved disagreements.

Changes

ares AccuracySNES validation

Layer / File(s) Summary
Host initialization and execution
scripts/accuracysnes/ares_host/ares_host.cpp, scripts/accuracysnes/ares_host/build.sh, scripts/accuracysnes/ares_host/README.md
The host adds signal backtraces, allocator initialization, accurate PPU selection, verbose logging, setup requirements, and debug symbols.
Result parsing and validation documentation
scripts/accuracysnes/ares_host/ares_host.cpp, scripts/accuracysnes/ares_host/README.md, docs/accuracysnes-plan.md, CHANGELOG.md
The host reads result counts from offset 0x06 and reports all result fields. Documentation records the reproducible run, A2.10 validation, five disagreements, and deferred cross-validation.
Estimated code review effort: 2 (Simple) ~10 minutes

Sequence Diagram(s)

sequenceDiagram
  participant AccuracySNES
  participant ares_host
  participant ares_allocator
  participant SuperFamicom
  AccuracySNES->>ares_host: start test battery
  ares_host->>ares_allocator: initialize fixed allocator
  ares_host->>SuperFamicom: select accurate PPU and load
  SuperFamicom-->>ares_host: execute tests and expose results
Loading

Possibly related PRs

Suggested reviewers: copilot

🚥 Pre-merge checks | ✅ 9 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Title check ⚠️ Warning The title uses a valid Conventional Commit type and scope, but its subject is declarative rather than imperative. Rewrite the subject in imperative mood, such as “feat(accuracysnes): add a working Ares battery host”.
✅ Passed checks (9 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Changelog Entry ✅ Passed The full PR diff from merge base includes a CHANGELOG.md hunk that replaces the prior entry with the working ares host and A2.10 results.
Docs-As-Spec ✅ Passed Against base 5482eb3, the PR changes no paths under crates/rustysnes-*; therefore the required crate behavior/specification condition is not applicable.
Accuracysnes Bookkeeping ✅ Passed The base-to-PR diff changes only five changelog, documentation, and ares-host files; it adds or removes no test or scene under tests/roms/AccuracySNES/gen/src/.
No Panic On Untrusted Input ✅ Passed The diff adds no .unwrap(), .expect(), or panic!() calls. The ROM path is handled by checked load() status results, and other input parsing has no listed panic.
Safety Comment On New Unsafe ✅ Passed The PR changes only Markdown, shell, and C++ files; the added-line scan finds no new unsafe { ... } block or unsafe fn, so no SAFETY comment is required.

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

@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown

Antigravity review (Gemini via Ultra)

This PR updates the C++ headless ares test host (ares_host.cpp, build.sh, README, CHANGELOG, and accuracy plan) to resolve startup crash conditions, add debugging stack traces, parse test battery result fields from WRAM, and document that ares passes AccuracySNES test A2.10.

Blocking issues

None found.

Suggestions

  • scripts/accuracysnes/ares_host/ares_host.cpp#L22-L28: fprintf is not async-signal-safe. Calling stdio functions inside SIGSEGV/SIGABRT handlers can deadlock or fail if the crash occurred within stdio memory allocation or stream locking. Use write(STDERR_FILENO, ...) for signal-safe diagnostics.
  • scripts/accuracysnes/ares_host/ares_host.cpp#L97-L103: arguments[0] and arguments[1] are evaluated before calling arguments.take("--verbose"). If a user invokes ares_host --verbose <rom.sfc> <frames>, arguments[0] resolves to "--verbose", causing positional parsing to fail. Call take() and validate argument count prior to indexing positional elements.
  • scripts/accuracysnes/ares_host/ares_host.cpp#L156-L173: Results parsing reads count and status bytes directly without verifying that the ACSN magic signature (wram[RESULTS..RESULTS+3]) was actually written. If a cart fails during early execution before reaching the test output routine, uninitialized WRAM values will be emitted as valid test results. Validate the magic signature bytes before printing status output.

Nitpicks

  • PR title is 74 characters, violating the project style guide constraint of 72 characters or shorter for commit subjects.
  • scripts/accuracysnes/ares_host/ares_host.cpp#L162: Lambda rd16 uses implicit reference capture [&]; explicit parameter pass or value capture is clearer.

Automated first-pass review by agy on a self-hosted runner -- not a human review.

Copilot AI 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.

Pull request overview

Adds a working headless ares host for running the AccuracySNES battery (providing a third reference implementation), and updates project docs to record that A2.10 is now settled as a 3-vs-1 (with Mesen2 as the outlier).

Changes:

  • Make the ares host runnable in-sandbox by adding an internal crash backtrace handler and required setup steps; extend results-block reporting (count/passed/failed/skipped/golden).
  • Fix results-block field offsets used by the host output.
  • Update accuracysnes-plan.md and CHANGELOG.md to reflect the new ares-based arbitration outcome for A2.10.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
scripts/accuracysnes/ares_host/README.md Updates documentation to reflect the host now runs and records newly observed ares disagreements.
scripts/accuracysnes/ares_host/build.sh Builds the ares host with debug symbols/backtrace support.
scripts/accuracysnes/ares_host/ares_host.cpp Adds in-process crash backtraces, a --verbose mode, and corrected results-block parsing/printing.
docs/accuracysnes-plan.md Records A2.10 as settled by adding ares as a third opinion.
CHANGELOG.md Summarizes the ares host milestone and the A2.10 arbitration outcome.

Comment on lines +44 to +46
**Treat `F1.10` as suspect-of-this-host first.** It is a `PAD2_CONTRACT` row, and this host's port
detection (`port->name().find("2")` on the button's grandparent) is *assumed* to work, not verified.
Check that before concluding anything about ares.
# link fails with a bare `undefined reference to 'main'` from crt1.o, which reads like a missing
# object rather than a missing shim.
g++ -std=c++2b -O2 -c "$HERE/ares_host.cpp" -o "$BUILD/ares_host.o" \
g++ -std=c++2b -O2 -g -rdynamic -c "$HERE/ares_host.cpp" -o "$BUILD/ares_host.o" \

@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 `@scripts/accuracysnes/ares_host/ares_host.cpp`:
- Around line 22-27: Update crashHandler to use only async-signal-safe
operations in the signal path: remove fprintf, backtrace, and
backtrace_symbols_fd, and emit only a fixed diagnostic via write before
preserving _exit(9). If backtrace symbolization is required, move it to a parent
process or post-mortem tool and verify the implementation against the target
POSIX/libc signal-safety contract.
- Around line 156-171: Validate the WRAM result block before emitting any output
in the results-reporting flow: confirm the magic is “ACSN”, version is 1, done
is 0xA5, and the count read via rd16 at offset 0x06 is within 1..512; return or
otherwise reject invalid blocks before printing any result fields. Also update
the status-processing bound to handle all entries up to the validated count
without silently truncating counts above 512.
- Around line 100-102: Move the positional-argument arity validation to after
`arguments.take("--verbose")` in the argument parsing flow, before accessing
`arguments[0]` or `arguments[1]`. Ensure the check uses the post-option-removal
count and rejects invocations missing either the ROM or budget argument.

In `@scripts/accuracysnes/ares_host/README.md`:
- Around line 5-18: Add language identifiers to both changed Markdown fences:
update the fence in scripts/accuracysnes/ares_host/README.md lines 5-18 and the
fence in CHANGELOG.md lines 19-21 to use text or console, preserving their
existing contents.
- Around line 52-66: Update scripts/accuracysnes/ares_host/README.md lines 52-66
to separate the allocator and PPU omissions, which cause System::load
segmentation faults, from the nall/main.hpp omission, which causes a link-time
undefined reference to main. Apply the same corrected separation to CHANGELOG.md
lines 33-39; both documentation sites must describe the implementation and build
behavior accurately.
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 6571b6cd-1e12-4303-bb37-4bc9977c0b8b

📥 Commits

Reviewing files that changed from the base of the PR and between 5482eb3 and 07df04c.

📒 Files selected for processing (5)
  • CHANGELOG.md
  • docs/accuracysnes-plan.md
  • scripts/accuracysnes/ares_host/README.md
  • scripts/accuracysnes/ares_host/ares_host.cpp
  • scripts/accuracysnes/ares_host/build.sh
📜 Review details
⏰ Context from checks skipped due to timeout. (6)
  • GitHub Check: test-light
  • GitHub Check: accuracysnes
  • GitHub Check: lint
  • GitHub Check: copilot-pull-request-reviewer
  • GitHub Check: build demo + docs
  • GitHub Check: review
🧰 Additional context used
📓 Path-based instructions (8)
**/*

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*: Do not commit or vendor the generated snesdev_wiki/ mirror; it is gitignored and intended only as a local reference.
Keep commits focused and use Conventional Commits: <type>(<scope>): <subject>, with an imperative subject of at most 72 characters.
Do not use emojis in code, comments, or commit messages.
Before opening a PR, ensure formatting, Clippy, workspace tests, the core embedded build, rustdoc with warnings denied, documentation coverage, and changelog requirements pass.
Ticket completion must be reflected in the relevant to-dos/ sprint file.

**/*: Preserve the one-directional crate graph: chip crates must not depend on one another; rustysnes-core ties them together.
Never commit commercial ROMs; only commit derived screenshots and hashes.
Keep docs/STATUS.md as the authoritative per-subsystem status and update project documentation in the same PR as code changes.
Do not treat RustyNES v2.0 or engine-lineage anchors as project releases.

Files:

  • scripts/accuracysnes/ares_host/build.sh
  • docs/accuracysnes-plan.md
  • scripts/accuracysnes/ares_host/README.md
  • CHANGELOG.md
  • scripts/accuracysnes/ares_host/ares_host.cpp
scripts/accuracysnes/**

⚙️ CodeRabbit configuration file

scripts/accuracysnes/**: The cross-validation harness: the same AccuracySNES image is run on snes9x (through a
libretro host in C) and on Mesen2 (through its test runner and a Lua script), and their
verdicts are compared with the cart's. Its integrity is the whole argument for the
battery, so flag anything that could make a reference appear to agree — a verdict parsed
loosely, a missing-file path that degrades to success, a scene comparison that skips
rather than fails when the golden is absent. A known reference divergence belongs in
SNES9X_KNOWN_FAILURES with a source citation, never in a widened match.

Files:

  • scripts/accuracysnes/ares_host/build.sh
  • scripts/accuracysnes/ares_host/README.md
  • scripts/accuracysnes/ares_host/ares_host.cpp
docs/**/*.md

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Before changing a subsystem, consult docs/architecture.md, docs/STATUS.md, CONTRIBUTING.md, the relevant subsystem documentation, and applicable ADRs.

New subsystems must add documentation under docs/.

Files:

  • docs/accuracysnes-plan.md
**/*.{rs,md}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Chip-behavior changes must update both the chip implementation and the corresponding docs/<subsystem>.md documentation.

A chip change must update both the chip implementation and its corresponding docs/<chip>.md documentation in the same change.

Files:

  • docs/accuracysnes-plan.md
  • scripts/accuracysnes/ares_host/README.md
  • CHANGELOG.md
docs/**/*

📄 CodeRabbit inference engine (docs/testing-strategy.md)

Chip crates should exceed 90% unit-test coverage, and each chip should be fuzzable in isolation.

Files:

  • docs/accuracysnes-plan.md
docs/**

⚙️ CodeRabbit configuration file

docs/**: Docs are the spec, not a history log. Flag claims that contradict the code, counts that
contradict the generated docs/accuracysnes-coverage.md, and any statement of coverage that
is broader than what the corresponding test actually asserts.

Files:

  • docs/accuracysnes-plan.md
**/*.md

⚙️ CodeRabbit configuration file

**/*.md: Docs are the spec, not a changelog. Flag prose that has drifted from the code it describes
rather than style nits. The markdownlint gate is pinned to v0.39.0 via pre-commit —
do not report rules that version does not have (MD060 in particular).

Files:

  • docs/accuracysnes-plan.md
  • scripts/accuracysnes/ares_host/README.md
  • CHANGELOG.md
CHANGELOG.md

📄 CodeRabbit inference engine (CONTRIBUTING.md)

User-visible changes must be recorded under the [Unreleased] section.

For the full pull request diff against its base branch, modify CHANGELOG.md when user-visible behavior changes, including emulator output, frontend features, CLI flags, public APIs, or AccuracySNES cartridge contents. Do not require it for purely internal changes, tests, comments, or CI configuration.

Files:

  • CHANGELOG.md
🧠 Learnings (2)
📚 Learning: 2026-07-21T01:34:22.909Z
Learnt from: doublegate
Repo: doublegate/RustySNES PR: 189
File: docs/accuracysnes-plan.md:0-0
Timestamp: 2026-07-21T01:34:22.909Z
Learning: When reviewing the AccuracySNES documentation in docs/accuracysnes-*.md (notably docs/accuracysnes-plan.md vs the generated docs/accuracysnes-coverage.md), treat the reported metrics as intentionally non-equivalent: the battery test count and dossier assertion coverage are not interchangeable. Do not infer one count/coverage from the other during review (e.g., one test may contain multiple assertions, and multiple tests may contribute to a single assertion/row such as E6.02).

Applied to files:

  • docs/accuracysnes-plan.md
📚 Learning: 2026-07-21T05:22:58.848Z
Learnt from: doublegate
Repo: doublegate/RustySNES PR: 197
File: docs/accuracysnes-plan.md:598-600
Timestamp: 2026-07-21T05:22:58.848Z
Learning: In the AccuracySNES documentation under `docs/`, when an assertion exists in the research dossier but cannot be measured/verified by the current cartridge timing test, distinguish the dossier assertion from test measurability: keep the original hardware assertion (and any contribution to the coverage denominator) intact, withdraw/stop using the specific test coverage only if the sources cannot decompose the required CPU-cycle timing into bus vs internal components, and mark the row as not measurable using the `[NOT CART-MEASURABLE ...]` annotation with links to the corresponding plan section (e.g., `docs/accuracysnes-plan.md` §A5.20) and the related roadmap/ticket (e.g., `to-dos/ROADMAP.md` ticket `T-06-A`). Ensure the documentation/coverage reporting treats the row as uncovered rather than removing or redefining the assertion.

Applied to files:

  • docs/accuracysnes-plan.md
🪛 Clang (14.0.6)
scripts/accuracysnes/ares_host/ares_host.cpp

[warning] 23-23: do not declare C-style arrays, use std::array<> instead

(modernize-avoid-c-arrays)


[warning] 24-24: variable name 'n' is too short, expected at least 3 characters

(readability-identifier-length)


[warning] 25-25: do not call c-style vararg functions

(cppcoreguidelines-pro-type-vararg)


[warning] 101-101: variable 'rom' is not initialized

(cppcoreguidelines-init-variables)


[warning] 102-102: variable 'budget' is not initialized

(cppcoreguidelines-init-variables)


[warning] 125-125: statement should be inside braces

(readability-braces-around-statements)


[warning] 125-125: do not call c-style vararg functions

(cppcoreguidelines-pro-type-vararg)


[warning] 134-134: variable 'root' is not initialized

(cppcoreguidelines-init-variables)


[warning] 136-136: do not call c-style vararg functions

(cppcoreguidelines-pro-type-vararg)


[warning] 139-139: statement should be inside braces

(readability-braces-around-statements)


[warning] 139-139: do not call c-style vararg functions

(cppcoreguidelines-pro-type-vararg)


[warning] 150-150: statement should be inside braces

(readability-braces-around-statements)


[warning] 150-150: do not call c-style vararg functions

(cppcoreguidelines-pro-type-vararg)


[warning] 153-153: statement should be inside braces

(readability-braces-around-statements)


[warning] 153-153: do not call c-style vararg functions

(cppcoreguidelines-pro-type-vararg)


[warning] 154-154: statement should be inside braces

(readability-braces-around-statements)


[warning] 158-158: variable 'RESULTS' is not initialized

(cppcoreguidelines-init-variables)


[warning] 163-163: variable 'count' is not initialized

(cppcoreguidelines-init-variables)


[warning] 164-164: do not call c-style vararg functions

(cppcoreguidelines-pro-type-vararg)

🪛 markdownlint-cli2 (0.23.1)
scripts/accuracysnes/ares_host/README.md

[warning] 5-5: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

CHANGELOG.md

[warning] 19-19: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🪛 Shellcheck (0.11.0)
scripts/accuracysnes/ares_host/build.sh

[warning] 34-34: Quote this to prevent word splitting.

(SC2046)

🔇 Additional comments (12)
scripts/accuracysnes/ares_host/ares_host.cpp (3)

104-110: LGTM!


125-139: LGTM!


150-153: LGTM!

scripts/accuracysnes/ares_host/build.sh (1)

31-38: LGTM!

scripts/accuracysnes/ares_host/README.md (4)

1-4: LGTM!


20-51: LGTM!


68-79: LGTM!


80-84: LGTM!

docs/accuracysnes-plan.md (2)

846-846: LGTM!


858-864: LGTM!

CHANGELOG.md (2)

14-18: LGTM!


22-32: LGTM!

Comment on lines +22 to +27
auto crashHandler(int sig) -> void {
void* frames[40];
int n = backtrace(frames, 40);
fprintf(stderr, "\nares_host: signal %d — backtrace follows\n", sig);
backtrace_symbols_fd(frames, n, 2);
_exit(9);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🔵 Trivial | 🏗️ Heavy lift

Keep crashHandler safe in signal context.

crashHandler calls fprintf, backtrace, and backtrace_symbols_fd after SIGSEGV or SIGABRT. These calls are not guaranteed to be async-signal-safe. If the fault interrupts allocator, loader, or stdio code while a lock is held, the handler can hang or fault again instead of exiting with status 9.

Keep the handler limited to a fixed write and _exit path, or move symbolization to a parent process or post-mortem tool. Verify the design against the target POSIX and libc signal-safety contract.

🧰 Tools
🪛 Clang (14.0.6)

[warning] 23-23: do not declare C-style arrays, use std::array<> instead

(modernize-avoid-c-arrays)


[warning] 24-24: variable name 'n' is too short, expected at least 3 characters

(readability-identifier-length)


[warning] 25-25: do not call c-style vararg functions

(cppcoreguidelines-pro-type-vararg)

🤖 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 `@scripts/accuracysnes/ares_host/ares_host.cpp` around lines 22 - 27, Update
crashHandler to use only async-signal-safe operations in the signal path: remove
fprintf, backtrace, and backtrace_symbols_fd, and emit only a fixed diagnostic
via write before preserving _exit(9). If backtrace symbolization is required,
move it to a parent process or post-mortem tool and verify the implementation
against the target POSIX/libc signal-safety contract.

Comment on lines +100 to 102
bool verbose = (bool)arguments.take("--verbose");
string rom = arguments[0];
u32 budget = (u32)toNatural(arguments[1]);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -eu

printf '%s\n' '--- candidate files ---'
git ls-files 'scripts/accuracysnes/ares_host/*' | sed -n '1,120p'

printf '%s\n' '--- host source context ---'
host=$(git ls-files | grep -E '(^|/)scripts/accuracysnes/ares_host/ares_host\.cpp$' | head -n 1 || true)
if [ -n "$host" ]; then
  cat -n "$host" | sed -n '80,125p'
fi

printf '%s\n' '--- Arguments definitions and uses ---'
rg -n --glob '!snesdev_wiki/**' \
  'class Arguments|struct Arguments|Arguments::|arguments\.take|take\([^)]*--verbose|arguments\.size\(\)|operator\[\]' \
  . | sed -n '1,240p'

Repository: doublegate/RustySNES

Length of output: 2447


🏁 Script executed:

#!/bin/bash
set -eu

printf '%s\n' '--- build script ---'
cat -n scripts/accuracysnes/ares_host/build.sh

printf '%s\n' '--- source header and dependency references ---'
cat -n scripts/accuracysnes/ares_host/ares_host.cpp | sed -n '1,45p'
rg -n --glob '!snesdev_wiki/**' \
  'ares|nall|Arguments|github.com|commit|checkout|submodule' \
  scripts/accuracysnes/ares_host README.md .github 2>/dev/null | sed -n '1,240p'

Repository: doublegate/RustySNES

Length of output: 22865


🌐 Web query:

Search the ares-emulator/ares GitHub source for the nall Arguments implementation, specifically Arguments::take, Arguments::size, and Arguments::operator[]semantics innall/string/arguments.hpp or equivalent.

💡 Result:

In the ares-emulator/ares source code, the nall::Arguments class (found in nall/nall/arguments.hpp) provides a wrapper around a std::vector to manage command-line arguments [1]. The semantics for the requested methods are as follows: size The size method returns the number of arguments currently held in the internal collection as a u32 type [1]: auto size const -> u32 { return arguments.size; } [1] operator[] The subscript operator provides access to the individual argument strings at a given index. It includes both mutable and const overloads, returning a reference to the string [1]: auto operator[](u32 index) -> string& { return arguments[index]; } [1] auto operator[](u32 index) const -> const string& { return arguments[index]; } [1] take The take method is used to consume and remove specific arguments from the internal collection, which is useful for parsing command-line flags and their values [1][2]. It is overloaded to support different search patterns: 1. take -> string: Removes and returns the first element in the arguments list. 2. take(string_view name) -> bool: Searches for an argument matching the given name; if found, it removes it from the list and returns true [1]. 3. take(string_view name, bool& argument) -> bool: Searches for a flag. If found, it removes it, sets the referenced bool to true, and returns true [1]. 4. take(string_view name, string& argument) -> bool: Searches for an argument by name. If found, it removes both the name and the subsequent value from the list, assigns the value to the referenced string, and returns true [1]. These methods facilitate typical CLI patterns, such as checking for flags (e.g., arguments.take("--fullscreen")) or extracting values associated with flags (e.g., arguments.take("--system", system)) [2].

Citations:


🏁 Script executed:

#!/bin/bash
set -eu

url='https://raw.githubusercontent.com/ares-emulator/ares/6f6786e0/nall/nall/arguments.hpp'
src=$(curl --fail --silent --show-error --location "$url")

printf '%s\n' '--- relevant declarations and methods ---'
printf '%s\n' "$src" | rg -n -A14 -B5 \
  'class Arguments|auto size|auto take|operator\[\]|arguments\.remove|arguments\.size' | sed -n '1,260p'

printf '%s\n' '--- source length and commit URL ---'
printf 'lines=%s\n' "$(printf '%s\n' "$src" | wc -l)"
printf '%s\n' "$url"

Repository: doublegate/RustySNES

Length of output: 4256


🏁 Script executed:

#!/bin/bash
set -eu

python3 - <<'PY'
args = ["--verbose", "rom.sfc"]
initial_size = len(args)

try:
    verbose = "--verbose" in args
    if verbose:
        args.remove("--verbose")
    final_size = len(args)
    print(f"input=ares_host --verbose rom.sfc")
    print(f"initial_size={initial_size}")
    print(f"take_verbose={verbose}")
    print(f"remaining={args}")
    print(f"final_size={final_size}")
    print(f"arity_check_before_take={'passes' if initial_size >= 2 else 'fails'}")
    print(f"arity_check_after_take={'passes' if final_size >= 2 else 'fails'}")
    if final_size < 2:
        raise IndexError("arguments[1] is out of bounds")
except IndexError as error:
    print(f"access_result=out_of_bounds: {error}")
PY

Repository: doublegate/RustySNES

Length of output: 379


Move the arity check after option removal. With ares_host --verbose <rom>, take("--verbose") reduces the argument count from two to one, so arguments[1] performs an out-of-bounds access.

🧰 Tools
🪛 Clang (14.0.6)

[warning] 101-101: variable 'rom' is not initialized

(cppcoreguidelines-init-variables)


[warning] 102-102: variable 'budget' is not initialized

(cppcoreguidelines-init-variables)

🤖 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 `@scripts/accuracysnes/ares_host/ares_host.cpp` around lines 100 - 102, Move
the positional-argument arity validation to after `arguments.take("--verbose")`
in the argument parsing flow, before accessing `arguments[0]` or `arguments[1]`.
Ensure the check uses the post-option-removal count and rejects invocations
missing either the ROM or budget argument.

Comment on lines 156 to +171
// The results block, straight out of WRAM. $7E:F000 is WRAM offset $F000.
const auto& wram = ares::SuperFamicom::cpu.wram;
const u32 RESULTS = 0xF000;
// Offsets are `asm/runtime.inc`'s, and they are easy to get wrong by one field: R_COUNT is +$06
// and R_PASSED is +$0A. Reading the latter as the former reported "count 299" for a 338-test
// battery, which looks like a truncated run rather than a misread field.
auto rd16 = [&](u32 off) -> u32 { return wram[RESULTS + off] | (wram[RESULTS + off + 1] << 8); };
u32 count = rd16(0x06);
printf("ACCURACYSNES-BEGIN\n");
printf("magic %c%c%c%c\n", wram[RESULTS], wram[RESULTS + 1], wram[RESULTS + 2], wram[RESULTS + 3]);
printf("done %02x\n", wram[RESULTS + 0x08]);
u32 count = wram[RESULTS + 0x0A] | (wram[RESULTS + 0x0B] << 8);
printf("count %u\n", count);
printf("passed %u\n", rd16(0x0A));
printf("failed %u\n", rd16(0x0C));
printf("skipped %u\n", rd16(0x0E));
printf("golden %u\n", rd16(0x10));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -eu
printf '%s\n' '--- target outline ---'
ast-grep outline scripts/accuracysnes/ares_host/ares_host.cpp
printf '%s\n' '--- target section ---'
cat -n scripts/accuracysnes/ares_host/ares_host.cpp | sed -n '120,205p'
printf '%s\n' '--- runtime definitions and uses ---'
rg -n -C 4 'R_(COUNT|PASSED|FAILED|SKIPPED|GOLDEN|DONE)|RESULTS|ACSN|ACCURACYSNES-BEGIN|i < 512|512' scripts/accuracysnes

Repository: doublegate/RustySNES

Length of output: 18375


🏁 Script executed:

#!/bin/bash
set -eu
find scripts/accuracysnes -type f -maxdepth 4 -print | sort
printf '%s\n' '--- relevant symbols ---'
rg -n -C 5 'R_(COUNT|PASSED|FAILED|SKIPPED|GOLDEN|DONE)|RESULTS|ACSN|ACCURACYSNES-BEGIN|i < 512|512' scripts/accuracysnes

Repository: doublegate/RustySNES

Length of output: 17761


🏁 Script executed:

rg -n -C 8 'ACCURACYSNES-BEGIN|R_DONE|R_COUNT|R_PASSED|R_FAILED|R_SKIPPED|R_GOLDEN|RESULTS' .

Repository: doublegate/RustySNES

Length of output: 50378


🏁 Script executed:

#!/bin/bash
set -eu
printf '%s\n' '--- shared results layout ---'
sed -n '7,45p' tests/roms/AccuracySNES/gen/src/emit.rs
printf '%s\n' '--- runtime layout symbols ---'
rg -n -C 3 'R_MAGIC|R_VERSION|R_COUNT|R_DONE|R_PASSED|R_FAILED|R_SKIPPED|R_GOLDEN|R_STATUS|R_DONE_MARK|R_FORMAT_VERSION|_test_count' tests/roms/AccuracySNES/asm
printf '%s\n' '--- Ares host entry and return behavior ---'
cat -n scripts/accuracysnes/ares_host/ares_host.cpp | sed -n '85,180p'

Repository: doublegate/RustySNES

Length of output: 26621


Reject incomplete or malformed result blocks before reporting counts.

The host emits ACCURACYSNES-BEGIN after any fixed frame budget, even when WRAM contains no completed battery. Validate ACSN, R_VERSION == 1, R_DONE == 0xA5, and 0 < count <= 512; reject invalid blocks before printing any result fields. Otherwise, i < 512 silently drops statuses from an oversized result.

🧰 Tools
🪛 Clang (14.0.6)

[warning] 158-158: variable 'RESULTS' is not initialized

(cppcoreguidelines-init-variables)


[warning] 163-163: variable 'count' is not initialized

(cppcoreguidelines-init-variables)


[warning] 164-164: do not call c-style vararg functions

(cppcoreguidelines-pro-type-vararg)

🤖 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 `@scripts/accuracysnes/ares_host/ares_host.cpp` around lines 156 - 171,
Validate the WRAM result block before emitting any output in the
results-reporting flow: confirm the magic is “ACSN”, version is 1, done is 0xA5,
and the count read via rd16 at offset 0x06 is within 1..512; return or otherwise
reject invalid blocks before printing any result fields. Also update the
status-processing bound to handle all entries up to the validated count without
silently truncating counts above 512.

Source: Path instructions

Comment on lines +5 to +18
```
$ REF_PROJ=$PWD/ref-proj bash scripts/accuracysnes/ares_host/build.sh
$ /tmp/ares_host tests/roms/AccuracySNES/build/accuracysnes.sfc 900
ACCURACYSNES-BEGIN
magic ACSN
done a5
count 338
passed 299
failed 5
skipped 1
golden 33
status 0 01
...
```

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 language identifiers to both changed Markdown fences.

Both fences omit a language identifier and can fail the active MD040 check.

  • scripts/accuracysnes/ares_host/README.md#L5-L18: change the opening fence to ```text or ```console.
  • CHANGELOG.md#L19-L21: change the opening fence to ```text or ```console.

As per path instructions, these Markdown files must follow the pinned markdownlint rules.

🧰 Tools
🪛 markdownlint-cli2 (0.23.1)

[warning] 5-5: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

📍 Affects 2 files
  • scripts/accuracysnes/ares_host/README.md#L5-L18 (this comment)
  • CHANGELOG.md#L19-L21
🤖 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 `@scripts/accuracysnes/ares_host/README.md` around lines 5 - 18, Add language
identifiers to both changed Markdown fences: update the fence in
scripts/accuracysnes/ares_host/README.md lines 5-18 and the fence in
CHANGELOG.md lines 19-21 to use text or console, preserving their existing
contents.

Sources: Path instructions, Linters/SAST tools

Comment on lines +52 to +66
## Three setup steps that are not optional, each of which cost a debugging round

Run it under a debugger and start at (1) — a null pak is the failure that would reach furthest
before dying.
All three fail as a **segfault inside `System::load`**, with a backtrace pointing at memory setup
rather than at what is actually missing.

## Usage, once it works
1. **`ares::Memory::FixedAllocator::get()` before anything touches a core.** `Bus::reset()`
allocates its page tables from that bump allocator. desktop-ui does this on its first line.
2. **`ares::SuperFamicom::option("Pixel Accuracy", "true")` before `load`.** `PPUBase::implementation`
is null until `setAccurate` picks one of the two PPUs, and `Bus::reset()` calls `ppu.map()` →
`implementation->map()`. `"true"` selects the **accurate** PPU, the only one worth
cross-validating against.
3. **`nall/main.hpp` included by this translation unit.** It emits `::main` only when
`NALL_MAIN_IMPL` is undefined, and nall's own `main.cpp.o` defines that. Omit it and the *link*
fails with a bare `undefined reference to 'main'` from `crt1.o`, which reads like a missing object
file rather than a missing shim.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Correct the repeated setup-failure description.

Both documents group the allocator, PPU, and nall/main.hpp omissions under the System::load segmentation-fault description. The third omission actually causes a link-time undefined reference to 'main'.

  • scripts/accuracysnes/ares_host/README.md#L52-L66: separate the allocator and PPU segmentation faults from the nall/main.hpp link failure.
  • CHANGELOG.md#L33-L39: apply the same separation to the changelog entry.

As per path instructions, documentation is the specification and must match the implementation and build recipe.

📍 Affects 2 files
  • scripts/accuracysnes/ares_host/README.md#L52-L66 (this comment)
  • CHANGELOG.md#L33-L39
🤖 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 `@scripts/accuracysnes/ares_host/README.md` around lines 52 - 66, Update
scripts/accuracysnes/ares_host/README.md lines 52-66 to separate the allocator
and PPU omissions, which cause System::load segmentation faults, from the
nall/main.hpp omission, which causes a link-time undefined reference to main.
Apply the same corrected separation to CHANGELOG.md lines 33-39; both
documentation sites must describe the implementation and build behavior
accurately.

Source: Path instructions

@doublegate
doublegate merged commit 6d43f87 into main Aug 1, 2026
17 checks passed
@doublegate
doublegate deleted the feat/ares-host-works branch August 1, 2026 11:24
doublegate added a commit that referenced this pull request Aug 1, 2026
…my own claims (#305)

Three of ares' five failures are rows snes9x ALREADY fails, which the tally
alone does not show and which changes what each one means: C7.10 and F1.10
become 2-vs-2 (RustySNES + Mesen2 against snes9x + ares), C7.05 is 2-vs-2 with
the two dissenters failing on different codes, and only E8.02 and E3.06 are
ares-only. ares is corroborating snes9x more than it is standing alone. Still
not wired into crossval.sh -- an ARES_KNOWN_FAILURES constant encoding
unadjudicated disagreements would be worse than no third reference.

CORRECTION 1, to the ares README and PR #304: F1.10 is NOT a PAD2_CONTRACT
row and this host's port detection is not the suspect. f1_require_contract
reads $4016 only -- port 1 -- and F1.10 code 2 means "$4212 read busy at the
very start of the vblank line", which does not involve controller state. The
claim was inherited from crossval.sh's Mesen2 grouping rather than checked.

CORRECTION 2, to crossval.sh itself: its Mesen2 known-failure comment names
idx279 F1.03 and idx286 F1.10, and in the current catalogue those indices are
F1.01 and F1.08 -- an index moves whenever a test is added ahead of it. Keyed
on rows now, with the drift noted. That same comment attributes Mesen2's F1.10
failure to the port-2 limitation while the snes9x block a few lines above says
Mesen2 PASSES F1.10; both cannot be true, and it is marked as doubted rather
than quietly rewritten, because resolving it needs Mesen2's failing set read
at DONE and mapped through SOURCE_CATALOG.tsv.

F1.10 now deserves a hard look on its own: fullsnes puts the automatic read's
start ~dot 32.5-95.5 into the first vblank line, snes9x fails the row, ares
fails it, and if the Mesen2 attribution is right then RustySNES passes ALONE
on a row it passes only because of a deliberate fix. The heuristic that says
RustySNES failing alone means a real bug should say the same about RustySNES
passing alone.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
doublegate added a commit that referenced this pull request Aug 1, 2026
… finding (#309)

RETRACTION, and it is the important half. The plan recorded "A2.10 -- Mesen2
is the outlier, 2-vs-1" as the battery's only unexplained reference
disagreement, and PR #304 said ares settled it 3-vs-1. Measured:

  RustySNES  pass
  Mesen2     PASS   (its failing set is F1.03 and F1.10, nothing else,
                     identical on six runs)
  ares       pass
  snes9x     FAIL code 1 -- and documented, the FIRST entry in
                     SNES9X_KNOWN_FAILURES

So the outlier is snes9x, the failure is already explained, and there was
never a disagreement on this row. The old text also asserted "A2.10 is not
among snes9x's 14 known divergences"; it is, at crossval.sh:80. The original
reading took a catalogue index off one host's output and attributed it to
another, and nothing checked it because no per-row measurement existed.

That is the second published claim in one day undone by keying on catalogue
indices instead of row names. An index is only meaningful next to the host
that produced it and the catalogue that was current, and neither travels with
the number.

The ares host was therefore built to settle a row that did not need settling.
It still earned itself: it found a real bug in ares' SMP.

ares is now wired in as a third reference. cross-validation reports
"3 reference(s) agree with the cart". ARES_KNOWN_FAILURES=5 carries per-row
rationale like the other two constants -- C7.05/C7.10/F1.10 are rows snes9x
already fails, E3.06/E8.02 cite the ares $F1 timer-2 reset bug. The block is
opt-in and skips cleanly when the binary is absent, verified in both states.

One bug caught on the way: counting failures with ("0x" $3) % 2 == 0 reported
337 failures, because POSIX awk does not parse "0x01" and the expression is
0 % 2 for every byte. A gate reporting catastrophe out of a parsing bug is a
specific kind of dangerous; the fix matches the last hex digit and says why.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.

2 participants