diff --git a/docs/audit-2026-09.md b/docs/audit-2026-09.md index a089ae78..2393d017 100644 --- a/docs/audit-2026-09.md +++ b/docs/audit-2026-09.md @@ -89,6 +89,114 @@ Effort: S (hours), M (a day or two), L (a week or more). Everything else below is narrower (file trees past 500 nodes; tasks, which are off by default), suspected, or cosmetic. +## Fix pass, 2026-09-24 + +One orchestrating session and one fix agent per area, each in its own git worktree; their +commits were cherry-picked onto `main` (`ee04e95..main`, about 160 commits). `npx tsc --noEmit` +and `npx vitest run` passed after every merge (1,886 tests at `b7a5953`). Nothing has run on a +device yet: a ticked box means the fix landed with unit tests, not that it was checked on the +emulator, and the startup numbers in PF2 come from `npx expo export`, not from device timings. A +device build and smoke test are in progress. + +Result: of the 93 bug, UI, performance and webmail-gap items, 80 are ticked, 7 are fixed in part +and 6 are open (B2, U8, PF9, the viewer's undo-send bar, Tabler icons, the password hand-off). +13 of the 14 stale parity entries are resolved; `dateLocale` is still missing. + +### Check on a device or server + +- **Android intents (B9–B11):** the Kotlin was reviewed but never compiled. Check `SEND` with a + `content://` image, `SENDTO mailto:` with extras on a cold and a warm start, and + `VIEW mailto:alice+news@partner.example`. +- **First build:** `063432b` adds `babel.config.js` and `metro.config.js`, so start Metro once with + `npx expo start --clear`. The AsyncStorage limit from `24849ba` only applies after a native + rebuild. +- **Timings:** record PF1, PF2, PF3, U1 and U2 again with `screenrecord`; none were re-measured. +- **Push:** the `forbidden` fallback with a mailbox shared by ACL (`d8046a8`), revoke detection + (`a3d3af7`), a group-mailbox notification tap (`8618abf`), and that a replacement subscription + fits under `maxPushSubscriptions`, since the old one is kept until the new one is verified. +- **Echo skip (`018accd`):** it assumes `Mailbox.totalEmails` matches the `Email/query` total on + Stalwart; confirm on the wire. +- **Scheduled send on Stalwart:** the 7-day hold clamp (`4e7ae2f`), the create-then-cancel + reschedule (`7e598c5`) and scheduled mail held in shared accounts (`72f48db`). +- **Server-side recurrence (`8454889`, `f397ee3`, `96c5a3f`):** needs Stalwart 0.16.20 or later; + check the synthetic-id probe, a single-occurrence edit and an RSVP to one occurrence. +- **Calendar time zone (`a8e6f6e`, `8af163a`):** open and save an event and a task with the + calendar zone set away from the device zone. +- **Sieve round trip:** save filters on the phone while the auto-reply is on; it should stay on, + and the webmail should read the script back unchanged (`d53bfec`, `3f88868`, `6c31c8d`). +- **Sign-in:** add a second OAuth account (`ab84578`), and restore a session behind a redirecting + proxy (`859770b`). +- **Composer WebView:** the editor CSP (`235f4ea`) and the 400 ms change throttle (`fc00781`). +- **iOS:** the app-icon badge (`25c0883`) and the in-app PDF preview (`409cdb1`). +- **Translations (`67935d2`):** 26 languages written without a native speaker; wording with no + precedent in the webmail catalog needs a review. + +### Decisions for the maintainer + +- **Release signing, before the next version bump:** create the release key, the rotation lineage + (`apksigner rotate`) and the five repository secrets (`docs/android-release.md`). The release + workflow now fails without them, and a local release build needs + `-PallowDebugSignedRelease=true`. `versionCode` is derived from `VERSION` (0.1.62 → 10062). +- **Trusted-sender sync:** the webmail turns "Sync trusted senders to address book" on at login; + the app now leaves it off until the user turns it on (`d89e331`). Follow the webmail, or keep + it opt-in? +- **Sender favicons:** still on by default, and the phone fetches them from icons.duckduckgo.com + itself, having no proxy like the webmail's `/api/favicon`. Default off, a proxy, or keep? +- **Design language:** "Flat fields" and the Tabler icons are not ported (open question below). +- **Short messages:** the quick reply now sits at the bottom of the page so it never jumps + (`54b169c`), which leaves empty space under a short message. +- **Android app badge:** the icon badge is iOS-only (`25c0883`). On Android, expo-notifications + clears a badge with `cancelAll()`, which would also dismiss mail notifications and reminders, + and launchers already badge from the notifications on display. +- **Password hand-off:** taking the password out of the `bulwarkmobile://…#password=` fragment + needs a one-time code exchange on the webmail (`/api/auth/mobile/handoff` plus a redeem call, + PKCE-style). +- **Composer font size:** the webmail's font-size picker was left out; it needs a + selection-rewriting command in the editor page that can only be tested on a device. +- The other open questions at the end (tasks default, office documents, barcode scanner, package + name, settings sync, feature requests) are unchanged. + +### Follow-ups worth doing + +- Offline cache: a cached message over about 2 MB can't be read back on Android; keep bodies in + files. +- Offline cache: eviction only counts the active account. +- Session restore: a store that hydrates after the 5 s timeout merges over the restored state. +- Calendar subscriptions and search history don't use `createPersistStorage` yet. +- Bodies cached truncated before `4767805` are never fetched again. +- Push: `expires` is patched on every launch, because Stalwart's 7-day cap equals the refresh + threshold; check revoke detection and expiry for users who open the app less than weekly. +- Push: the onboarding prompt comes back after push was turned off. +- Webmail: `lib/web-push.ts` has the same shared-account `emailPush` bug as B18. +- Mail list: the swipe drag still runs on the JS thread (needs gesture-handler or reanimated). +- Unified Inbox: the inline `renderItem` pattern `ebd8dac` removed from the folder list, no + attachment chips, and `patchRows` duplicates the keyword-patch helper. +- Mail: the webmail's opt-in "All unread" and "All starred" views are missing. +- Composer: the undo-send bar only exists on the list screen, so a quick reply can't be undone. +- Composer: drafts can't be saved offline (B16 now says so instead of dropping the text). +- Composer: `findReceivingIdentity` scans identities in list order; no "remove text colour". +- Startup: the date-fns main barrel still adds about 300 modules; the 4.3 MB of catalogs stay in + the bundle, only no longer evaluated at startup. +- Startup: screens other than the mail list take their top inset from the native `SafeAreaView` + and jump; the window colour follows the system theme, not the app's. +- Intents: a `mailto:` without a recipient opens nothing; Bcc can't be passed through + `bulwarkmobile://compose`. +- Files: no refresh after a partly failed delete; the webmail's share-rights conversion for + Stalwart before 0.16.6 (`c3225b3f`) is not ported. +- File preview: no PDF renderer on Android, no audio, video, HTML or Markdown preview, and text + is read as UTF-8 only. +- Filters: calendar and contacts settings aren't scoped when managing a shared account; no UI for + the forward limit (`maxNumberRedirects`) or the auto-reply length warning (webmail + `f3aec163`); `fileinto` lingers in `require`. +- Settings search: sidebar apps aren't indexed, and theme names aren't translated. +- i18n pass 2: hard-coded English is left in the viewer, calendar, email store, drawer, Unified + Inbox and `App.tsx`; then top up the translations (`node scripts/rn-missing-translations.mjs`). +- Release workflow: the `workflow_dispatch` hint "leave empty to skip upload" doesn't match what + the workflow does (older than this pass). +- Upstream: GitHub `main` has `c2584c2` and `5b8c435` (PR #53, links in event descriptions), + which local `main` lacks. +- `src/lib/mdn.ts`: the top comment still names `sendMdn`. + ## Bugs ### Crashes