Repository navigation
feat(v1.9.9): "Workshop" — iOS creator/power tools + final readiness gate - #204
Conversation
…gate The last iOS TestFlight release before v2.0.0 "Timebase". Brings the desktop creator/power-tools to touch and runs a full pre-freeze readiness pass (host-gate verification, security audit, gap analysis, completeness-critic). Additive / off-by-default: the bridge gains only forwarding fns over existing rustynes-core APIs, the deterministic core / chip crates are untouched, the shipped / native / no_std / wasm core stays byte-identical, and AccuracyCoin holds 100% (139/139). Creator tools: - Cheats: Game Genie editor (persistent) + raw-RAM peek/poke ($0000-$1FFF). - Read-only debugger inspector (FOSS/TestFlight build only, gated off the App-Store channel per ADR 0027): CPU regs, disassembly window, hex view, single-frame step, over new observational bridge fns. - TAStudio piano-roll: touch frame-input table + scripted playback + record-to-.rnm from power-on. - Foreign movie import .fm2/.bk2/.fcm/.fmv/.vmv -> native .rnm (bounds-checked, 16 MiB per-ZIP-member cap, graceful errors). - Audio depth (rustynes-ios host DSP): 5-band EQ, panning, Schroeder reverb, crossfeed; bypassable to a bit-identical passthrough. - Host-side symbol maps (.sym/.mlb/.nl). Readiness pass / fixes: - File imports + foreign-movie transcode moved off the main thread. - poke_ram clamps the address to the work-RAM mirror bridge-side. - Missed EN/ES catalog strings + VoiceOver labels added across the new views. - TAStudio .rnm export no longer captures trailing idle frames. - Mobile ROM loading is iNES/NES 2.0 only: the picker + Info.plist no longer advertise .fds/.nsf (the shared bridge has no FDS/NSF load path) -- FDS/NSF on mobile are a post-v2.0.0 carryover. - docs/ios-v1.9.9-readiness.md records the full gate. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR ships the iOS v1.9.9 “Workshop” release: bringing creator/power tools (cheats, TAStudio, read-only debugger, foreign movie import, symbol maps, and host-side audio DSP) to the iOS SwiftUI shell while keeping the deterministic Rust core behavior unchanged, plus a “readiness gate” documentation pass and version bumps.
Changes:
- Adds new iOS creator tooling UI (Cheats, TAStudio, Debugger) and related bridge/host plumbing (foreign movie import, symbol map parsing, audio-depth DSP controls).
- Extends
rustynes-mobilewith additive FFI-forwarded APIs for cheats + observational debug reads + foreign movie import, and extendsrustynes-ioswith an output-only audio DSP stage wired into the CoreAudio sink. - Updates iOS import flows to use async/off-main file I/O and removes iOS
.fds/.nsfadvertising (Info.plist + picker) to match supported load paths.
Reviewed changes
Copilot reviewed 29 out of 30 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| ios/RustyNES/TAStudioView.swift | New touch TAStudio piano-roll authoring/playback/export UI. |
| ios/RustyNES/SymbolMap.swift | New host-side parser for .sym/.mlb/.nl symbol files. |
| ios/RustyNES/SettingsView.swift | Adds audio-depth section + localizable slider titles + async palette import. |
| ios/RustyNES/RustyNESApp.swift | Updates open-URL handling to async import/open; clarifies supported ROM types. |
| ios/RustyNES/ROMLibrary.swift | Moves ROM import and ROM reads off-main via async APIs. |
| ios/RustyNES/PillMenu.swift | Adds creator/power tool menu entries; gates debugger to FOSS channel. |
| ios/RustyNES/PaletteManager.swift | Makes palette import async/off-main. |
| ios/RustyNES/MoviePanelView.swift | Adds foreign movie import entry and UTTypes support. |
| ios/RustyNES/Localizable.xcstrings | Adds EN/ES strings for new creator tools + audio-depth labels. |
| ios/RustyNES/Info.plist | Removes .fds/.nsf document types/UTIs; keeps .nes + .zip. |
| ios/RustyNES/GameView.swift | Wires new sheets (Cheats/TAStudio/Debugger) + pause policy updates. |
| ios/RustyNES/EmulatorCore.swift | Adds forwarding APIs (cheats/debug/movie import/audio depth) + TAStudio playback/export logic. |
| ios/RustyNES/DebuggerView.swift | New read-only debugger inspector UI + symbol loading. |
| ios/RustyNES/ContentView.swift | Updates import/open and library open to async; limits ROM picker types to .nes + .zip. |
| ios/RustyNES/CheatsView.swift | New Game Genie + raw RAM peek/poke UI. |
| ios/RustyNES/AudioDepth.swift | New persisted settings model for host audio-depth DSP. |
| ios/RustyNES/AppModel.swift | Adds audio-depth model/apply hook; adds foreign movie import pipeline; async open/import. |
| docs/STATUS.md | Updates project status matrix for v1.9.9. |
| docs/ios.md | Documents v1.9.9 creator/power tools and iOS v1.9.x status/carryovers. |
| docs/ios-v1.9.9-readiness.md | New readiness gate record (verification/security/gap/completeness). |
| crates/rustynes-mobile/src/lib.rs | Adds UniFFI records + exported APIs for cheats/debug/import; adds bounds/safety helpers + tests. |
| crates/rustynes-ios/src/lib.rs | Exposes new audio_dsp module. |
| crates/rustynes-ios/src/ffi.rs | Adds C ABI to publish live audio-depth config to the sink. |
| crates/rustynes-ios/src/audio.rs | Wires audio-depth DSP into real-time callback via lock-free config mailbox. |
| crates/rustynes-ios/src/audio_dsp.rs | New host-safe EQ/pan/reverb/crossfeed DSP implementation + unit tests. |
| crates/rustynes-ios/include/rustynes_ios.h | Adds header declaration for rustynes_ios_audio_set_depth. |
| CHANGELOG.md | Adds v1.9.9 release notes. |
| Cargo.toml | Bumps workspace version to 1.9.9. |
| Cargo.lock | Updates crate versions to 1.9.9. |
| android/app/build.gradle.kts | Bumps Android versionCode/versionName to 1.9.9. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Code Review
This pull request introduces the v1.9.9 'Workshop' release, which adds several creator and power-user tools to the iOS build, including a Game Genie cheat editor, a read-only debugger inspector, a TAStudio piano-roll for input scripting, foreign movie import support, and host-side audio-depth DSP (EQ, pan, reverb, crossfeed). The changes include new Rust modules for the DSP and FFI, updated Swift models for settings and UI, and several async refactors to improve UI responsiveness during file operations. The review feedback highlights critical issues regarding security-scoped resource access in background tasks, suggests improvements for hex address parsing robustness, proposes UI enhancements for the memory editor, and recommends replacing a polling timer with an asynchronous loop for better battery efficiency.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
…tudio Resolve the gemini + copilot threads on v1.9.9 "Workshop" (all in ios/RustyNES/): - Security-scoped resource (gemini HIGH x4): hoist startAccessingSecurityScoped- Resource() + its defer out of Task.detached onto the main-actor caller so the scope brackets the await (acquiring it inside the detached task can fail). Fixed in ROMLibrary, PaletteManager, AppModel.importForeignMovie, DebuggerView; also fixed the identical pre-existing pattern in HDPackStore.importPack. - importForeignMovie no longer captures the non-Sendable EmulatorCore in a detached closure: the task returns only Data; the transcode runs back on main. - CheatsView raw-RAM editor validates the address to $0000-$1FFF (parsedAddr is nil out-of-range), so Peek/Poke disable and can't alias into the mirror. - tasStartExport guards against an empty frame table so the recorder is never left armed. - SymbolMap parses hex with UInt(_,radix:16) + <= 0xFFFF range check instead of a fragile length test. - TAStudio frame-count label uses the localized "%lld frames" key; the poll timer only runs during an active export (connectable publisher), idle-CPU-free. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
v1.9.9 "Workshop" — the final iOS TestFlight release before v2.0.0 "Timebase"
Brings the desktop creator/power-tools to touch and runs a full pre-freeze readiness pass. Additive / off-by-default: the bridge gains only forwarding fns over existing
rustynes-coreAPIs, the deterministic core / chip crates are untouched, the shipped / native /no_std/ wasm core stays byte-identical, and AccuracyCoin holds 100% (139/139).Creator / power tools
$0000–$1FFF)..rnm..fm2/.bk2/.fcm/.fmv/.vmv→ native.rnm(bounds-checked: 16 MiB per-ZIP-member cap, graceful errors, never panics).rustynes-ioshost DSP) — 5-band EQ, panning, Schroeder reverb, crossfeed; bypassable to a bit-identical passthrough..sym/.mlb/.nl.Readiness gate (verification · security · gap · completeness)
Full host-gate suite green (fmt / clippy every feature combo / rustdoc /
no_std/ wasm ×2 /test-roms139/139 / markdownlint). A security audit (no Critical/High), a gap analysis, and a completeness-critic sweep ran; their findings were folded into a final fix round. Full record indocs/ios-v1.9.9-readiness.md.Fixes from the gate: file imports + foreign-movie transcode moved off the main thread;
poke_ramclamps the address bridge-side; missed EN/ES catalog strings + VoiceOver labels added; TAStudio.rnmexport no longer captures trailing idle frames.Note: mobile is iNES / NES 2.0 only
The picker +
Info.plistno longer advertise.fds/.nsf(the shared bridge has no FDS/NSF load path). FDS disk + NSF playback on mobile are a post-v2.0.0 carryover, alongside the 20-band EQ and.dbgsource maps.iOS build + on-device validation remain the documented TestFlight carryover (Linux CI can't compile Swift).
🤖 Generated with Claude Code