Skip to content

Commit ade0084

Browse files
authored
release: cut v2.0.6 "Harbor" ("Parity" — iOS feature parity + opt-in crash reporting) (#245)
Second iOS finalization release on the byte-identical v2.0.0 Timebase core (AccuracyCoin 141/141). Adds an opt-in, privacy-first crash-reporting surface (off by default; local-only, excluded from backup; EN+ES) — the iOS analogue of Android's CrashReporter, closing the v1.9.9 gap — plus a feature-parity re-verification against the unchanged v2.0.0 bridge. Version 2.0.5->2.0.6. Independent Swift review + Gemini (5) + Copilot (2) findings all adopted and resolved (incl. the @mainactor crash-handler isolation fix, metadata pre-caching, off-main log read, backup exclusion, i18n).
1 parent 2cd5312 commit ade0084

13 files changed

Lines changed: 571 additions & 28 deletions

File tree

‎.github/release-notes/v2.0.6.md‎

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
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`.

‎CHANGELOG.md‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,26 @@ cycle-accurate core later replaced.
1414

1515
## [Unreleased]
1616

17+
## [2.0.6] - 2026-07-09 - "Harbor" (iOS feature parity — "Parity")
18+
19+
- The second iOS finalization release (the v2.0.5–v2.0.8 window), on the
20+
byte-identical v2.0.0 "Timebase" core: **AccuracyCoin 141/141**, nestest 0-diff,
21+
the `#![no_std]` chip stack untouched. Host / iOS-only — no accuracy / save-state /
22+
determinism number moves.
23+
- **New opt-in crash-reporting surface** (privacy-first, **off by default**) — the
24+
iOS analogue of the Android v1.8.8 `CrashReporter`, closing the v1.9.9 readiness
25+
gap. Enabled from **Settings → Diagnostics**, an uncaught-`NSException` handler
26+
writes **local** crash logs (viewable + copyable in-app; **nothing is uploaded**,
27+
so the "Data Not Collected" privacy label is unchanged). The handler re-checks the
28+
live opt-in at crash time, so opting out stops new logs immediately. EN + ES.
29+
- **Feature-parity re-verification** of the v1.9.x host features against the v2.0.0
30+
bridge (Game Center, CloudKit save sync, MFi controllers, capture / PiP,
31+
accessibility) — all route through the unchanged bridge surface; recorded in
32+
`docs/ios-v2.0.6-readiness.md`.
33+
- Version bump: workspace `2.0.5 → 2.0.6`; iOS `MARKETING_VERSION → 2.0.6`.
34+
- TestFlight-only; the App Store + AltStore PAL launch stays deferred to v2.1.0.
35+
On-device crash-capture verification is flagged for the v2.0.9 readiness pass.
36+
1737
## [2.0.5] - 2026-07-09 - "Harbor" (iOS re-port onto Timebase — "Landfall")
1838

1939
- Opens the iOS finalization window (v2.0.5–v2.0.8) of the v2.0.x "Harbor" train:

‎Cargo.lock‎

Lines changed: 18 additions & 18 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎Cargo.toml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ members = [
2121
]
2222

2323
[workspace.package]
24-
version = "2.0.5"
24+
version = "2.0.6"
2525
edition = "2024"
2626
rust-version = "1.96"
2727
license = "MIT OR Apache-2.0"

‎docs/STATUS.md‎

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,27 @@
11
# RustyNES — Project Status Matrix
22

3-
> **Current release: v2.0.5 "Harbor"** (2026-07-09) — the fifth release of the v2.0.x
3+
> **Current release: v2.0.6 "Harbor"** (2026-07-09) — the sixth release of the v2.0.x
4+
> mobile-finalization train, and the **second iOS finalization release** ("Parity"),
5+
> continuing the iOS window (v2.0.5–v2.0.8). A **host / iOS-only** cut: the
6+
> cycle-accurate emulation core is **unchanged and byte-identical to v2.0.5** —
7+
> AccuracyCoin still **141/141 (100.00%, RAM-authoritative)**, nestest 0-diff, the
8+
> `#![no_std]` chip stack untouched — so no accuracy / save-state / determinism number
9+
> moves. It adds a **new opt-in, privacy-first crash-reporting surface** (off by
10+
> default, the iOS analogue of the Android v1.8.8 `CrashReporter`, closing the v1.9.9
11+
> iOS-applicable deferral): **Settings → Diagnostics** installs an
12+
> uncaught-`NSException` handler that writes **local** crash logs the user can view +
13+
> copy in-app — **nothing is uploaded**, so the "Data Not Collected" privacy label is
14+
> unchanged (EN + ES); the handler re-checks the live opt-in at crash time so opting
15+
> out stops new logs immediately. It also records the **feature-parity
16+
> re-verification** of the v1.9.x host features (Game Center, CloudKit save sync, MFi
17+
> controllers, capture / PiP, accessibility) against the unchanged v2.0.0 bridge
18+
> surface. Version bump (workspace `2.0.5 -> 2.0.6`; iOS `MARKETING_VERSION -> 2.0.6`).
19+
> **TestFlight-only**; App Store + AltStore PAL deferred to v2.1.0; on-device
20+
> crash-capture verification is a **maintainer / v2.0.9** step. See `CHANGELOG.md`
21+
> `[2.0.6]` + `docs/ios-v2.0.6-readiness.md` +
22+
> `to-dos/plans/v2.0.5-v2.0.8-ios-finalization-plan.md`.
23+
>
24+
> **The preceding release: v2.0.5 "Harbor"** (2026-07-09) — the fifth release of the v2.0.x
425
> mobile-finalization train, and the **first iOS finalization release** ("Landfall"),
526
> opening the iOS window (v2.0.5–v2.0.8) that mirrors the Android v2.0.1–v2.0.4 window.
627
> This is a **host / iOS-only** cut: the cycle-accurate emulation core is **unchanged and
@@ -24,7 +45,7 @@
2445
> determinism smoke on Apple silicon. See `CHANGELOG.md` `[2.0.5]` +
2546
> `docs/ios-v2.0.5-readiness.md` + `to-dos/plans/v2.0.5-v2.0.8-ios-finalization-plan.md`.
2647
>
27-
> **The preceding release: v2.0.4 "Harbor"** (2026-07-08) — the fourth release of the v2.0.x
48+
> **The release before that: v2.0.4 "Harbor"** (2026-07-08) — the fourth release of the v2.0.x
2849
> mobile-finalization train, and the **Android release-candidate** milestone. This is a
2950
> **host / Android-only** cut: the cycle-accurate emulation core is **unchanged and
3051
> byte-identical to v2.0.3** — AccuracyCoin still **141/141 (100.00%, RAM-authoritative)**,
@@ -52,7 +73,7 @@
5273
> them to the monetization `feature_enabled` façade without on-device validation). See
5374
> `CHANGELOG.md` `[2.0.4]` + `to-dos/plans/v2.0.4-android-rc-plan.md`.
5475
>
55-
> **The release before that: v2.0.3 "Harbor"** (2026-07-08) — the third release of the v2.0.x
76+
> **Earlier in the train: v2.0.3 "Harbor"** (2026-07-08) — the third release of the v2.0.x
5677
> mobile-finalization train, and the one that makes the octal-latch accuracy work
5778
> real at the shipped default. The **2-cycle-ALE PPU fetch model is promoted from the
5879
> experimental `mc-ppu-2cycle-ale` flag to the unconditional, only PPU fetch path**

0 commit comments

Comments
 (0)