RFC: Android Kotlin → Rust/Tauri 2 migration#96
Conversation
Draft RFC for owner review before any bulk conversion. Maps each of the 7 Kotlin files + 3 *.gradle.kts to a Rust/Tauri replacement, calls out the unavoidable JVM-bytecode surface (Service / BroadcastReceiver / AppWidgetProvider), and proposes a 9-PR landing sequence gated on CI-exemption coordination for Tauri-generated Java shims under src-tauri/gen/android/. No Kotlin deleted, no Tauri scaffolding generated — pure planning artefact. Both banned-language CI gates remain red until the sequenced sub-PRs land in order. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Replaced by PR on chore/gossamer-migration-rfc — owner corrected the migration target from Tauri to Gossamer; rewriting under the right branch name. |
|
Two owner decisions for this RFC are now settled — please update the doc accordingly before any sub-PRs:
(Tracked on the neurophone side as #83, which now names gossamer.) Generated by Claude Code |
## Status **DRAFT — RFC only. Awaiting owner review BEFORE any bulk conversion.** No Kotlin deleted, no Gossamer scaffolding generated, no behaviour change. Supersedes #96 (was titled "Tauri 2" — owner correction: Gossamer is the estate target). ## Why `android/` ships 7 Kotlin files + 3 `*.gradle.kts` files, all banned by the Hyperpolymath language policy. Two CI gates permanently red: - `Check for Banned Languages` (`.github/workflows/language-policy.yml:87-94`) - `governance / Language / package anti-pattern policy` (estate-wide) ## What this PR contains A single document — `docs/migrations/RFC-ANDROID-KOTLIN-TO-RUST.adoc` — mapping every Kotlin component to its Gossamer replacement and proposing a 9-PR landing sequence. ## Component mapping (one-line summary) | Kotlin file | Replacement | |---|---| | `MainActivity.kt` | `NeurophoneMainActivity extends GossamerActivity` | | `NeurophoneService.kt` | Hand-written Java `Service` shim → JNI into Rust | | `BootReceiver.kt` | Hand-written Java `BroadcastReceiver` shim → JNI | | `NativeLib.kt` | Delete; lives in `crates/neurophone-android/src/lib.rs` | | `NeurophoneAppWidget.kt` | Hand-written Java `AppWidgetProvider` shim | | `NeurophoneWidgetActions.kt` | Hand-written Java `BroadcastReceiver` shim | | `NeurophoneWidgetConfigureActivity.kt` | Java `Activity` shim (or drop) | | `*.gradle.kts` | Groovy `*.gradle` (matches Gossamer upstream) | ## Key structural finding **Gossamer Android is webview-only today.** ROADMAP Phase 3 (Mobile) lists Android as *Partially Implemented* — only `GossamerActivity` + `GossamerBridge` exist upstream. The 7 platform-integration surfaces neurophone needs (service, widget, receivers, sensors, intent dispatch, prefs, deep-links) have **no upstream Gossamer support and no open Gossamer issues**. **Recommendation:** build all 7 downstream in neurophone's own `android/` tree as small Java shims that JNI immediately into Rust. Don't block neurophone on Gossamer upstream PRs. Estimated total shim surface: < 250 LoC of Java vs. current 926 LoC of Kotlin. ## Estate precedent - `panll` migrated `src-tauri/` → `src-gossamer/` (commit `598d537`, ADR-0001 in `b935727`). Webview UI unchanged; swapped `tauri` crate for `gossamer-rs`, `tauri.conf.json` for `gossamer.conf.json`, `cargo tauri build` for `deno task build` invoking the `gossamer` CLI. - panll is **desktop only** — its migration did not exercise foreground service or home-screen widget surfaces; neurophone will be the first. ## Sub-PR sequence (proposed) 1. **This PR** — RFC only. 2. CI exemption for `android/**/*.java` (coordinated with `hyperpolymath/standards`). 3. Gossamer scaffolding: `gossamer-rs` workspace dep, `gossamer.conf.json`, `NeurophoneMainActivity` Java shim loading placeholder HTML. 4. Port `NativeLib` Kotlin → `crates/neurophone-android/src/lib.rs`. 5. Port `NeurophoneService` → Java shim + Rust impl. 6. Port `BootReceiver`. 7. Port widget triple (provider / actions / configure). 8. AffineScript UI compiled to JS, loaded by Gossamer webview. 9. Delete legacy Kotlin `android/` tree — both CI gates green. PRs 2 & 3 sequenced; 4–7 parallelizable after 3; 8 needs 4; 9 gated on all. ## Open questions for owner 1. **CI exemption scope** — estate-wide via `hyperpolymath/standards` or neurophone-local? Linchpin question. 2. **Estate governance** — who owns the cross-repo anti-pattern policy callable in standards? 3. **Widget config sacrifice** — acceptable to drop the configure activity? 4. **Gradle DSL** — Groovy `*.gradle` (matches Gossamer upstream) or keep Kotlin `*.gradle.kts` under a separate exemption? 5. **Hardware test plan** — Oppo Reno 13 vs emulator + Termux? 6. **Upstream contribution** — build shims neurophone-local, or factor a `gossamer-android-services` companion as we go? ## Constraints honoured - All new files MPL-2.0 SPDX. - No new GitHub Actions added. - No Deno/npm/TypeScript changes. ## Test plan - [x] RFC document renders as AsciiDoc. - [ ] Owner reviews component mapping for completeness. - [ ] Owner picks CI-exemption scope (open Q1). - [ ] Owner resolves Gradle DSL choice (open Q4). - [ ] Sub-PR #2 (CI exemption) opens once approved. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Status
DRAFT — RFC only. Awaiting owner review BEFORE any bulk conversion.
No Kotlin deleted, no Tauri scaffolding generated, no behaviour change.
Why
android/ships 7 Kotlin files + 3*.gradle.ktsfiles, all banned by theHyperpolymath language policy. This keeps two CI gates permanently red:
Check for Banned Languages(.github/workflows/language-policy.yml:87-94)governance / Language / package anti-pattern policy(estate-wide)What this PR contains
A single document —
docs/migrations/RFC-ANDROID-KOTLIN-TO-RUST.adoc— that:Activity,Service,BroadcastReceiver,AppWidgetProvider— that Android instantiates byclass name and that pure Rust cannot satisfy.
src-tauri/gen/android/, with a CI exemption analogous tonode_modules/) and explicitly rejects Paths B (drop the widget) andC (JVM bytecode emission from Rust).
Component mapping (one-line summary)
MainActivity.ktMainActivity+ AffineScript webview UINeurophoneService.ktServiceshim → JNI into RustBootReceiver.ktBroadcastReceivershim → JNINativeLib.ktcrates/neurophone-android/src/lib.rsNeurophoneAppWidget.ktAppWidgetProvidershimNeurophoneWidgetActions.ktBroadcastReceivershimNeurophoneWidgetConfigureActivity.ktActivityshim (or drop)*.gradle.ktsgen/android/Sub-PR sequence (proposed)
src-tauri/gen/android/(coordinated withhyperpolymath/standards).cargo tauri android initscaffolding.NativeLibKotlin →crates/neurophone-android/src/lib.rs.NeurophoneService.BootReceiver.activity_main.xml).android/tree — both CI gates green.PRs 2 & 3 sequenced; 4–7 parallelizable after 3; 8 needs 4; 9 gated on all.
Open questions for owner
src-tauri/gen/android/?callable in
hyperpolymath/standards?PMPL-1.0-or-later, local hook expectsMPL-2.0. Pick canonical before sub-PRs.Constraints honoured in this PR
flagged in the RFC's "Open questions". See open question chore(deps): update reqwest requirement from 0.11 to 0.12 #6.
Test plan
🤖 Generated with Claude Code