|
| 1 | +# RustyNES v2.0.5 "Harbor" ("Landfall") — iOS re-port readiness |
| 2 | + |
| 3 | +This is the readiness record for **v2.0.5 "Landfall"**, the first iOS/iPadOS release of |
| 4 | +the v2.0.x "Harbor" mobile-finalization train — the iOS re-port of the frozen v1.9.9 app |
| 5 | +onto the **v2.0.0 "Timebase"** core. It is the iOS analogue of the Android v2.0.1 |
| 6 | +re-port, and opens the iOS finalization window (**v2.0.5 → v2.0.8**). `docs/STATUS.md` |
| 7 | +remains the per-suite source of truth; this file is the authoritative v2.0.5 summary. |
| 8 | + |
| 9 | +v2.0.5 is a **host / iOS-only** cut. The deterministic core and chip crates are |
| 10 | +untouched; the shipped / native / `no_std` / wasm core stays **byte-identical to |
| 11 | +v2.0.4** and **AccuracyCoin holds 141/141 (100.00%, RAM-authoritative)**, nestest is |
| 12 | +0-diff. Every change is presentation / host-side. |
| 13 | + |
| 14 | +## 1. What landed |
| 15 | + |
| 16 | +- **The pre-Timebase movie warning, surfaced + localized on iOS.** The v2.0.0 timebase |
| 17 | + rewrite bumped the `.rns`/`.rnm` epoch (ADR 0028): a pre-v2.0.0 `.rnm` still replays |
| 18 | + its input on the new core, but byte-exact framebuffer / audio reproduction is no |
| 19 | + longer guaranteed. The v2.0.3 bridge queues a machine-readable `HostWarning` code for |
| 20 | + this; v2.0.5 surfaces it on iOS: |
| 21 | + - `EmulatorCore.drainWarnings() -> [String]` drains `NesController.drainWarningCodes()` |
| 22 | + and maps each `HostWarning` to a localized string (idempotent — the queue empties on |
| 23 | + read, so each warning surfaces exactly once). |
| 24 | + - `AppModel.surfaceWarnings()` is called after every successful `moviePlay` (both the |
| 25 | + saved-`.rnm` `playMovie(at:)` path and the foreign-movie `importForeignMovie(at:)` |
| 26 | + path) and routes the text to a new `@Published var warningMessage`. |
| 27 | + - `ContentView` presents `warningMessage` through a **single alert that multiplexes |
| 28 | + the error + warning channels** — it prefers the error when both are queued and |
| 29 | + clears only the visible channel on dismissal, so neither is dropped (two chained |
| 30 | + `.alert` modifiers on one view would race — SwiftUI presents only one) and a |
| 31 | + warning still never reads as a failure. |
| 32 | + - `Localizable.xcstrings` gains the EN source string + its ES translation; the English |
| 33 | + key and the ES copy are **byte-identical to the Android `host_warning_pre_timebase_movie` |
| 34 | + resource**, so both platforms surface the same wording. |
| 35 | +- **UniFFI-Swift binding surface re-confirmed against the v2.0.0 bridge.** The generated |
| 36 | + Swift surface (`drainWarningCodes() -> [HostWarning]`, `HostWarning.preTimebaseMovie`, |
| 37 | + `moviePlay(bytes:)`) matches the new host code, verified by a host emit (see §2). |
| 38 | +- **Version realignment.** Workspace `2.0.4 → 2.0.5` (version-only `Cargo.lock` cascade, |
| 39 | + 18 crates). iOS `MARKETING_VERSION 1.9.1 → 2.0.5` in `ios/project.yml` (the frozen |
| 40 | + v1.9.x default is realigned to the workspace version); the build number stays |
| 41 | + CI-injected by the fastlane `beta` lane. |
| 42 | + |
| 43 | +## 2. Verification / validation |
| 44 | + |
| 45 | +### Host gate suite |
| 46 | + |
| 47 | +| Gate | Result | |
| 48 | +|---|---| |
| 49 | +| `cargo check --workspace` (version bump + lock regen) | PASS (46 crates; version-only lock diff) | |
| 50 | +| `cargo fmt --all --check` | PASS | |
| 51 | +| `cargo clippy --workspace --all-targets -- -D warnings` | PASS | |
| 52 | +| `RUSTDOCFLAGS="-D warnings" cargo doc --workspace --no-deps` | PASS | |
| 53 | +| `cargo build -p rustynes-core --target thumbv7em-none-eabihf --no-default-features` (`no_std`) | PASS | |
| 54 | +| both wasm clippy gates | PASS | |
| 55 | +| `markdownlint` (pinned v0.39.0, changed docs) | PASS | |
| 56 | +| **UniFFI-Swift emit** (`uniffi-bindgen generate --library <host build> --language swift`) | PASS — emits `drainWarningCodes`, `HostWarning.preTimebaseMovie`, `moviePlay(bytes:)` | |
| 57 | +| `Localizable.xcstrings` JSON validity (EN source + added ES entry) | PASS | |
| 58 | + |
| 59 | +The Swift-side change references only symbols confirmed present in the regenerated |
| 60 | +bridge surface; the exhaustive `switch` over `HostWarning` is sound (the generated enum |
| 61 | +is compiled into the app module). |
| 62 | + |
| 63 | +### Not host-certifiable (macOS / device) |
| 64 | + |
| 65 | +The Xcode build, the `RustyNESFFI.xcframework` assembly (`scripts/build-ios-xcframework.sh`), |
| 66 | +and any on-device run are **not** reproducible on the Linux host and remain the documented |
| 67 | +TestFlight carryover (§3). |
| 68 | + |
| 69 | +## 3. On-device / maintainer carryovers (v2.0.9 / the TestFlight upload) |
| 70 | + |
| 71 | +- Regenerate the xcframework on macOS and archive with **Xcode 26 / the iOS 26 SDK** (the |
| 72 | + App Store submission floor — a hard gate at v2.0.7; deployment target may stay iOS 16/17). |
| 73 | +- **Save-state migration** from a v1.9.x install onto the v2.0.0 epoch, and the |
| 74 | + **AccuracyCoin / SMB / Zelda determinism smoke** on Apple silicon. |
| 75 | +- A physical-device **TestFlight boot smoke** (iPhone 14+ / iPad); confirm the |
| 76 | + pre-Timebase-movie notice renders correctly under both EN and ES locales, and that a |
| 77 | + post-v2.0.0 `.rnm` produces **no** warning. |
| 78 | +- The full v1.9.9 on-device TestFlight checklist (ROM import, save / rewind, MFi |
| 79 | + controller, audio interruptions, ProMotion pacing, an accurate privacy label). |
| 80 | + |
| 81 | +## 4. Carryovers to v2.0.6 → v2.0.8 (unchanged from v1.9.9 §5) |
| 82 | + |
| 83 | +Feature-parity re-verify against the v2.0.0 behaviour (Game Center, CloudKit save sync, |
| 84 | +controllers, capture/PiP, accessibility) lands in **v2.0.6**; polish / performance + the |
| 85 | +**privacy-manifest + required-reason-API audit** + the submission-floor wiring in |
| 86 | +**v2.0.7**; the App Store Connect listing + signing scaffold + §4.7 self-audit in the |
| 87 | +**v2.0.8** iOS RC. The post-Timebase feature carryovers (FDS/NSF, the 20-band EQ, `.dbg` |
| 88 | +source maps, a cheats DB, box-art scraping, a dedicated external-display output) remain |
| 89 | +deferred for re-evaluation at/after v2.1.0. Full phasing: |
| 90 | +`to-dos/plans/v2.0.5-v2.0.8-ios-finalization-plan.md`. |
0 commit comments