Skip to content

Commit caf6bea

Browse files
committed
docs: refresh cycle 15 research queue
1 parent 2b300a4 commit caf6bea

3 files changed

Lines changed: 105 additions & 2 deletions

File tree

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# Cycle 15 Findings - 2026-06-04
2+
3+
## Scope
4+
5+
- Repository: `SwiftFloris`
6+
- Baseline: clean detached worktree at pushed `master` `2b300a4`
7+
(`docs: refresh cycle 14 research queue`), described as
8+
`v1.8.246-3-g2b300a4`.
9+
- Sync: `git pull --rebase origin master` reported up to date before this
10+
cycle.
11+
- Constraint: research/docs only. No feature source, tests, build files, or
12+
assets were edited.
13+
14+
## Anti-Duplicate Checks
15+
16+
- Did not reopen ZipUtils NUL/space findings. `docs/AUDIT_2026-05-29.md:101-106`
17+
marks those as verified-clean, and current `ZipUtils.kt:47-56` contains the
18+
NUL guard with no space rejection.
19+
- Did not add an MCP daemon tool-name row in this cycle; the current focus is
20+
keyboard-layout diagnostics.
21+
- Did not change the honeycomb parser's fail-safe design. The row preserves
22+
empty-list degradation and adds only diagnostic visibility.
23+
- Did not duplicate visual/manual honeycomb follow-ups already tracked under
24+
broader keyboard surface and Roborazzi/device-proof rows.
25+
26+
## Local Evidence
27+
28+
- `HoneycombLayoutLoader.kt:39-43` documents the malformed-input policy: tolerate
29+
malformed input by returning an empty list rather than throwing.
30+
- `HoneycombLayoutLoader.kt:59-79` wraps the parse in `try/catch`, catches
31+
`Exception`, and returns `emptyList()` without logging.
32+
- `HoneycombLayoutLoaderTest.kt:152-156` verifies malformed JSON returns an
33+
empty list, but does not assert diagnostic visibility.
34+
- `ZipfFrequencyTable.kt:109-117` is a nearby parser/degradation precedent that
35+
logs parse failures with `flogError` before returning a default result.
36+
- `docs/AUDIT_2026-05-28.md:72-74` records the user-visible silent
37+
empty-keyboard diagnostic gap.
38+
39+
## Roadmap Changes Fed
40+
41+
- R15-1: Log Honeycomb layout parse failures before fail-safe empty layout. The
42+
implementation should keep malformed layouts non-fatal while emitting an
43+
actionable project-log diagnostic and adding focused coverage that fails if
44+
the catch path silently returns `emptyList()` again.
45+
46+
## Non-Adds
47+
48+
- No source fix was made in this cycle.
49+
- No new parser strictness, crash behavior, permission, or network behavior was
50+
proposed.
51+
- No visual baseline or device-proof expansion proposed; those stay under the
52+
existing keyboard-surface and Roborazzi/device-gated roadmap items.

RESEARCH_REPORT.md

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

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 14 and v1.8.246 implementation notes.
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 15 and v1.8.246 implementation notes.
44

55
2026-06-04 implementation note: v1.8.241 closed R4-3. `MimeTypeFilter`
66
constructor stdout logging is removed, aggregate helper semantics are documented
@@ -38,6 +38,12 @@ must remain local generated output rather than review evidence.
3838
AndroidX Core `1.19.0` remains blocked on the API 37 behavior-gate because the
3939
published `core-1.19.0.aar` metadata declares `minCompileSdk=37`.
4040

