|
| 1 | +# RustyNES v2.0.6 — "Harbor" ("Parity") |
| 2 | + |
| 3 | +**iOS feature-parity finalization.** The sixth release of the v2.0.x "Harbor" mobile-finalization train, and the second of the four-release **iOS finalization window (v2.0.5 → v2.0.8)**. It runs on the byte-identical **v2.0.0 "Timebase"** core — **AccuracyCoin 141/141 (100.00%)**, nestest 0-diff, the `#![no_std]` chip stack untouched — so **no accuracy, save-state, or determinism number moves**. This is a host / iOS-only cut. |
| 4 | + |
| 5 | +No store submission happens here (that is the future v2.1.0 joint launch); v2.0.6 closes a host-authorable v1.9.9 parity gap and re-verifies the v1.9.x host features against the new core. |
| 6 | + |
| 7 | +--- |
| 8 | + |
| 9 | +## The core is unchanged (141/141) |
| 10 | + |
| 11 | +Nothing in the emulation core changed since v2.0.3. AccuracyCoin holds **141/141 (100.00%, RAM-authoritative)**, nestest is 0-diff, the 60-ROM commercial byte-identity oracle is unmoved. |
| 12 | + |
| 13 | +## New: opt-in crash reporting (privacy-first) |
| 14 | + |
| 15 | +The iOS analogue of the Android v1.8.8 `CrashReporter`, closing the v1.9.9 readiness gap that listed an "opt-in crash-reporting surface" as an iOS-applicable deferral. |
| 16 | + |
| 17 | +- **Off by default.** Enabled from **Settings → Diagnostics**. With it off, the app collects and writes nothing — the **"Data Not Collected"** privacy nutrition label is unchanged, and `PrivacyInfo.xcprivacy` needs no edit. |
| 18 | +- **Local-only.** When enabled, an uncaught-`NSException` handler writes a timestamped crash report (app version, device, OS, exception name / reason, call stack) to `Application Support/RustyNES/crash-logs/`, keeping the 10 most recent. **Nothing is uploaded** — the reports are for the user to read, **copy** to the clipboard, and share manually if they choose. A **Crash logs** viewer (list → per-log detail → Copy / Clear) lives in the same section. EN + ES. |
| 19 | +- **Honest about scope.** `NSSetUncaughtExceptionHandler` catches the Objective-C / bridged `NSException` class (UIKit, KVO, bridged Foundation). Pure-Swift runtime traps (`fatalError`, force-unwrap of nil, out-of-bounds) abort via a POSIX signal an exception handler cannot see; writing files from a signal handler is async-signal-unsafe, so — exactly as the Android side documents Firebase Crashlytics as the maintainer option rather than pulling it in — Swift-trap capture is left to a real third-party reporter a maintainer can add later, gated on this same opt-in flag. The handler also re-checks the live opt-in at crash time, so opting back out stops new logs immediately. |
| 20 | + |
| 21 | +## Feature-parity re-verification |
| 22 | + |
| 23 | +The v1.9.x host features were re-checked against the **v2.0.0 bridge surface** (unchanged by the timebase rewrite, which touched only the scheduler internals): Game Center cloud saves / achievements, iCloud KV-store config + CloudKit `.rns` save-state sync, MFi / hardware controllers (hot-plug, P1–P4), ReplayKit capture / share + PiP, and the accessibility layer (VoiceOver, Dynamic Type, colorblind palettes). All continue to route through the same typed bridge and the re-ported save-state epoch. The audit is recorded in `docs/ios-v2.0.6-readiness.md`. |
| 24 | + |
| 25 | +## Verification (host) |
| 26 | + |
| 27 | +- **Core unchanged** — AccuracyCoin **141/141**, nestest 0-diff (not re-run; the chip stack is untouched). |
| 28 | +- `cargo check --workspace` green after the version bump + `Cargo.lock` regen; `cargo fmt --all --check`, `cargo clippy --workspace --all-targets -D warnings` (no issues), `RUSTDOCFLAGS=-D warnings cargo doc`, the `no_std` cross-compile, and both wasm32 clippy gates all green. |
| 29 | +- `Localizable.xcstrings` remains valid JSON (EN source + the added ES entries). |
| 30 | +- markdownlint (CI-pinned) clean on the new / edited docs. |
| 31 | +- New Swift matches the app's existing SwiftUI baseline (the crash-log views follow the same `NavigationStack` / closure-`NavigationLink` / `.topBarTrailing` patterns already in Settings, so they add no availability regression) and is auto-included by xcodegen (`sources: path: RustyNES`); the Swift compile + on-device behaviour remain the documented macOS / TestFlight carryover (no Xcode on the Linux host). |
| 32 | + |
| 33 | +## Maintainer / on-device closeout (deferred to v2.0.9 / the TestFlight upload) |
| 34 | + |
| 35 | +- Build the app with **Xcode 26 / the iOS 26 SDK** (the App Store submission floor — a hard gate at v2.0.7) and confirm the new Diagnostics UI + crash-log viewer render on device. |
| 36 | +- Force a test `NSException` on device and confirm a local log is written, viewable, copyable, and pruned to 10; confirm the toggle-off path stops new logs. |
| 37 | +- The full v1.9.9 on-device TestFlight checklist (ROM import, save / rewind, MFi controller, audio interruptions, ProMotion pacing, an accurate privacy label). |
| 38 | + |
| 39 | +## What's next — the rest of "Harbor" |
| 40 | + |
| 41 | +- **v2.0.7** — iOS polish + performance + the **iOS 26 SDK / Xcode 26** App Store submission-floor readiness + the privacy-manifest / required-reason-API audit. |
| 42 | +- **v2.0.8** — the iOS release candidate (App Store Connect listing staged, TestFlight external beta, App-Review self-audit). |
| 43 | +- **v2.0.9** — joint on-device readiness verification for both apps. |
| 44 | +- **v2.1.0** — the **joint Google Play + Apple App Store + AltStore PAL + F-Droid launch**. |
| 45 | + |
| 46 | +Full detail: `CHANGELOG.md` `[2.0.6]` · `docs/STATUS.md` (single source of truth) · `docs/ios-v2.0.6-readiness.md` · `to-dos/plans/v2.0.5-v2.0.8-ios-finalization-plan.md`. |
0 commit comments