Skip to content

Commit 714437e

Browse files
committed
Release v1.8.185 — drop :lib:native placeholder + libnative Rust scaffold
The :lib:native Gradle module and the libnative/dummy/ Rust scaffold had been disabled in settings.gradle.kts since 2025 (commented-out include). Nothing in :app consumed it — the only reference was a commented-out import in FlorisApplication.kt and a paired flogError log that fired on every cold start announcing the module's disablement. The placeholder promised "native code can land in :app" while the project's architectural direction had firmly settled on the opposite: native runtimes for optional capabilities (LiteRT-LM, whisper.cpp, librime, Bergamot, ML Kit, Vosk) ship as out-of-tree signed addon APKs per the AddonContract.Action. REGISTER_* enrolment contract, not in the base APK. Changes: - git rm -rf lib/native libnative — 8 tracked files under lib/native/ + 3 under libnative/dummy/ - settings.gradle.kts: removed the //include(":lib:native") line - FlorisApplication.kt: removed commented-out import + cold-start log - ARCHITECTURE.md / PROJECT_CONTEXT.md / README.md: replaced module-layout notes with the addon-only-native-runtime explanation - ROADMAP.md §2 + §0 v5.2 follow-up: refreshed both :lib:native mentions - docs/REPRODUCIBLE_BUILDS.md: Rust-toolchain pin row's annotation updated to "dormant pin retained for future out-of-tree native addons"; pin itself stays (no harm; Gradle doesn't download unless referenced) - docs/THREAT_MODEL.md §3.8: replaced the misleading "the only native code is lib/native (Rust ICU helpers)" claim with the accurate "base APK ships zero native code as of v1.8.185" - .github/workflows/android.yml: 16 KB alignment-guard comment updated Closes RESEARCH_FEATURE_PLAN.md EI11. Verification: - grep -rn "lib/native\|libnative\|:lib:native" — matches now only in .ai/research/2026-05-17/ (frozen snapshot per AGENTS.md) + v1.8.185 changelog entries - bash scripts/check-fastlane-metadata.sh -> OK (versionCode 1985) - bash scripts/check-repo-hygiene.sh -> OK - ls lib/ -> android, color, compose, kotlin, snygg (5 surviving) - Gradle reload + build deferred to maintainer host per CLAUDE.md; dropped module had no consumers in :app or :benchmark
1 parent e3e71bc commit 714437e

24 files changed

Lines changed: 92 additions & 479 deletions

File tree

.github/workflows/android.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,10 @@ jobs:
106106
# ROADMAP §7 Next-12.4 — 16 KB memory-page alignment guard. Per Google
107107
# Play's Nov 1 2025 cutoff [STD-A15-16KB], every native .so shipped on
108108
# a target-Android-15+ APK must be 16 KB ELF-segment aligned. SwiftFloris
109-
# currently ships zero native libs (the libnative/ module is disabled),
110-
# so this check is a forward-looking guard: as soon as Next-2 (whisper.cpp),
109+
# currently ships zero native libs in :app (native runtimes for optional
110+
# capabilities live in out-of-tree signed addon APKs per the AddonContract
111+
# enrolment path), so this check is a forward-looking guard: as soon as
112+
# Next-2 (whisper.cpp),
111113
# N1.2 (CleverKeys ONNX), L1 (LiteRT-LM), or L7 (MCP bridge) bring native
112114
# code back in, the gate catches a 4 KB regression at PR time instead of
113115
# at Play upload time. If no .so files exist in the APK the check is a

ARCHITECTURE.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,12 @@ The active Gradle modules are declared in `settings.gradle.kts`.
3333
| `:benchmark` | AndroidX Macrobenchmark module plus adb-driven benchmark harness target |
3434