41+
2026-06-04 Cycle 15 note: after the Cycle 14 docs push, `master` is clean at
42+
`2b300a4` (`v1.8.246-3-g2b300a4`). Cycle 15 rechecked the deferred
43+
Honeycomb layout parse diagnostics audit against live parser and test code.
44+
This cycle adds R15-1: log Honeycomb layout parse failures before preserving
45+
the intentional fail-safe `emptyList()` fallback.
46+
4147
2026-06-04 Cycle 14 note: after the Cycle 13 docs push, `master` is clean at
4248
`857cfe0` (`v1.8.246-2-g857cfe0`). Cycle 14 rechecked the deferred
4349
personal n-gram TSV token-safety audit against live bigram/trigram
@@ -212,6 +218,7 @@ Top opportunities (one line each):
212218
26. **Personal n-gram file replacement** — bigram/trigram flush fallback deletes the live file before a successful replacement exists (R12-1, P2). [Verified]
213219
27. **Personal n-gram stats/reset serialization**`totalEntryCount()` can enumerate/load persisted bigram/trigram locales outside the reset lock while `resetAndAwait()` clears and deletes those files (R13-1, P2). [Verified]
214220
28. **Personal n-gram TSV token safety** — learned bigram/trigram tokens can still contain tab/newline/NUL/control separators that corrupt TSV rows or trigram context keys on reload (R14-1, P2). [Verified]
221+
29. **Honeycomb layout parse diagnostics** — malformed honeycomb layout JSON degrades to an empty keyboard without logging the parse failure (R15-1, P2). [Verified]
215222

216223
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.
217224

