feat(v2.1.10): browser RetroAchievements deploy + Vs. DualSystem libretro present (Web Parity)#287
Merged
Merged
Conversation
Contributor
|
Warning You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again! |
There was a problem hiding this comment.
Pull request overview
Implements the “Web Parity” deliverables for the WebAssembly/frontend deployment stack and the libretro wrapper: adds a deployable browser RetroAchievements auth-proxy service (env-configured) and wires Vs. DualSystem dual-screen presentation into the libretro core while updating documentation and changelog entries to match.
Changes:
- Add env-driven configuration support to the browser RA auth proxy stub and ship it as a first-class
deploy/compose service behind Caddy at/ra/*. - Implement Vs.
DualSystemdetection and dual-framebuffer side-by-side (512×240) presentation inrustynes-libretro, including input/audio/state/memory-map behavior. - Add/extend documentation and changelog coverage for the deploy stack and the libretro dual presentation; add wasm RA marshalling-contract tests.
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| scripts/cheevos/auth_proxy_stub.py | Adds env-var override configuration so the same proxy stub works for local dev and container deployment. |
| crates/rustynes-libretro/src/lib.rs | Adds Emu::from_rom-based DualSystem detection plus dual present/serialize/memory-map paths (512×240 composed output). |
| crates/rustynes-frontend/src/wasm_cheevos.rs | Adds browser RA marshalling-contract unit tests (unlock filtering, malformed payload tolerance, “not configured” caveat). |
| deploy/Dockerfile.raproxy | Introduces a container image for the RA auth proxy stub (non-root, env-configured). |
| deploy/docker-compose.yml | Adds the ra-proxy service and wires it behind Caddy alongside signaling and coturn. |
| deploy/Caddyfile | Proxies /ra/* to the RA proxy service (in addition to the existing signaling proxying). |
| deploy/.env.example | Documents required RA proxy environment variables (User-Agent, CORS allowlist, upstream, casual enforcement). |
| deploy/README.md | Expands deploy bundle docs to include the RA proxy and a manual live-verify checklist. |
| docs/cheevos-browser.md | Updates browser RA docs to reflect deployable auth-proxy service + env-driven configuration. |
| docs/libretro/advanced_features.md | Documents libretro Vs. DualSystem two-screen presentation behavior and constraints. |
| docs/frontend.md | Notes libretro dual present parity and documents wasm/mobile deferrals for dual present. |
| CHANGELOG.md | Adds Unreleased bullets describing libretro dual present and the RA proxy deploy stack work. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
… Web Parity) Wire the core's existing Vs. DualSystem support (Emu::Dual / VsDualSystem — the four cross-wired arcade boards) through the libretro present path, mirroring the desktop frontend's emu.dual branch. Previously the wrapper only built a single Nes, so a DualSystem dump would boot one console that hangs on its absent partner. Detection reuses Emu::from_rom (NES 2.0 header Vs. type OR SHA-keyed vs_db). The core holds nes OR dual (mutually exclusive). run_dual steps both consoles, composes their two 256x240 RGBA framebuffers into one 512x240 XRGB8888 side-by-side image (MAIN left, SUB right), and presents it; max_width in the AV info is 512 so RetroArch honours the per-frame width without a geometry renegotiation. Ports 0/1 drive MAIN P1/P2, 2/3 drive SUB P1/P2. Only MAIN audio plays; the SUB APU ring is drained to stay bounded. Save states use snapshot/restore; memory maps expose MAIN. Shared blit + audio helpers; hot buffers pre-sized to 512x240. The deterministic no_std core is untouched and byte-identical. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…, v2.1.10) The browser-RA marshalling (ra_glue.js + wasm_cheevos.rs) has shipped since v1.7.0; the remaining ADR 0015 carryover was the DEPLOY half — the auth proxy that injects RA's identity User-Agent server-side. Adds deploy/Dockerfile.raproxy + an ra-proxy compose service behind Caddy at https://<DOMAIN>/ra/*, env-configured (no committed secret; the proxy holds no RA secret). The stub gained env-var config so one script serves local dev and the container. .env.example + deploy/README.md document the four-service stack + a browser-RA live-verify runbook. wasm_cheevos.rs gains marshalling-contract tests. docs/cheevos-browser.md records the deployable proxy. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Document the v2.1.10 Web Parity work: the libretro Vs. DualSystem side-by-side present (docs/libretro/advanced_features.md + docs/frontend.md present-path parity note), and record the wasm desktop-style dual present as a documented deferred (cross-platform compositor + core already exist; the GPU present un-gate + wasm load-detection defer to the v2.1.8/v2.1.9 gfx rebase). CHANGELOG [Unreleased] gains the libretro-dual + browser-RA-deploy Added entries and the wasm-dual Deferred entry, explicit about code-complete vs needs-live-deploy-to-verify. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…-defer rationale The rebase onto origin/main (through v2.1.9) correctly relocated the v2.1.6-2.1.9 entries into their released [2.1.x] sections and left [Unreleased] empty; re-add ONLY the v2.1.10 Web Parity entry (libretro Vs. DualSystem present + browser-RA deploy Added, wasm dual Deferred). Update the docs/frontend.md wasm-defer note to the accurate post-rebase rationale: the concurrency reason is resolved, so the deferral now rests on the real basis — enabling wasm dual present is a multi-site change to the common wasm present hot-path (separate wasm ROM-load path, un-gate present_dual/dual_mode + Gfx::render_dual) for a niche feature that cannot be runtime-verified in CI (no headless browser GPU present); the libretro core delivers Vs. DualSystem for RetroArch now. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
11b1d9d to
345f2f1
Compare
…, assert cleanup Three Copilot review points on #287: 1. libretro push_audio: audio_buffer had capacity 4096 but pushes up to 2x the mono drain (8192 stereo samples), so it could reallocate on the hot path. Bumped the pre-alloc to 4096*2 (Default + retro_core!) and added a reserve(produced*2) belt-and-suspenders guard so the no-alloc guarantee stays true even if audio_float_buffer is later grown. 2. auth_proxy_stub.py: a non-numeric RA_PROXY_BIND (or config bind) port raised a raw ValueError traceback. Added _parse_port() that fails fast with a clear, actionable message (and an out-of-range 1-65535 check) for both the file-config and env paths — clean exit for container deploys, not a stack trace. 3. wasm_cheevos.rs: removed a stray trailing comma in a single-condition assert!(). (assert!(expr,) is actually valid Rust — the macro accepts an optional trailing comma — but the cleaner form removes any doubt.) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
doublegate
added a commit
that referenced
this pull request
Jul 12, 2026
…#295) Cuts the v2.1.10 release — the creator-tools-and-web-parity step of the v2.1.5 → v2.2.0 "deepen the existing project" run. Bumps the workspace version 2.1.9 → 2.1.10, renames CHANGELOG `[Unreleased]` → `[2.1.10]`, refreshes Cargo.lock, syncs the README badge / current-release paragraph / BibTeX, and authors `.github/release-notes/v2.1.10.md`. v2.1.10 (PRs #287, #288) deepens content-creation and closes the deferred browser gaps, on the byte-identical deterministic core (AccuracyCoin 141/141, visual_regression byte-identical, save-state / TAS / netplay replay bit-identical): - #288 — TAStudio greenzone / force-greenzone caching + Lua API breadth (full lifecycle callbacks, memory read-write with *Debug variants, HUD drawing, example library, wasm piccolo parity). Two review-surfaced greenzone anchor-bookkeeping bugs fixed with new regression tests. - #287 — browser RetroAchievements (wasm trampoline + deployable auth-proxy, ADR 0015; live login is a documented deploy-to-verify step) + Vs. DualSystem presentation in the libretro core. Vs. DualSystem wasm present honestly deferred. A real rustynes-libretro push_audio realloc bug fixed en route. No default-build behavior change. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
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.
v2.1.10 "Web Parity" — browser RetroAchievements deploy + Vs.
DualSystemlibretro presentFinishes the Web Parity half of v2.1.10. All work is frontend / libretro /
infra — the deterministic
#![no_std]core is untouched and byte-identical(AccuracyCoin 141/141, visual_regression + save-state round-trip green).
1. Browser RetroAchievements — the ADR 0015 deploy carryover
The browser-RA marshalling (
ra_glue.jsrc_client trampoline +wasm_cheevos.rs)has shipped since v1.7.0; the remaining ADR 0015 carryover was the deployable
auth proxy — the service that injects RA's identity
User-Agentserver-side(browsers forbid scripts from setting it).
deploy/Dockerfile.raproxyruns the stdlib-only reference stub (non-root,env-configured); an
ra-proxycompose service sits behind the shared CaddyTLS proxy, exposed at
https://<DOMAIN>/ra/*(ahandle_pathstrips/rasothe rcheevos path reaches upstream RA verbatim).
RA_PROXY_BIND/RA_USER_AGENT/
RA_UPSTREAM/RA_ALLOWED_ORIGINS/RA_ENFORCE_CASUAL) so one script servesboth local dev (
--configTOML) and the container (env only). No RA secret isheld or committed — only the non-secret identity header is injected; the user's
own login transits at request time.
wasm_cheevos.rsgains marshalling-contract tests (ACHIEVEMENT_TRIGGEREDfiltering, malformed-payload tolerance, the not-configured caveat).
Code-complete + validated (
docker compose configvalid, proxy env-configverified, wasm
browser-cheevosgate green). Needs live deploy to fully verify:standing the stack on a real host, the RA-team
User-Agentcoordination, and areal browser RA login + casual unlock (the un-CI-able ADR 0015 acceptance gate).
Runbook in
deploy/README.md§"Browser RA live-verify checklist" +docs/cheevos-browser.md.2. Vs.
DualSystempresentation — libretro (wasm documented-deferred)The core already models the four Vs.
DualSystemarcade boards (Emu::Dual/VsDualSystem); this wires the libretro present path (crates/rustynes-libretro):Emu::from_rom(NES 2.0 header Vs. type OR theSHA-keyed
vs_db) the desktop frontend uses; the core now holdsnesordual(mutually exclusive).retro_runand composes their two 256×240framebuffers into a single 512×240 XRGB8888 side-by-side image (MAIN left, SUB
right), presented within a 512-wide
max_widthgeometry so RetroArch draws thevariable width without a geometry renegotiation.
to stay bounded); save states use
VsDualSystem::snapshot/restore; memory mapsexpose the MAIN console. Previously a cabinet dump booted a single console that
hangs on its absent partner.
Code-complete + builds (
cargo build -p rustynes-libretro, clippy clean). Alive RetroArch run with a real cabinet dump is the maintainer's manual check.
wasm dual present is a documented deferred: the CPU compositor
(
Gfx::compose_dual_into) and the core (Emu::Dual) are already cross-platform,but the wasm ROM-load detection + un-gating the GPU present branch
(
Gfx::render_dual,cfg(not(wasm))) are deferred to the v2.1.8/v2.1.9gfx/composite rebase to avoid colliding with that concurrently-rewritten present
path (per the worktree concurrency directive). Mobile stays deferred.
3. Deploy stack coherence
deploy/is now a coherent four-service stack (signaling+ra-proxy+caddycoturn);docker compose upbrings all four up..env.example+deploy/README.mddocument the full stack, the RA proxy config, and both live-verifyrunbooks (netplay + browser RA). Not deployed live here — made deployable + documented.
Gates
cargo fmt --all --check✅ ·cargo clippy --workspace --all-targets -D warnings✅retroachievements✅ · wasm32 (wasm-winit, wasm-canvas, browser-cheevos) ✅cargo build -p rustynes-libretro✅ · rustdoc-D warnings✅ · markdownlint (v0.39.0) ✅docker compose configvalid ✅ · proxypy_compile+ env-config ✅🤖 Generated with Claude Code