3535
`:benchmark` is included in settings for Macrobenchmark and adb performance
36-
harnesses. `:lib:native` remains present on disk but inactive until a native
37-
addon/runtime slice intentionally revives it.
36+
harnesses. Native runtimes for optional capabilities (LiteRT-LM smart compose,
37+
Bergamot offline NMT, librime CJK input, ML Kit Digital Ink handwriting, Vosk
38+
voice) ship as out-of-tree signed addon APKs per the addon enrolment contract
39+
(`AddonContract.Action.REGISTER_*`); the base APK does not carry a native
40+
module. The previous `:lib:native` placeholder + `libnative/` Rust scaffold
41+
were dropped in v1.8.185.
3842

3943
## Runtime Entrypoints
4044

CHANGELOG.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,56 @@
22

33
All SwiftFloris release history is consolidated here. This replaces the former root-level `RELEASE_NOTES_v*.md` file-per-release pattern.
44

5+
<a id="v1.8.185"></a>
6+
## v1.8.185
7+
8+
Released: 2026-05-25
9+
10+
### Drop the `:lib:native` placeholder + `libnative/` Rust scaffold (RESEARCH_FEATURE_PLAN.md EI11)
11+
12+
The `:lib:native` Gradle module and its sibling `libnative/dummy/` Rust scaffold had been disabled in `settings.gradle.kts` since 2025 (`//include(":lib:native")`). The module shipped one Kotlin file (`external fun dummyAdd(a: Int, b: Int): Int`), a Rust `lib.rs` with the matching JNI implementation, a CMakeLists.txt, an empty Android manifest, and a `Cargo.toml`. Nothing in `:app` consumed it — the only reference in production code was a commented-out import in `FlorisApplication.kt:57` and a corresponding commented-out `flogError { "dummy result: ${dummyAdd(3,4)}" }` log at line 138 with a paired `flogError { "native module disabled, skipping dummy test" }` warning that surfaced on every cold start.
13+
14+
The placeholder was originally retained as a roadmap surface for future native-in-`:app` work, but the project's architectural direction has firmly settled: native runtimes for optional capabilities (LiteRT-LM smart-compose per L1.1a, whisper.cpp per Next-2, librime CJK per L3, Bergamot offline NMT per L2.1a, ML Kit Digital Ink per Next-4.2a, Vosk voice per F8) ship as out-of-tree signed addon APKs via the `AddonContract.Action.REGISTER_*` enrolment contract. The base APK does not, and is not intended to, carry a native module. A dormant placeholder that promises otherwise was misleading to contributors.
15+
16+
### Changes
17+
18+
- **Deleted the `:lib:native` module** — `git rm -rf lib/native libnative` removed 8 tracked files under `lib/native/` (`build.gradle.kts`, `src/main/AndroidManifest.xml`, `src/main/kotlin/org/florisboard/libnative/test.kt`, `src/main/rust/CMakeLists.txt`, `src/main/rust/Cargo.toml`, `src/main/rust/Cargo.lock`, `src/main/rust/src/lib.c`, `src/main/rust/src/lib.rs`) plus 3 tracked files under `libnative/dummy/` (`Cargo.toml`, `Cargo.lock`, `src/lib.rs`). The working-tree `lib/native/build/` cache was deleted on disk but was never gitignored at the directory level; the v1.8.174 hygiene script already catches future tracked-build-output regressions.
19+
- **`settings.gradle.kts`** — removed the `//include(":lib:native") // Skip Rust native - not needed for basic keyboard` line at line 51. The trailing `include(":lib:snygg")` line now lands immediately after `include(":lib:kotlin")`.
20+
- **`FlorisApplication.kt`** — removed the commented-out `import org.florisboard.libnative.dummyAdd` line and the corresponding `flogError { "native module disabled, skipping dummy test" }` + `// Originally: flogError { "dummy result: ${dummyAdd(3,4)}" }` block. Both fired on every cold start, polluting `adb logcat` with a noise marker for a non-existent feature.
21+
- **`ARCHITECTURE.md` Module Layout** — replaced the `:lib:native remains present on disk but inactive` paragraph with a forward-looking note explaining that native runtimes ship as out-of-tree signed addon APKs.
22+
- **`PROJECT_CONTEXT.md` §4 module layout** — removed the `:lib:native … placeholder for future native add-ons (commented out)` line and added the addon-only-native-runtime explanation.
23+
- **`README.md` Module Layout** — same change for the user-facing README.
24+
- **`ROADMAP.md` §2 State of the Repo + §0 v5.2 follow-up** — updated both mentions of `:lib:native` to reflect the drop, citing v1.8.185 + the addon-only enrolment contract.
25+
- **`docs/REPRODUCIBLE_BUILDS.md`** — the Rust toolchain pin row's annotation moved from "only used by `lib/native` (currently disabled)" to a forward-looking note explaining the pin is retained for future out-of-tree native addons that may use the same toolchain. The pin itself stays (no harm in keeping the toolchain version recorded; Gradle does not download it unless a module references it).
26+
- **`docs/THREAT_MODEL.md` §3.8 Auditability** — replaced the "the only native code is `lib/native` (Rust ICU helpers, source visible)" claim with the more accurate "the base APK ships zero native code as of v1.8.185" framing. The auditability surface is still strong; the prior sentence was misleading anyway because `lib/native` shipped a Rust JNI stub that returned `a + b`, not "ICU helpers."
27+
- **`.github/workflows/android.yml`** — updated the 16 KB native-library guard comment from `the libnative/ module is disabled` to `native runtimes for optional capabilities live in out-of-tree signed addon APKs per the AddonContract enrolment path`. The check itself is unchanged (it remains a forward-looking guard for the day a release variant brings native code in).
28+
29+
### Verification
30+
31+
- `grep -rn "lib/native\|libnative\|:lib:native" .` returns matches only in `.ai/research/2026-05-17/` (frozen historical snapshot per `AGENTS.md`) plus the v1.8.185 entries in CHANGELOG, RESEARCH_FEATURE_PLAN, and PROJECT_CONTEXT/ARCHITECTURE/ROADMAP that reference the drop.
32+
- `bash scripts/check-repo-hygiene.sh` → OK.
33+
- `bash scripts/check-fastlane-metadata.sh` → OK (versionCode 1985).
34+
- `ls lib/` returns the 5 surviving modules: `android`, `color`, `compose`, `kotlin`, `snygg`. `ls libnative` returns `No such file or directory`.
35+
- Gradle reload + build deferred to maintainer host per `CLAUDE.md`. The dropped module had no consumers in `:app` or `:benchmark`, so dependency graph remains clean.
36+
37+
### Files Touched
38+
39+
- `lib/native/` (deleted, 8 tracked files + working-tree `build/` cache)
40+
- `libnative/` (deleted, 3 tracked files)
41+
- `settings.gradle.kts` (removed commented-out include)
42+
- `app/src/main/kotlin/dev/patrickgold/florisboard/FlorisApplication.kt` (removed dead import + log)
43+
- `ARCHITECTURE.md`
44+
- `PROJECT_CONTEXT.md`
45+
- `README.md`
46+
- `ROADMAP.md` (two mention sites refreshed)
47+
- `docs/REPRODUCIBLE_BUILDS.md`
48+
- `docs/THREAT_MODEL.md`
49+
- `.github/workflows/android.yml` (comment update only)
50+
- `fastlane/metadata/android/en-US/changelogs/1985.txt` (new)
51+
- `gradle.properties` (versionCode 1984→1985, versionName 1.8.184→1.8.185)
52+
- `CHANGELOG.md` (this section)
53+
- `RESEARCH_FEATURE_PLAN.md` (tick EI11)
54+
555
<a id="v1.8.184"></a>
656
## v1.8.184
757