@@ -344,6 +351,9 @@ Privacy-first multilingual IME. `:app` is Apache-2.0-ceiling, no network permiss
344351
carriage-return, NUL, and other ISO control characters in bigram/trigram
345352
normalized tokens before they can corrupt tab-separated rows or trigram
346353
context keys.
354+
- **[Medium] Honeycomb layout parse diagnostics** → R15-1. Keep malformed
355+
honeycomb layouts fail-safe, but log the parse failure before returning an
356+
empty layout so a blank keyboard has an actionable support signal.
347357
- **[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`.
348358
- **[High] Local release ledger drift** → R3-1. Three code-fix commits after
349359
the v1.8.225 docs marker are untagged and absent from the release ledger.
@@ -444,6 +454,9 @@ Privacy-first multilingual IME. `:app` is Apache-2.0-ceiling, no network permiss
444454
centralizes leave/mutation/transfer gates. v1.8.232 keeps that policy and
445455
adds a visible response when Compose back handling blocks the gesture during
446456
active work.
457+
- **Honeycomb parser diagnostics:** `HoneycombLayoutLoader` already keeps bad
458+
layout JSON non-fatal, but Cycle 15 adds the diagnostic boundary so parser
459+
degradation does not silently produce an empty character keyboard.
447460
- **Dependency health:** the security-sensitive pins checked here are still current for SQLCipher 4.16.0 and Tink 1.21.0, and Room/Robolectric also match metadata. The compatible P3 maintenance batch shipped in v1.8.216 (Compose BOM `2026.05.01`, KSP `2.3.9`, Roborazzi `1.63.0`). Kotlin `2.4.0` and AndroidX Core `1.19.0` remain gated on KSP publication and compileSdk 37 respectively; AGP 9.2.1 appears to be the stable baseline while Google Maven's newest AGP metadata is 9.3 alpha. [Verified via Maven metadata]
448461
- **Overgrown files:** `IndicTransliterator.kt` (~86 KB), `TextKeyboardLayout.kt` (~76 KB), `LatinLanguageProvider.kt` (~60 KB), `KeyboardManager.kt` (~60 KB) are large but the SHIFT state machine was already extracted (F27 shipped) and the audits already track `LatinLanguageProvider` heap risk (A1). Left as-is — no speculative refactor proposed.
449462
- **Testability:** 221 JVM test files, 5 androidTest. The search catalog's integrity and synonym-hit coverage are now pinned by RA-1 and RA-3, the RA-10 scroll-reset guard is covered, RA-4 has source/resource accessibility contract coverage, and R3-4 backfills the post-hotfix Arabic/Snygg/trace/n-gram regression surface.
@@ -452,7 +465,7 @@ Privacy-first multilingual IME. `:app` is Apache-2.0-ceiling, no network permiss
452465

453466
## Security / Privacy / Data Safety
454467

455-
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. R13-1 is local stats/reset consistency hardening for the same personal n-gram files and likewise does not change retention, export, permissions, or outbound data. R14-1 is local write-time token-safety hardening for existing personal n-gram persistence and does not add collection, 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.
468+
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. R13-1 is local stats/reset consistency hardening for the same personal n-gram files and likewise does not change retention, export, permissions, or outbound data. R14-1 is local write-time token-safety hardening for existing personal n-gram persistence and does not add collection, retention, export, permissions, or outbound data. R15-1 is local parser diagnostics for existing honeycomb layout JSON and does not add permissions, storage, export, 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.
456469

457470
## UX & Accessibility
458471

@@ -484,6 +497,8 @@ The keyboard surface already has a strong a11y baseline (`ACCESSIBILITY.md`, `To
484497
product decision is required.
485498
9. R14-1 needs focused personal n-gram token-safety tests for control
486499
separators; no maintainer product decision is required.
500+
10. R15-1 needs a focused Honeycomb malformed-layout diagnostics test; no
501+
maintainer product decision is required.
487502

488503
## Archived Evidence
489504

ROADMAP.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,42 @@ These are genuine blockers — each needs an account, key, sibling repo, ML infr
176176

177177
## Research-Driven Additions
178178

179+
### Researcher Queue (Cycle 15 - 2026-06-04)
180+
181+
- [x] 🔬 `honeycomb-parse-diagnostics-recheck-2026-06-04` - synced
182+
`master` after the Cycle 14 docs push, rechecked the deferred keyboard-layout
183+
parse diagnostics audit against live Honeycomb parser and tests. This cycle
184+
adds one focused row for logging malformed honeycomb layout JSON before the
185+
fail-safe empty-layout fallback.
186+
187+
#### Honeycomb layout diagnostics
188+
189+
- [ ] 🤖 P2 — Log Honeycomb layout parse failures before fail-safe empty layout (R15-1)
190+
- Why: `HoneycombLayoutLoader.parse(...)` intentionally returns `emptyList()`
191+
for malformed layout JSON so a corrupt disk/addon layout does not crash the
192+
IME, but the catch block drops the exception with no diagnostic. The result
193+
can be an empty character keyboard with no support signal, while sibling
194+
parser/degradation paths such as `ZipfFrequencyTable.parse(...)` already log
195+
before returning a safe empty/default result.
196+
- Evidence: `HoneycombLayoutLoader.kt:39-43` documents the fail-safe malformed
197+
input policy; `HoneycombLayoutLoader.kt:59-79` catches `Exception` and
198+
returns `emptyList()` without `flogWarning`/`flogError`;
199+
`HoneycombLayoutLoaderTest.kt:152-156` pins the malformed-JSON empty-list
200+
fallback but not diagnostic emission; `ZipfFrequencyTable.kt:109-117`
201+
catches parse failures and logs them with `flogError`; the deferred audit
202+
records the silent empty-keyboard path in `docs/AUDIT_2026-05-28.md:72-74`.
203+
- Touches: `HoneycombLayoutLoader.kt` and `HoneycombLayoutLoaderTest.kt` or a
204+
small source-level logging contract test. Preserve the fail-safe return
205+
value and do not turn malformed layouts into crashes.
206+
- Acceptance: malformed JSON still returns `emptyList()`, but the catch path
207+
emits one actionable diagnostic through the project logging stack naming
208+
`HoneycombLayoutLoader` and the parse failure; valid layouts and modifier
209+
filtering are unchanged; tests fail if the catch block silently returns
210+
`emptyList()` again.
211+
- Verify: `./gradlew.bat :app:testDebugUnitTest --tests
212+
"dev.patrickgold.florisboard.ime.text.keyboard.HoneycombLayoutLoaderTest"`
213+
- Complexity: XS
214+
179215
### Researcher Queue (Cycle 14 - 2026-06-04)
180216

181217
- [x] 🔬 `personal-ngram-control-token-recheck-2026-06-04` - synced

0 commit comments

Comments
 (0)