You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: RESEARCH_REPORT.md
+25-3Lines changed: 25 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,6 +1,6 @@
1
1
# SwiftFloris Research Report
2
2
3
-
This report summarizes current research conclusions. The full 2026-05-25 research plan is archived at `docs/archive/research/RESEARCH_FEATURE_PLAN_2026-05-25.md`. Deep-research pass refreshed **2026-06-03** (post-v1.8.204), with 2026-06-04 freshness notes through v1.8.246.
3
+
This report summarizes current research conclusions. The full 2026-05-25 research plan is archived at `docs/archive/research/RESEARCH_FEATURE_PLAN_2026-05-25.md`. Deep-research pass refreshed **2026-06-03** (post-v1.8.204), with 2026-06-04 freshness notes through Cycle 12 and v1.8.246 implementation notes.
constructor stdout logging is removed, aggregate helper semantics are documented
@@ -38,6 +38,13 @@ must remain local generated output rather than review evidence.
38
38
AndroidX Core `1.19.0` remains blocked on the API 37 behavior-gate because the
39
39
published `core-1.19.0.aar` metadata declares `minCompileSdk=37`.
40
40
41
+
2026-06-04 Cycle 12 note: after the Cycle 11 docs push, `master` is clean at
42
+
`8b68d3e` (`v1.8.238-1-g8b68d3e`). Cycle 12 rechecked the personal n-gram
43
+
persistence data-loss audit against live `PersonalBigramStore`,
44
+
`PersonalTrigramStore`, and the locale-isolation flush tests. This cycle adds
45
+
R12-1: replace personal n-gram files atomically without deleting the live
46
+
destination before a successful replacement exists.
47
+
41
48
2026-06-04 Cycle 11 note: after the Cycle 10 docs push, `master` is clean at
42
49
`31cfa44` (`v1.8.237-1-g31cfa44`). Cycle 11 rechecked the async preference
43
50
initialization audit against live `FlorisApplication.init()` and Settings
@@ -159,7 +166,7 @@ F22/F10/F12/API 37 work.
159
166
160
167
## Executive Summary
161
168
162
-
SwiftFloris is a mature, heavily-audited privacy-first Android IME (FlorisBoard fork, `dev.patrickgold.florisboard`, `:app` permission-clean with no `INTERNET`). At v1.8.246, the post-v1.8.225 pushed fixes are covered by a release ledger and focused regression tests, the Japanese locale capability typo is fixed, clipboard history search is wired into the keyboard palette, clipboard image/video history tiles have TalkBack labels, non-co-signed addon enrollment now requires explicit Settings trust, the sync sealed-box v1 envelope is pinned by deterministic vector coverage, editor `InputConnection` batch edits now exclude expected-content queue work, stale editor content-generation jobs are cancelled or superseded across input-session boundaries, async preference-store init failures now unblock Settings into the crash recovery path, MIME helper aggregate semantics are documented and pinned without constructor stdout, native string decoding now honors ByteBuffer position/limit windows, localization copy now has Turkish repeated-word/source-label/failure-copy guardrails, visual/manual/release evidence checklists are consolidated, Fastlane changelog drafting guidance is documented, module build-cache cleanup expectations are documented, dynamic incognito toggles re-apply the IME window screen-capture guard immediately, blocked user-dictionary system-back gestures now explain active save/delete/import/export work, Settings search now has TalkBack labels/live result-status/result-row context plus one-shot dismissible destination highlights, and async suggestion candidate generation now uses request-scoped privacy snapshots. The feature surface is broad (autocorrect/prediction, glide typing, clipboard, addons, voice handoff, sync, MCP bridge, hardware-keyboard import). The compatible dependency stack is current for the applied pins (Compose BOM 2026.05.01, Kotlin 2.3.21, AGP 9.2.1, targetSdk 36). Three deep engineering audits (2026-05-28/29 and 2026-06-02) plus the existing roadmap already cover correctness, crypto, resource, and device-gated visual work, so the **net-new** opportunity space is narrow and concentrated on device-gated proof, external actions, and a few docs/build hygiene rows. The **settings search** feature shipped in v1.8.204 (commit `1966c69`) now has drift/no-results/synonym/scroll/accessibility/highlight-lifecycle polish. [Verified]
169
+
SwiftFloris is a mature, heavily-audited privacy-first Android IME (FlorisBoard fork, `dev.patrickgold.florisboard`, `:app` permission-clean with no `INTERNET`). At v1.8.246, the post-v1.8.225 pushed fixes are covered by a release ledger and focused regression tests, the Japanese locale capability typo is fixed, clipboard history search is wired into the keyboard palette, clipboard image/video history tiles have TalkBack labels, non-co-signed addon enrollment now requires explicit Settings trust, the sync sealed-box v1 envelope is pinned by deterministic vector coverage, editor `InputConnection` batch edits now exclude expected-content queue work, stale editor content-generation jobs are cancelled or superseded across input-session boundaries, async preference-store init failures now unblock Settings into the crash recovery path, MIME helper aggregate semantics are documented and pinned without constructor stdout, native string decoding now honors ByteBuffer position/limit windows, localization copy now has Turkish repeated-word/source-label/failure-copy guardrails, visual/manual/release evidence checklists are consolidated, Fastlane changelog drafting guidance is documented, module build-cache cleanup expectations are documented, dynamic incognito toggles re-apply the IME window screen-capture guard immediately, blocked user-dictionary system-back gestures now explain active save/delete/import/export work, Settings search now has TalkBack labels/live result-status/result-row context plus one-shot dismissible destination highlights, and async suggestion candidate generation now uses request-scoped privacy snapshots. The feature surface is broad (autocorrect/prediction, glide typing, clipboard, addons, voice handoff, sync, MCP bridge, hardware-keyboard import). The compatible dependency stack is current for the applied pins (Compose BOM 2026.05.01, Kotlin 2.3.21, AGP 9.2.1, targetSdk 36). Three deep engineering audits (2026-05-28/29 and 2026-06-02) plus the existing roadmap already cover correctness, crypto, resource, and device-gated visual work, so the **net-new** opportunity space is narrow and concentrated on small data-integrity/API-contract hardening, device-gated proof, external actions, and docs/build hygiene rows. The **settings search** feature shipped in v1.8.204 (commit `1966c69`) now has drift/no-results/synonym/scroll/accessibility/highlight-lifecycle polish. [Verified]
163
170
164
171
Top opportunities (one line each):
165
172
@@ -188,6 +195,7 @@ Top opportunities (one line each):
188
195
23.**Suggestion privacy request snapshot** — async candidate generation now freezes incognito/editor sensitivity and suggestion preference inputs before provider, trace, and ghost-text work runs (R9-1). [Closed]
189
196
24.**Editor content-generation lifecycle** — delayed start/selection content jobs are cancelled or superseded across reset/finishInput and input-connection switches before they can publish state or touch a captured `InputConnection` (R10-1). [Closed]
190
197
25.**Preference-store init splash recovery** — async `initAndroid` failures now stage a crash report, unblock the splash wait, and redirect to crash recovery before normal Settings content renders (R11-1). [Closed]
198
+
26.**Personal n-gram file replacement** — bigram/trigram flush fallback deletes the live file before a successful replacement exists (R12-1, P2). [Verified]
191
199
192
200
No Critical or Major reliability/security defects were found that are not already on the roadmap or in the deferred audit lists. The remaining heavy work (glide model training, Vosk addon, F-Droid submission, device-only visual verification) stays maintainer-gated as the existing roadmap records.
193
201
@@ -266,6 +274,10 @@ Privacy-first multilingual IME. `:app` is Apache-2.0-ceiling, no network permiss
266
274
preference-store failures by staging the failure, marking preference loading
267
275
complete, and checking the staged crash path before Settings content renders.
268
276
[Closed]
277
+
-**Personal n-gram persistence (partial):** locale-scoped flushes and
278
+
concurrency guards are in place, but bigram/trigram file replacement still
279
+
deletes the destination before a second rename attempt. R12-1 keeps the
280
+
last-known-good n-gram file until replacement succeeds. [Verified]
269
281
- Established surfaces (autocorrect/SymSpell, glide classifier, clipboard, addons, voice handoff, sync, MCP, hardware-keyboard import) are covered by `COMPLETED.md` and the audits; no net-new gap surfaced beyond what the roadmap already tracks.
270
282
271
283
## Competitive Landscape
@@ -301,6 +313,9 @@ Privacy-first multilingual IME. `:app` is Apache-2.0-ceiling, no network permiss
301
313
launched `FlorisPreferenceStore.initAndroid(...)` path is supervised,
302
314
error-guarded, staged through crash recovery on failure, and always unblocks
303
315
the Settings splash wait for non-cancelled completion.
316
+
-**[Medium] Personal n-gram atomic replacement** → R12-1. Replace bigram and
317
+
trigram TSV files without deleting the live destination before a successful
318
+
replacement exists.
304
319
-**[Closed v1.8.219] Remaining diagnostic `printStackTrace()` paths** → R2-2. `RestoreScreen` failure diagnostics now use `flogError`, restore UI copy falls back to the existing "Unknown error" string for null/blank throwable messages, and `CrashUtility.writeToFile` logs through `LogTopic.CRASH_UTILITY`.
305
320
-**[High] Local release ledger drift** → R3-1. Three code-fix commits after
306
321
the v1.8.225 docs marker are untagged and absent from the release ledger.
@@ -389,6 +404,10 @@ Privacy-first multilingual IME. `:app` is Apache-2.0-ceiling, no network permiss
389
404
failures are logged and staged, `preferenceStoreLoaded` unblocks the splash,
390
405
and `FlorisAppActivity` checks the staged crash path again before normal
centralizes leave/mutation/transfer gates. v1.8.232 keeps that policy and
394
413
adds a visible response when Compose back handling blocks the gesture during
@@ -401,7 +420,7 @@ Privacy-first multilingual IME. `:app` is Apache-2.0-ceiling, no network permiss
401
420
402
421
## Security / Privacy / Data Safety
403
422
404
-
No net-new permission or data-egress finding. The settings-search additions are display/navigation only; the no-results Browse all settings action (RA-2), synonym keyword coverage (RA-3), and query-change scroll reset (RA-10) do not weaken the no-network posture. R2-1 and R2-2 closed as local diagnostic-safety work without adding network, telemetry, or broad file export. R11-1 closes the async side of startup diagnostics by surfacing preference-store init failures through the existing local crash recovery path without adding storage, permissions, or outbound data. R3-2 is also local-only clipboard filtering. R3-3 closed as sync-crypto contract hardening before transport activation, with no new permission or native dependency. R4-1/R4-2/R4-3/R4-4 are closed local correctness/a11y/API-contract work. WS12 and WS10/WS15 are docs/resource-only and do not change permissions, retention, or storage behavior. R5-1 closed as trust-boundary hardening for optional addon APKs: it keeps the no-network addon screen but requires explicit trust before non-co-signed packages become active. R6-1 is local editor critical-section hardening and does not change storage, permissions, or outbound data. R7-1 closed as privacy posture hardening for the existing incognito mode and `FLAG_SECURE` contract, not a permission change. R9-1 is privacy-state hardening for existing local suggestion and smart-compose paths: it keeps the no-network posture and ensures `IME_FLAG_NO_PERSONALIZED_LEARNING` / incognito decisions are request-scoped across async work. R10-1 is local editor-session lifecycle hardening and does not change storage, permissions, or outbound data. R8-1 is UI feedback for an already-blocked dictionary operation path and does not change data retention, dictionary mutation, or export/import permissions. WS13 now explicitly includes the deferred `StickerMediaProvider.openFile` SAF allow-list validation so forged encoded sticker URIs are rejected without broadening file access. The deferred audit lists (`docs/AUDIT_2026-06-02.md`) remain the authority for crypto/parsing/lifecycle hardening; this pass does not duplicate them.
423
+
No net-new permission or data-egress finding. The settings-search additions are display/navigation only; the no-results Browse all settings action (RA-2), synonym keyword coverage (RA-3), and query-change scroll reset (RA-10) do not weaken the no-network posture. R2-1 and R2-2 closed as local diagnostic-safety work without adding network, telemetry, or broad file export. R11-1 closes the async side of startup diagnostics by surfacing preference-store init failures through the existing local crash recovery path without adding storage, permissions, or outbound data. R12-1 is local personal-prediction durability hardening and does not change dictionary retention, export, permissions, or outbound data. R3-2 is also local-only clipboard filtering. R3-3 closed as sync-crypto contract hardening before transport activation, with no new permission or native dependency. R4-1/R4-2/R4-3/R4-4 are closed local correctness/a11y/API-contract work. WS12 and WS10/WS15 are docs/resource-only and do not change permissions, retention, or storage behavior. R5-1 closed as trust-boundary hardening for optional addon APKs: it keeps the no-network addon screen but requires explicit trust before non-co-signed packages become active. R6-1 is local editor critical-section hardening and does not change storage, permissions, or outbound data. R7-1 closed as privacy posture hardening for the existing incognito mode and `FLAG_SECURE` contract, not a permission change. R9-1 is privacy-state hardening for existing local suggestion and smart-compose paths: it keeps the no-network posture and ensures `IME_FLAG_NO_PERSONALIZED_LEARNING` / incognito decisions are request-scoped across async work. R10-1 is local editor-session lifecycle hardening and does not change storage, permissions, or outbound data. R8-1 is UI feedback for an already-blocked dictionary operation path and does not change data retention, dictionary mutation, or export/import permissions. WS13 now explicitly includes the deferred `StickerMediaProvider.openFile` SAF allow-list validation so forged encoded sticker URIs are rejected without broadening file access. The deferred audit lists (`docs/AUDIT_2026-06-02.md`) remain the authority for crypto/parsing/lifecycle hardening; this pass does not duplicate them.
405
424
406
425
## UX & Accessibility
407
426
@@ -427,6 +446,8 @@ The keyboard surface already has a strong a11y baseline (`ACCESSIBILITY.md`, `To
427
446
delayed editor-session contract is covered by focused JVM/Robolectric tests.
428
447
6. v1.8.240 still needs manual forced preference-init debug smoke on a device;
429
448
the async failure contract is covered by focused JVM/Robolectric tests.
449
+
7. R12-1 needs a focused file-replacement/flush test; no maintainer product
450
+
decision is required.
430
451
431
452
## Archived Evidence
432
453
@@ -460,3 +481,4 @@ The keyboard surface already has a strong a11y baseline (`ACCESSIBILITY.md`, `To
0 commit comments