PROJECT_CONTEXT.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -535,9 +535,16 @@ lib/compose — Compose helpers
535535
lib/kotlin — pure-Kotlin utilities
536536
lib/snygg — Snygg theme engine
537537
:benchmark — Macrobenchmark + adb benchmark harness (active in settings)
538-
:lib:native — placeholder for future native add-ons (commented out)
539538
```
540539

540+
Native runtimes for optional capabilities (LiteRT-LM, Bergamot, librime, ML
541+
Kit Digital Ink, Vosk) ship as out-of-tree signed addon APKs via the addon
542+
enrolment contract, not as a `:lib:native` module in the base APK. The
543+
prior `:lib:native` placeholder and `libnative/` Rust scaffold were dropped
544+
in v1.8.185 (RESEARCH_FEATURE_PLAN.md EI11) since no addon was ever going
545+
to consume them and they confused contributors about whether native code
546+
was permitted in `:app`.
547+
541548
`app/src/main/kotlin/dev/patrickgold/florisboard/` is the work tree. Full
542549
subsystem map in
543550
[.ai/research/2026-05-17/STATE_OF_REPO.md §5](.ai/research/2026-05-17/STATE_OF_REPO.md).

README.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# SwiftFloris
22

3-
![Version](https://img.shields.io/badge/version-v1.8.184-blue) ![License](https://img.shields.io/badge/license-Apache%202.0-green) ![Platform](https://img.shields.io/badge/platform-Android%208.0+-orange) ![Network](https://img.shields.io/badge/network-none-lightgrey) ![SwiftKey migration](https://img.shields.io/badge/SwiftKey%20migration-window%20closes%202026--05--31-red)
3+
![Version](https://img.shields.io/badge/version-v1.8.185-blue) ![License](https://img.shields.io/badge/license-Apache%202.0-green) ![Platform](https://img.shields.io/badge/platform-Android%208.0+-orange) ![Network](https://img.shields.io/badge/network-none-lightgrey) ![SwiftKey migration](https://img.shields.io/badge/SwiftKey%20migration-window%20closes%202026--05--31-red)
44

55
**SwiftFloris** is a privacy-first Android keyboard, forked from FlorisBoard and pushed toward SwiftKey-class multilingual typing without the cloud. It ships under Apache-2.0, holds no `INTERNET` permission, and binds zero accounts.
66

@@ -153,9 +153,12 @@ lib/compose — Compose helpers
153153
lib/kotlin — pure-Kotlin utilities
154154
lib/snygg — Snygg theme engine
155155
:benchmark — Macrobenchmark + adb benchmark harness (active in settings)
156-
:lib:native — placeholder for future native add-ons (commented out)
157156
```
158157

