@@ -15,71 +15,108 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1515
1616## [ Unreleased]
1717
18- ### Android — v2.0.1 core re-port onto Timebase + the start of the ` foss ` /` play ` split
19-
20- - ** Android re-ported onto the v2.0.0 "Timebase" core.** The ` versionCode ` /` versionName `
21- bump to ` 20001 ` / ` 2.0.1 ` cuts the first release of the Android mobile-finalization
22- re-port train (see ` to-dos/ROADMAP.md ` ). The deterministic chip stack is byte-identical,
23- so host CI accuracy is unchanged (** AccuracyCoin 139/141** ).
24- - ** Movie-epoch warning on the mobile bridge (ADR 0028).** ` rustynes-mobile ` 's
25- ` NesController::movie_play ` now peeks ` rustynes_core::recorded_before_v2_timebase ` and, for
26- a pre-v2.0.0 ` .rnm ` , queues a drainable host warning (new ` NesController::drain_warnings ` )
27- — mirroring the desktop + wasm frontends. Input replay still proceeds, but the host can now
28- tell the user that exact framebuffer/audio reproduction is not guaranteed across the
29- engine-timebase boundary. A pre-v2.0.0 ` .rns ` restore already maps to a clean
30- ` MobileError::SaveState ` (no crash). Host-shell wiring only; the core is untouched.
31- - ** Structural start of the ` foss ` / ` play ` Android product-flavor split (ADR 0025).** Added a
32- ` distribution ` flavor dimension — ` foss ` (default, ` isDefault = true ` ) + ` play ` — with
33- ` PLAY_BUILD ` set per-flavor. Every proprietary Google-Play SDK (Play Billing, the Cast
34- Application Framework, Play Games v2, Play Integrity, in-app update/review) moved from
35- unconditional ` implementation(…) ` to ** ` playImplementation(…) ` ** , so the ` foss ` variant links
36- ** none** of them. The glue that touches those SDKs (` LicenseManager ` , ` PlayGamesManager ` ,
37- ` CloudSaveManager ` , ` IntegrityManager ` , ` PlayUpdatesManager ` , ` ChromecastSender ` ) moved to
38- ` src/play/ ` with byte-compatible ** no-op façades in ` src/foss/ ` ** ; shared pure types
39- (` PgsIds ` , ` IntegrityVerdict ` , ` DEMO_SESSION_SECONDS ` ) moved to ` src/main ` ; ` MainActivity `
40- now reads a flavor-neutral ` LicenseManager.priceLabel ` instead of the Google ` ProductDetails `
41- type, so ` src/main ` links no Play SDK. The Cast-framework OPTIONS_PROVIDER + Play-Games APP_ID
42- manifest meta-data moved to ` src/play/AndroidManifest.xml ` so they never merge into the
43- ` foss ` manifest. An ` installDebug ` alias forwards to ` installFossDebug ` so the dev/CI command
44- is unchanged; ` android.yml ` now bundles both flavors. The monetization / ad glue stays dormant
45- (the AppLovin/RevenueCat wiring is the v2.1.0 step). The AOSP Presentation-API ` CastManager `
46- is not a proprietary SDK and stays shared in ` src/main ` .
47- - ** Docs:** added the previously-dangling ` to-dos/v1.8.x-on-device-verification.md ` (the manual
48- on-device checklist the mobile plan cites).
18+ * Nothing yet — the next planned milestone is ** v2.0.2** , continuing the v2.0.x
19+ "Harbor" mobile-finalization train (see ` to-dos/ROADMAP.md ` ).*
20+
21+ ## [ 2.0.1] - 2026-07-08 - "Harbor" (first Android re-port onto Timebase + AccuracyCoin re-sync + housekeeping)
22+
23+ The first release of the ** v2.0.x "Harbor" mobile-finalization train** — the
24+ Android app re-ported onto the v2.0.0 "Timebase" core, the AccuracyCoin oracle
25+ re-synced to upstream, and the housekeeping #225 deferred to "v2.0.1+". All core
26+ changes are behaviour-neutral: the deterministic chip stack is byte-identical to
27+ v2.0.0 and AccuracyCoin holds its honest ** 139/141 (98.58%)** (the two new upstream
28+ PPU tests are known, documented gaps — see below). No store submission (that is
29+ the future v2.1.0 joint launch); Android continues as GitHub-sideload.
30+
31+ ### Added
32+
33+ - ** Android core re-port onto the v2.0.0 Timebase core (ADR 0028, PR #235 ).** The
34+ ` rustynes-android ` host + Jetpack Compose app rebuild against the one-clock
35+ ` rustynes-mobile ` UniFFI bridge (regenerated against uniffi 0.32);
36+ ` versionCode 20000 → 20001 ` , ` versionName "2.0.0" → "2.0.1" ` . The ` .rnm ` movie
37+ epoch warning is wired into the mobile ` movie_play ` path
38+ (` recorded_before_v2_timebase ` → a drainable host warning via
39+ ` NesController::drain_warnings ` citing ADR 0028), reaching desktop/wasm parity: a
40+ pre-v2.0.0 movie replays its input faithfully but surfaces the cross-timebase
41+ reproduction caveat, and a pre-v2.0.0 ` .rns ` restore maps to a clean
42+ ` MobileError::SaveState ` . Host-shell wiring only; the core is untouched.
43+ - ** ` foss ` / ` play ` Android flavor split — structural scaffolding (ADR 0025, PR
44+ #235 ).** A new ` distribution ` flavor dimension with a default ** ` foss ` ** flavor
45+ (no Google SDKs, no ads, no tracking — the F-Droid/sideload artifact) and a
46+ ** ` play ` ** flavor. The five proprietary subsystems (Billing, Cast/Chromecast,
47+ Play Games v2, Integrity, in-app update/review) move to ` playImplementation `
48+ behind ` src/main ` façades with ** no-op ` src/foss/ ` ** twins and real ` src/play/ `
49+ implementations — including the CAF ` MediaRouteButton ` (routed through the
50+ ` ChromecastSender ` façade so ` src/main ` links no ` androidx.mediarouter ` /
51+ ` com.google.android.gms.cast ` ). CI builds both ` assembleFoss* ` /` assemblePlay* `
52+ (the foss+play Gradle bundle is green). Monetization stays dormant; on-device
53+ flavor verification is deferred to v2.0.9. Also added the previously-dangling
54+ ` to-dos/v1.8.x-on-device-verification.md ` .
55+
56+ ### Changed
57+
58+ - ** AccuracyCoin oracle re-synced to upstream ` 100thCoin/AccuracyCoin ` (PR #232 ).**
59+ The catalog grows ** 144 → 146 rows / 139 → 141 assigned tests** — the two new
60+ upstream PPU tests, ** "ALE + Read"** and ** "Hybrid Addresses"** , plus the
61+ upstream "$2002 Flag Timing" + "Sprites On Scanline 0" fixes folded into the
62+ existing rows. The drift-guards in
63+ ` crates/rustynes-test-harness/src/accuracy_coin_catalog.rs ` move to ` == 146 ` /
64+ last-index 145. ** Measured honestly: 139/141 (98.58%)** — the two new tests are
65+ known gaps (deep sub-instruction PPU octal-latch address-corruption timing)
66+ tracked for a dedicated future accuracy campaign (ADR 0030), not blocked on here.
67+ - ** CI cost/time optimization — full suite gated to release branches (PR #233 ).**
68+ The heavy legs (` test-roms ` , ` bench ` , and the full macOS/Windows matrix) now run
69+ only on ` release/* ` PRs + a weekly ` schedule ` drift-net, not on every
70+ intermediate PR; the required correctness gates still run on all PRs.
71+ - ** ` docs/performance.md ` ** gains a v2.0.1 ` full_frame ` measure-first entry
72+ (` nes_run_frame_nestest ` 3.77 ms / 4.42× realtime; ` flowing_palette ` 2.26 ms /
73+ 7.37×), confirmed far under the 16.639 ms NTSC budget. Per the
74+ 3%-plus Criterion-stable + byte-identical bar (v1.7.0 H7 precedent), ** no
75+ optimization was adopted** .
76+ - ** ` docs/adr/0030 ` ** (new) records the octal-latch roadmap: both bounded v2.0.1
77+ attempts — Option 2 (` mc-ppu-bus-addr-hybrid ` , PR #234 ) and Option 1 (the
78+ 2-cycle-ALE draft, PR #236 ) — reach only 139/141 flag-on, empirically confirming
79+ the ALE+Read / Hybrid Addresses fix needs a dedicated Timebase-scale campaign.
80+ ** 139/141 is the honest v2.0.1 baseline.**
81+ - ** ` docs/STATUS.md ` ** feature-flags section: the DMC-abort-probe removal recorded
82+ as done; the new default-off v2.0.1 experiments (` mc-ppu-bus-addr-hybrid ` ,
83+ ADR 0030; ` mmc3-m2-phase-irq ` , ADR 0002) listed among the remaining flags.
84+
4985### Removed
5086
51- - ** Dead ` mc-r1-dmc-abort-probe ` diagnostic feature (v2.0.1 housekeeping). ** The
52- default-off DMC-DMA-abort scheduling probe left over from the v2.0.0 Timebase
53- R-1 work is removed in full: the ` [features] ` declarations in ` rustynes-apu ` ,
54- ` rustynes-core ` , and ` rustynes-test-harness ` ; the gated ` abort_probe ` pub-static
55- atomic-counter module and its ` lib.rs ` re-export; every `# [ cfg(feature =
56- "mc-r1-dmc-abort-probe")] ` increment/dump site in ` rustynes-apu/src/apu.rs` and
57- ` rustynes-core/src/bus.rs ` ; and the probe-only reporting block in the
58- ` scan_dma_abort ` diagnostic bin (the bin itself is retained — its no-features
59- RAM-scan fast-path has standalone value). The flag gated ** only ** diagnostic
60- counters and CSV dumps, never shipped behaviour, so the default build is
61- byte-identical — ** AccuracyCoin holds 139/141, nestest 0-diff** . The
62- ` mmc3-m2-phase-irq ` experiment was evaluated for the same treatment and
87+ - ** Dead ` mc-r1-dmc-abort-probe ` diagnostic feature (v2.0.1 housekeeping, PR
88+ # 237 ). ** The default-off DMC-DMA-abort scheduling probe left over from the
89+ v2.0.0 Timebase R-1 work is removed in full: the ` [features] ` declarations in
90+ ` rustynes-apu ` , ` rustynes- core` , and ` rustynes-test-harness ` ; the gated
91+ ` abort_probe ` pub-static atomic-counter module and its ` lib.rs ` re-export; every
92+ ` #[cfg(feature = "mc-r1-dmc-abort-probe")]` increment/dump site in
93+ ` rustynes-apu/src/apu.rs ` and ` rustynes- core/src/bus.rs` ; and the probe-only
94+ reporting block in the ` scan_dma_abort ` diagnostic bin (the bin itself is
95+ retained — its no-features RAM-scan fast-path has standalone value). The flag
96+ gated ** only ** diagnostic counters and CSV dumps, never shipped behaviour, so the
97+ default build is byte-identical — ** AccuracyCoin holds 139/141, nestest 0-diff** .
98+ The ` mmc3-m2-phase-irq ` experiment was evaluated for the same treatment and
6399 deliberately ** kept** : it gates real alternate MMC3-IRQ-timing behaviour (with
64100 ` #[cfg(not)] ` shipped-path counterparts) and remains tied to the still-open
65101 R1/R2 residual investigation (ADR 0002, by-design-deferred, not closed).
66102
67- ### Changed
103+ ### Dependencies
68104
69- - ** ` docs/performance.md ` ** gains a v2.0.1 ` full_frame ` measure-first entry:
70- the end-to-end headless frame cost is re-measured and confirmed far under the
71- 16.639 ms NTSC budget and against the ≤2 ms/frame target; per the standing
72- > 3%-Criterion-stable + byte-identical bar (v1.7.0 H7 precedent), ** no
73- optimization was adopted** .
74- - ** ` docs/adr/0030 ` ** records that both bounded v2.0.1 AccuracyCoin ALE/hybrid
75- attempts — Option 2 (` mc-ppu-bus-addr-hybrid ` , PR #234 ) and Option 1 (the
76- 2-cycle-ALE draft, PR #236 ) — reached only 139/141 flag-on, empirically
77- confirming the fix needs a dedicated Timebase-scale campaign, not a bounded
78- fork. ** 139/141 is the honest v2.0.1 baseline.**
79- - ** ` docs/STATUS.md ` ** feature-flags section updated: the DMC-abort-probe removal
80- is now recorded as done, and the new default-off v2.0.1 experiments
81- (` mc-ppu-bus-addr-hybrid ` , ADR 0030; ` mmc3-m2-phase-irq ` , ADR 0002) are listed
82- among the genuinely-remaining flags.
105+ - ** uniffi 0.31 → 0.32** (` rustynes-mobile ` + ` rustynes-monetization ` , lockstep),
106+ ** mlua 0.11 → 0.12** (` rustynes-script ` ), ** wgpu/naga 29.0.3 → 29.0.4** (the
107+ in-tier patch), ** cc 1.2.65 → 1.2.66** ; security-advisory surface re-verified
108+ (cargo-deny + cargo-audit). Consolidates and closes Dependabot #226 –#230 .
109+ ** wgpu/naga 30.0.0 deferred** : ` egui-wgpu 0.35 ` pins ` wgpu ^29 ` and egui 0.35 is
110+ the newest release, so the 30 majors cannot resolve until an egui 0.36+ targets
111+ wgpu 30 (tracked follow-up).
112+
113+ ### Notes
114+
115+ - The ` mc-ppu-bus-addr-hybrid ` (Option 2, PR #234 ) octal-latch scaffold ships
116+ ** default-off** and does ** not** yet pass the two new AccuracyCoin tests; with
117+ the flag off the build is byte-identical at 139/141. The full fix (Option 1,
118+ 2-cycle-ALE) is carried forward to the v2.0.2–v2.0.4 "Harbor" cycle (draft PR
119+ #236 , ADR 0030).
83120
84121## [ 2.0.0] - 2026-07-03 - "Timebase" (one-clock master-clock rewrite + Vs. DualSystem)
85122
0 commit comments