Repository navigation
release: cut v2.0.4 "Harbor" (Android release candidate — host-side RC scaffolding on the byte-identical v2.0.3 core) - #241
Merged
Conversation
There was a problem hiding this comment.
Pull request overview
Cuts the v2.0.4 “Harbor” Android release-candidate by bumping workspace/Android versions and adding host-side scaffolding (release signing fallback + debug-only StrictMode), plus release documentation and Play Console fastlane metadata. No emulation-core changes are included (intended byte-identity with v2.0.3).
Changes:
- Bump workspace version to 2.0.4 (Cargo.toml + Cargo.lock) and Android versionCode/versionName to 20004/2.0.4.
- Android RC scaffolding: release signing config now always resolves (upload keystore when present, else debug signing) and install debug-only StrictMode early in
MainActivity. - Add version-controlled fastlane Play listing metadata (en-US/es-ES) and update release docs/status/roadmaps.
Reviewed changes
Copilot reviewed 19 out of 20 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| to-dos/ROADMAP.md | Updates “Current release” status block to v2.0.4 and shifts v2.0.3 to preceding. |
| to-dos/plans/v2.0.x-mobile-finalization-plan.md | Reconciles v2.0.4 plan bullet to reflect host-side RC scaffolding vs on-device maintainer steps. |
| to-dos/plans/v2.0.4-android-rc-plan.md | Adds a dedicated v2.0.4 Android RC sprint plan doc. |
| fastlane/metadata/android/es-ES/title.txt | Adds Spanish Play title. |
| fastlane/metadata/android/es-ES/short_description.txt | Adds Spanish short description. |
| fastlane/metadata/android/es-ES/full_description.txt | Adds Spanish full description. |
| fastlane/metadata/android/es-ES/changelogs/20004.txt | Adds Spanish changelog for versionCode 20004. |
| fastlane/metadata/android/en-US/title.txt | Adds English Play title. |
| fastlane/metadata/android/en-US/short_description.txt | Adds English short description. |
| fastlane/metadata/android/en-US/full_description.txt | Adds English full description. |
| fastlane/metadata/android/en-US/changelogs/20004.txt | Adds English changelog for versionCode 20004. |
| docs/STATUS.md | Updates current release block to v2.0.4 and records RC scope. |
| CHANGELOG.md | Adds v2.0.4 release notes section (host/Android-only RC scaffolding). |
| Cargo.toml | Workspace version bump 2.0.3 → 2.0.4. |
| Cargo.lock | Propagates workspace crate versions to 2.0.4. |
| android/app/src/main/java/com/doublegate/rustynes/MainActivity.kt | Installs DebugStrictMode at the start of onCreate. |
| android/app/src/main/java/com/doublegate/rustynes/Crash.kt | Adds DebugStrictMode implementation (debug-only StrictMode policies). |
| android/app/proguard-rules.pro | Records the v2.0.4 RC keep-set audit outcome in comments. |
| android/app/build.gradle.kts | Bumps Android versionCode/versionName; adds release signing-config fallback logic. |
| .github/release-notes/v2.0.4.md | Adds GitHub Release notes for v2.0.4. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
doublegate
added a commit
that referenced
this pull request
Jul 9, 2026
…copilot #241) Resolves all 9 copilot review threads on PR #241: the es-ES fastlane store copy (short_description, full_description, changelogs/20004) was written without Spanish diacritics, so the customer-facing Play listing read as misspelled Spanish. Restored the correct orthography throughout — precisión, núcleo, emulación, rápido, versión, público, código, características, batería, línea, teléfonos, diseños, etc. — and tidied two phrasings to the idiomatic form ("de ciclo exacto", "versión candidata"). Play field limits still respected (short <= 80, full <= 4000, changelog <= 500). No functional/code change; en-US copy unaffected. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Contributor
|
Warning Gemini encountered an error creating the review. You can try again by commenting |
…C scaffolding on the byte-identical v2.0.3 core)
The fourth release of the v2.0.x "Harbor" mobile-finalization train, and the
Android release-candidate milestone. This is a HOST / ANDROID-ONLY cut: the
cycle-accurate emulation core is unchanged and byte-identical to v2.0.3 —
AccuracyCoin still 141/141 (100.00%), nestest 0-diff, the deterministic
`#![no_std]` chip stack untouched — so no accuracy / save-state / determinism
number moves. What lands is the release-candidate scaffolding a maintainer needs
to stage the Android app onto a Play Console testing track, with every on-device
step explicitly flagged for the maintainer / v2.0.9. The `foss`
(F-Droid / GitHub-sideload) flavor stays behaviour-identical.
Version bump
------------
Workspace `2.0.3 -> 2.0.4` (cascades version-only through Cargo.lock — 18 crate
entries, no dependency graph change). Android `versionCode 20003 -> 20004`,
`versionName "2.0.3" -> "2.0.4"`: the monotonic versionCode is the Play upload
ordinal for the internal/closed testing (RC) track.
Release signing wired with a graceful debug-signing fallback
------------------------------------------------------------
The `release` build type now ALWAYS resolves a signing config instead of leaving
the artifact unsigned when the upload keystore is absent. When the maintainer
secret is present (a gitignored `keystore.properties` file or the
`RUSTYNES_UPLOAD_*` env vars, CI-injected, never committed) the release is signed
with the real upload key so the produced AAB is store-uploadable; when ABSENT (a
keyless CI or local RC build) it falls back to the debug signing config so
`assemble{Foss,Play}Release` still yields an INSTALLABLE artifact for smoke
testing. Debug-signed is never shippable (Play App Signing rejects the debug key),
so this fallback only ever produces a locally-installable RC artifact — the real
keystore path is what a store upload uses. `keystore.properties` / `*.jks` /
`*.keystore` were already gitignored since v2.0.3 (verified, no change needed).
The signing block + `buildTypes.release` evaluate at Gradle configuration time,
which the green foss/play compile exercised end-to-end.
Crash / ANR hardening (DebugStrictMode)
---------------------------------------
A debug-only StrictMode installer (`DebugStrictMode` in `Crash.kt`, shared
`src/main` across foss+play) surfaces the two most common ANR / jank sources
during development: thread policy (main-thread disk / network I/O + custom slow
calls — the single most dangerous ANR class for an emulator that must never block
the UI thread on the native bridge) and VM policy (leaked `Closeable`s / SQLite
cursors / registered receivers, relevant to the wgpu SurfaceView + UniFFI object
graph spanning the JNI boundary). It is log-only (never penaltyDeath, so a false
positive can never crash a dev build) and guarded on `BuildConfig.DEBUG`, so a
release / RC / store build constructs no policy and carries zero runtime cost or
behavioural change. Installed as the first statement of `MainActivity.onCreate`
so launch-path violations are caught too. Complements the existing opt-in,
privacy-first `CrashReporter` (uncaught-exception handler chaining to the previous
default handler; unchanged). The authoritative crash-free-rate + ANR measurement
is an on-device gate (real hardware / Play vitals) and is a maintainer / v2.0.9
step; this installer only makes the host build fail loud so those numbers start
clean.
R8 / ProGuard final hardening review
------------------------------------
Re-audited the release keep set for the RC and confirmed it COMPLETE — the UniFFI
(rustynes_mobile + monetization) + JNA surface, the NativeRenderer JNI seam, and
the play-flavor Google / AppLovin / RevenueCat SDKs (added in v2.0.3) are all
covered. The v2.0.4 host additions need no new keeps by construction:
DebugStrictMode is stripped from release (BuildConfig.DEBUG-guarded), CrashReporter
is reached by a direct Kotlin call, and the ResumeWidgetReceiver / ResumeTileService
are manifest-declared components R8 keeps automatically. No existing keep was
loosened; the audit outcome is recorded in `proguard-rules.pro`.
Fastlane / Play Console listing metadata (version-controlled)
-------------------------------------------------------------
A `fastlane/metadata/android/{en-US,es-ES}/` tree — title / short + full
description / `changelogs/20004.txt` — stages the store listing as tracked source
a maintainer uploads via fastlane / the Play Console (no upload is performed).
Copy is accurate to the app (a cycle-accurate NES emulator, bring-your-own-ROMs,
open source) and flags the RC / testing-track status; fields respect Play's limits
(title <= 30, short <= 80, full <= 4000, changelog <= 500).
Docs
----
CHANGELOG.md `[2.0.4]` (Added/Changed; fresh empty `[Unreleased]`); docs/STATUS.md
gains a v2.0.4 current-release block (v2.0.3 demoted to "The preceding release");
to-dos/ROADMAP.md status updated; `.github/release-notes/v2.0.4.md` authored;
to-dos/plans/v2.0.4-android-rc-plan.md authored (host-done vs maintainer/on-device
split + plan reconciliation: ADR 0030 "Option 1" already landed in v2.0.3, so
v2.0.4 is the pure Android RC closeout); the mobile-finalization plan's v2.0.4
bullet marks the host-doable items done and the on-device ones maintainer/v2.0.9.
Deferred (maintainer / on-device, per the plan)
-----------------------------------------------
The actual Play Console listing upload, signing with the real keystore, the
internal/closed testing track, the crash-free-rate + ANR gate on real hardware,
live monetization runtime verification, on-device Baseline Profile regeneration,
and the per-feature `feature_enabled` gate migration (the existing Play-Billing
LicenseManager freemium gates are intentionally left as-is — rewiring them to the
monetization façade is a v2.0.9 product decision needing on-device validation).
Verification (host gates, all green)
------------------------------------
- `cargo check --workspace` clean (2m22s); Cargo.lock diff is version-only.
- `cargo fmt --all --check` clean.
- `./gradlew :app:compileFossDebugKotlin :app:compilePlayDebugKotlin` BUILD
SUCCESSFUL (both flavors; the two showAd() deprecation warnings are pre-existing
v2.0.3 monetization glue, not from this change). assembleFossRelease not re-run
here (10m+ compile alone) — relied on the green compile + config-time validation
of the signing block + CI.
- `pre-commit run markdownlint --all-files` Passed.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…copilot #241) Resolves all 9 copilot review threads on PR #241: the es-ES fastlane store copy (short_description, full_description, changelogs/20004) was written without Spanish diacritics, so the customer-facing Play listing read as misspelled Spanish. Restored the correct orthography throughout — precisión, núcleo, emulación, rápido, versión, público, código, características, batería, línea, teléfonos, diseños, etc. — and tidied two phrasings to the idiomatic form ("de ciclo exacto", "versión candidata"). Play field limits still respected (short <= 80, full <= 4000, changelog <= 500). No functional/code change; en-US copy unaffected. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The accent-corrected es-ES changelog reached 565 chars (Spanish is more verbose); Play rejects a changelog over 500. Tightened to mirror the en-US length while keeping correct orthography and all the RC points. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
doublegate
force-pushed
the
feat/v2.0.4-android-rc
branch
from
July 9, 2026 01:55
54e9eb3 to
896d093
Compare
… resources Completes the Android half of the "host-localizable bridge warnings" carryover (target v2.0.2-v2.0.4, DEFERRED-AND-CARRYOVER-FEATURES.md). v2.0.3 added the stable HostWarning code/enum + drain_warning_codes() to the rustynes-mobile bridge; this wires the Android host to actually consume it. Previously the bridge queued a HostWarning::PreTimebaseMovie on a pre-v2.0.0 .rnm load, but the Android app never drained it -- so the ADR-0028 movie-epoch notice was silently dropped on-device (grep confirmed no drain call anywhere in the app). Now, after a successful moviePlay in MainActivity's SAF picker, the app drains the warning CODES and maps each through a device-locale Android string resource (host_warning_pre_timebase_movie, en + es) rather than the bridge's baked-in English, surfacing it via the existing status line. The `when` over HostWarning is exhaustive, so a future bridge warning is a compile error here until it is localized -- the intended end state for keeping the frontends in locale parity without embedding locale text in the deterministic-adjacent core bridge. Scope: Android host only (src/main -> both foss + play). No core / bridge change (HostWarning + drain_warning_codes already shipped in v2.0.3), so AccuracyCoin stays 141/141 byte-identical. The iOS half (Localizable) lands in the v2.0.5-v2.0.8 iOS train; the DEFERRED item is updated to [~] (bridge + Android done, iOS remaining). Verified: ./gradlew :app:compileFossDebugKotlin :app:compilePlayDebugKotlin BUILD SUCCESSFUL (resources parsed, R.string resolves, both flavors compile). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
v2.0.4 "Harbor" — Android release candidate (host-side RC scaffolding)
The fourth release of the v2.0.x "Harbor" train — the Android release candidate. The emulation core is byte-identical to v2.0.3 (AccuracyCoin still 141/141, no
crates/rustynes-{cpu,ppu,apu,mappers,core}changes); this is a host/Android-only RC cut that stages everything a maintainer needs to push the RC to a Play Console testing track.Host-side RC work (this PR)
2.0.3 → 2.0.4; AndroidversionCode 20003 → 20004,versionName "2.0.4".buildTypes.releasenow always resolves a signing config — theuploadkeystore (keystore.properties /RUSTYNES_UPLOAD_*env) when present, else a graceful fallback to debug signing so CI + local builds without the secret still assemble. Keystore files stay gitignored (maintainer secret).DebugStrictMode(thread + VM policy, log-only,BuildConfig.DEBUG-guarded, release-stripped), installed first inMainActivity.onCreate. The existing opt-inCrashReporteralready chains the uncaught-exception handler (unchanged).fastlane/metadata/android/{en-US,es-ES}/title / short / full description +changelogs/20004.txt, staged as version-controlled Play listing (maintainer uploads).[2.0.4], STATUS (single source of truth — new current-release block), ROADMAP,.github/release-notes/v2.0.4.md,to-dos/plans/v2.0.4-android-rc-plan.md, finalization-plan v2.0.4 bullet.Flagged for the maintainer / on-device (v2.0.9)
Play Console AAB upload; signing with the real keystore; internal/closed testing track; crash-free-rate + ANR gate on real hardware; live monetization runtime; on-device Baseline Profile regen; and the deferred per-feature
feature_enabledgate migration (existingLicenseManagerfreemium gates left as-is — a product decision needing runtime validation).Verification
cargo check --workspaceexit 0 (lock diff version-only);cargo fmt --all --checkclean;./gradlew :app:compileFossDebugKotlin :app:compilePlayDebugKotlinBUILD SUCCESSFUL (both flavors; signing-fallback validated at configuration time);pre-commit run markdownlintpassed.🤖 Generated with Claude Code