158+
Native runtimes for optional capabilities (LiteRT-LM, Bergamot, librime, ML
159+
Kit Digital Ink, Vosk) ship as out-of-tree signed addon APKs through the
160+
addon enrolment contract, not as a `:lib:native` module in the base APK.
161+
159162
The IME's main work lives under `app/src/main/kotlin/dev/patrickgold/florisboard/ime/{keyboard,nlp,theme,ext,emoji,mcp,voice,bidi,dictionary,kenlm}`.
160163

161164
## Building

RESEARCH_FEATURE_PLAN.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -876,8 +876,8 @@ The roadmap below is **additive** to [`ROADMAP.md`](ROADMAP.md) and [`IMPROVEMEN
876876
- [ ] **P3** — F13 — Cross-platform desktop "SwiftFloris dictionary export" CLI
877877
- Touches: out-of-tree `swiftfloris-desktop-bridge/`
878878

879-
- [ ] **P3** — EI11 — Drop the `:lib:native` placeholder module
880-
- Touches: `settings.gradle.kts`, `lib/native/`, `ARCHITECTURE.md`
879+
- [x] **P3** — EI11 — Drop the `:lib:native` placeholder module**shipped v1.8.185 (2026-05-25)**
880+
- Removed `lib/native/` (8 tracked files), `libnative/dummy/` (3 tracked files), the `//include(":lib:native")` line in `settings.gradle.kts`, and the dead `flogError { "native module disabled, skipping dummy test" }` cold-start log in `FlorisApplication.kt`. Updated ARCHITECTURE.md / PROJECT_CONTEXT.md / README.md / ROADMAP.md / THREAT_MODEL.md / REPRODUCIBLE_BUILDS.md / android.yml to reflect the addon-only path for native runtimes.
881881

882882
---
883883

ROADMAP.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1045,7 +1045,7 @@ GIF keyboard via Tenor/Giphy · Bing search bar · Microsoft account sync · in-
10451045

10461046
**Stack:** Kotlin 2.3.21 · Compose BOM 2026.05.00 · Material 3 + material-kolor · AGP 9.2.1 · Gradle 9.5.1 · JDK 17 · minSdk 26 · targetSdk/compileSdk 36 · Room 2.8.4 · SQLCipher 4.16.0 · Tink Android 1.21.0 · coroutines 1.11.0 · KSP 2.3.8 · ZXing 3.5.4 · AboutLibraries 14.2.0 · Kotest 6.1.11 · Roborazzi 1.60.0 plugin active with `:app:recordRoborazziDebug` / `:app:verifyRoborazziDebug` tasks · Robolectric 4.16.1 · Crowdin translation pipeline · no `INTERNET` permission in the manifest.
10471047

1048-
**Modules:** `:app`, `:benchmark`, and `lib/{android,color,compose,kotlin,snygg}` are included in `settings.gradle.kts`. `:benchmark` is active again for AndroidX Macrobenchmark and adb-driven first-render, first-suggestion, dictionary-load, candidate-row recomposition, theme-switch, and backup/restore evidence; `:lib:native` is still commented out. Treat `:lib:native` as a roadmap surface, not a production module, until settings + CI intentionally wire it back in.
1048+
**Modules:** `:app`, `:benchmark`, and `lib/{android,color,compose,kotlin,snygg}` are included in `settings.gradle.kts`. `:benchmark` is active again for AndroidX Macrobenchmark and adb-driven first-render, first-suggestion, dictionary-load, candidate-row recomposition, theme-switch, and backup/restore evidence. The previous `:lib:native` placeholder and `libnative/` Rust scaffold were dropped in v1.8.185 (per `RESEARCH_FEATURE_PLAN.md` EI11); native runtimes for optional capabilities ship as out-of-tree signed addon APKs per the `AddonContract.Action.REGISTER_*` enrolment contract, not inside the base APK.
10491049

10501050
**Source size:** 624+ tracked Kotlin files repo-wide, with the main IME work concentrated in `app/src/main/kotlin/dev/patrickgold/florisboard/ime/{keyboard,nlp,theme,ext,emoji,mcp,voice,bidi,dictionary,kenlm,calendar}`. The v1.8.40 release line reported **998 unit tests** at HEAD, and v1.8.41-v1.8.69 pushed the suite past **1000+ unit tests** with targeted gates around apostrophe auto-return, password-field popup suppression, Roborazzi task wiring, Kotlin reproducibility drift, Android 17 IME visibility restore, split rendering, bundled theme contrast/registration, calendar quick-insert formatting/serialization, encrypted dictionary export/import round-trip parsing, AI-feature disclosure catalog coverage, and the Tink encrypted-preference migration contract. Production TODO/FIXME markers are now mostly design debt rather than crash stubs: language-capability hard-coding in `FlorisLocale`, loader/locking notes in language-pack extensions, emoji-compat GMS/no-GMS cleanup, honeycomb/layout constraint comments, and unsupported mutating calls in read-only media providers. **No known production `TODO()` crash stub remains.**
10511051

@@ -1067,7 +1067,7 @@ GIF keyboard via Tenor/Giphy · Bing search bar · Microsoft account sync · in-
10671067
- GitHub Releases still need to be checked against the current local tag stream
10681068
(`v1.8.84` at this snapshot); publication remains a maintainer-host task
10691069
because this VM cannot push to `SysAdminDoc/SwiftFloris`.
1070-
- `:benchmark` is active again and has committed SM-S938B / Android 16 first-render, first-suggestion, dictionary-load/preload, candidate-row recomposition, theme-switch, and backup/restore evidence in `docs/benchmark-results/`. `:lib:native` remains present-but-detached, so embedded Whisper remains impossible until the native module is intentionally revived.
1070+
- `:benchmark` is active again and has committed SM-S938B / Android 16 first-render, first-suggestion, dictionary-load/preload, candidate-row recomposition, theme-switch, and backup/restore evidence in `docs/benchmark-results/`. The `:lib:native` placeholder was dropped in v1.8.185; embedded native runtimes (Whisper, librime, LiteRT-LM, Bergamot) ship as out-of-tree signed addon APKs per the `AddonContract.Action.REGISTER_*` enrolment contract rather than as a `:lib:native` module in the base APK.
10711071
- Roborazzi is now externally unblocked, baseline PNGs are committed, and `.github/workflows/android.yml` treats `:app:verifyRoborazziDebug` as a hard gate. Future visual work should add focused baselines instead of softening CI.
10721072
- `FlorisLocale.kt` still hard-codes capitalization/autospace support tables; replace with ICU/script metadata before the next language-expansion wave.
10731073
- ✅ Honeycomb renderer components are wired into the production character-layout

app/src/main/kotlin/dev/patrickgold/florisboard/FlorisApplication.kt

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@ import kotlinx.coroutines.flow.MutableStateFlow
5454
import kotlinx.coroutines.launch
5555
import org.florisboard.lib.kotlin.io.deleteContentsRecursively
5656
import org.florisboard.lib.kotlin.tryOrNull
57-
//import org.florisboard.libnative.dummyAdd // Native module disabled
5857
import java.lang.ref.WeakReference
5958

6059
/**
@@ -134,9 +133,6 @@ class FlorisApplication : Application() {
134133
// provider in place.
135134
}
136135
}
137-
flogError { "native module disabled, skipping dummy test" }
138-
// Originally: flogError { "dummy result: ${dummyAdd(3,4)}" }
139-
140136
if (!UserManagerCompat.isUserUnlocked(this)) {
141137
cacheDir?.deleteContentsRecursively()
142138
extensionManager.value.init()

docs/REPRODUCIBLE_BUILDS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ verify it matches the official Release artifact.
2323
| JDK | `gradle/tools.versions.toml` `jdk` | 17 | enforced by `compileOptions { sourceCompatibility = JavaVersion.VERSION_11 }` and `kotlin { compilerOptions { jvmTarget = JVM_11 } }`; build container uses `setup-java@v4 java-version: 17 distribution: temurin` |
2424
| CMake | `gradle/tools.versions.toml` `cmake` | 4.1.2 | fixed |
2525
| cmdline tools | `gradle/tools.versions.toml` `cmdlineTools` + `cmdlineToolsChecksum` | 14742923 | SHA-256 pinned |
26-
| Rust toolchain | `gradle/tools.versions.toml` `rustToolchain` | 1.93.0 | only used by `lib/native` (currently disabled in `settings.gradle.kts`) |
26+
| Rust toolchain | `gradle/tools.versions.toml` `rustToolchain` | 1.93.0 | dormant pin retained for future out-of-tree native addons; `:app` ships no Rust today (the `:lib:native` placeholder was dropped in v1.8.185) |
2727

2828
All Compose / library dependencies live behind `gradle/libs.versions.toml` version refs — no transitive `+` or `latest.release` selectors.
2929

docs/THREAT_MODEL.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,8 +179,13 @@ Out of scope:
179179
### 3.8 Auditability
180180
- Apache-2.0 codebase, no obfuscation in debug builds, ProGuard rules visible
181181
in `app/proguard-rules.pro` for release builds.
182-
- No closed-source binary blobs (e.g. `libjni_latinimegoogle.so`); the only
183-
native code is `lib/native` (Rust ICU helpers, source visible).
182+
- No closed-source binary blobs (e.g. `libjni_latinimegoogle.so`); the base
183+
APK ships **zero** native code as of v1.8.185 (the prior `:lib:native` Rust
184+
placeholder was dropped — see `RESEARCH_FEATURE_PLAN.md` EI11 + the
185+
v1.8.185 CHANGELOG entry). When optional native runtimes (LiteRT-LM,
186+
whisper.cpp, librime, etc.) land they ship as out-of-tree signed addon
187+
APKs with their own auditable sources, never as a hidden `:app`
188+
dependency.
184189
- F-Droid metadata + reproducible-build target are Now items (N6.2 / N6.3).
185190

186191
---

0 commit comments

Comments
 (0)