diff --git a/docs/audit-2026-09.md b/docs/audit-2026-09.md index 22bde7fb..a089ae78 100644 --- a/docs/audit-2026-09.md +++ b/docs/audit-2026-09.md @@ -56,24 +56,28 @@ Effort: S (hours), M (a day or two), L (a week or more). ## Summary: fix these ten first -1. [ ] **P0 · S:** read receipts carry attacker-controlled headers and are sent for messages the user - never opened ([S1](#s1), [B7](#b7)). -2. [ ] **P0 · S–M:** published release APKs are signed with the public React Native debug key - ([S2](#s2)). -3. [ ] **P0 · S–M:** viewer actions on a shared/group message hit the user's own account and can - delete an unrelated message ([B3](#b3)). -4. [ ] **P0 · S:** opening, starring or tagging replaces the whole keyword map; stars and tags are - erased ([B4](#b4)). -5. [ ] **P1 · S:** the viewer switches to another message when new mail arrives, and its buttons act - on the message you are not looking at ([B5](#b5)). -6. [ ] **P1 · S–M:** messages disappear from the list after a background refresh until you pull to - refresh ([B6](#b6)). -7. [ ] **P1 · S:** scheduled send, the undo-send delay and the Scheduled folder are dead on every - Stalwart server (#57, [B8](#b8)). -8. [ ] **P1 · S–M:** sharing a file into the app always fails, and `SENDTO`/`+`-address `mailto:` links - open nothing ([B9](#b9), [B10](#b10), [B11](#b11)). -9. [ ] **P1 · M:** opening a message takes 1.7–1.9 s and the layout jumps three times ([PF1](#pf1)). -10. [ ] **P1 · M:** cold start takes 3.6–4.1 s to a settled inbox and is JS-bound ([PF2](#pf2)). +1. [x] **P0 · S:** read receipts carry attacker-controlled headers and are sent for messages the user + never opened ([S1](#s1), [B7](#b7)). Fixed in `cb6ddd6`, `5f3f584`. +2. [x] **P0 · S–M:** published release APKs are signed with the public React Native debug key + ([S2](#s2)). Fixed in `6f0abb4`, `746572c`; the release key and secrets still have to be set up + before the next release. +3. [x] **P0 · S–M:** viewer actions on a shared/group message hit the user's own account and can + delete an unrelated message ([B3](#b3)). Fixed in `5c7301b`. +4. [x] **P0 · S:** opening, starring or tagging replaces the whole keyword map; stars and tags are + erased ([B4](#b4)). Fixed in `5041897`. +5. [x] **P1 · S:** the viewer switches to another message when new mail arrives, and its buttons act + on the message you are not looking at ([B5](#b5)). Fixed in `9c31de2`. +6. [x] **P1 · S–M:** messages disappear from the list after a background refresh until you pull to + refresh ([B6](#b6)). Fixed in `0a8686a`. +7. [x] **P1 · S:** scheduled send, the undo-send delay and the Scheduled folder are dead on every + Stalwart server (#57, [B8](#b8)). Fixed in `e28e8b4`. +8. [x] **P1 · S–M:** sharing a file into the app always fails, and `SENDTO`/`+`-address `mailto:` links + open nothing ([B9](#b9), [B10](#b10), [B11](#b11)). Fixed in `cd4ce9d`, `06e8942`, `ee652d3` (not + yet checked on a device). +9. [x] **P1 · M:** opening a message takes 1.7–1.9 s and the layout jumps three times ([PF1](#pf1)). + Fixed in `33e303e`, `ac8e3fb`, `1348e7d`, `01fc6fb`, `6ebadf7`, `54b169c` (not re-timed yet). +10. [x] **P1 · M:** cold start takes 3.6–4.1 s to a settled inbox and is JS-bound ([PF2](#pf2)). + Fixed in `604eb39`, `063432b`, `5bcfe1f`, `82ca359`, `b9db376` (not re-timed yet). **Why these ten:** - **1–2:** security holes that can be exploited today without any user mistake. @@ -89,8 +93,8 @@ suspected, or cosmetic. ### Crashes -- [ ] **B1 · P1 · M: session restore can hang forever when a persisted cache fails - to load.** +- [x] **B1 · P1 · M: session restore can hang forever when a persisted cache fails + to load.** Fixed in `29169c3`, `e37621b`, `24849ba`. - Where: `src/stores/auth-store.ts:23-31`, `src/stores/auth-store.ts:603-608`, `src/stores/settings-store.ts:423`. - Why: @@ -110,8 +114,8 @@ suspected, or cosmetic. ### Data correctness -- [ ] **B3 · P0 · S–M: viewer actions use the open folder's account instead of the - message's.** +- [x] **B3 · P0 · S–M: viewer actions use the open folder's account instead of the + message's.** Fixed in `5c7301b`, `d2066da`. - Where: `src/screens/EmailThreadScreen.tsx:107-113` (owner falls back to the list folder), `src/screens/EmailThreadScreen.tsx:355-358` (delete), `:388-414` (archive, move, spam), `src/stores/email-store.ts:1194-1197`. @@ -122,8 +126,8 @@ suspected, or cosmetic. id, since Stalwart ids are only unique per account) to Trash. - The team message stays where it was. - **Verified.** -- [ ] **B4 · P0 · S: mark-read, star, pin and tag replace the whole `keywords` - map.** +- [x] **B4 · P0 · S: mark-read, star, pin and tag replace the whole `keywords` + map.** Fixed in `5041897`, `ddff2f7`. - Where: `src/stores/email-store.ts:963-983`, `src/api/email.ts:602-609`. Outbox replay does the same. - Web: `lib/jmap/client.ts` (`keywords/$seen` pointer patch, `batchMarkAsRead`). RN already has @@ -135,8 +139,8 @@ suspected, or cosmetic. - Repro 2 (message in the list): Star sent the full map `{$notjunk, $seen, $flagged}`. That reverts any keyword another client changed since the list loaded. - **Verified.** -- [ ] **B5 · P1 · S: the viewer pager follows the live list, so new mail shifts the - page under the user.** +- [x] **B5 · P1 · S: the viewer pager follows the live list, so new mail shifts the + page under the user.** Fixed in `9c31de2`, `e0b7288`. - Where: `src/screens/EmailThreadScreen.tsx:81-102`, `:639`. - Repro: - Open "Quarterly numbers" (row 2) and deliver 2 new messages. @@ -145,7 +149,7 @@ suspected, or cosmetic. Archive use the same `activeEmailId`. - Fix: snapshot the id list when the viewer opens. - **Verified.** -- [ ] **B6 · P1 · S–M: messages vanish after a delta refresh.** +- [x] **B6 · P1 · S–M: messages vanish after a delta refresh.** Fixed in `0a8686a`. - Where: `src/stores/email-store.ts:1953-1990` and `:2058-2060`. - Web: `stores/email-store.ts` (`applyEmailDeltaNow`, which runs `Email/changes` against the list's own state). @@ -161,8 +165,8 @@ suspected, or cosmetic. - A pull-to-refresh (a full query) brings it back. - Before the empty-folder visit the same test worked (`queryChanges` → `changes` → `get`). - **Verified.** -- [ ] **B7 · P1 · S: with "Always send", read receipts go out for messages that were - never displayed, and a failed one leaves junk in Sent.** +- [x] **B7 · P1 · S: with "Always send", read receipts go out for messages that were + never displayed, and a failed one leaves junk in Sent.** Fixed in `5f3f584`, `1fb60a5`. - Where: `src/components/email/ReadReceiptBanner.tsx:92-101` (mounted in the neighbouring pages the pager pre-renders, `src/screens/EmailThreadScreen.tsx:641` `windowSize={3}`), `src/api/email.ts:1456-1486`. @@ -173,8 +177,8 @@ suspected, or cosmetic. confirm receipt" stays in Sent. `$mdnsent` is not set and a failed auto-send clears its guard (`autoRef.current = null`), so it can run again and import another copy. - **Verified.** -- [ ] **B8 · P1 · S: scheduled send and the undo-send delay are off on Stalwart - (#57).** +- [x] **B8 · P1 · S: scheduled send and the undo-send delay are off on Stalwart + (#57).** Fixed in `e28e8b4`, `4e7ae2f`. - Where: `src/api/jmap-client.ts:973-999` reads `session.capabilities[submission]`. Stalwart only puts `maxDelayedSend` and FUTURERELEASE in `accountCapabilities`. `:919-925` (attachment size cap) has the same problem. @@ -183,7 +187,8 @@ suspected, or cosmetic. → "In 1 hour" → "Scheduling unavailable: This mail server does not support scheduled send". - The Scheduled screen and the undo delay use the same check. - **Verified.** -- [ ] **B9 · P1 · S: files shared into the app never upload.** +- [x] **B9 · P1 · S: files shared into the app never upload.** Fixed in `cd4ce9d`, + `3c7b96e`. - Where: `src/api/blob.ts:99` passes the `content://` URI to `createUploadTask`, which requires a file path. `src/lib/share-intent.ts:40` names the file after the URI's last segment. @@ -191,20 +196,23 @@ suspected, or cosmetic. → alert "Failed to upload 1000000027 … IOException: Directory for '/external/images/media/1000000027' doesn't exist". - **Verified.** -- [ ] **B10 · P1 · S: `ACTION_SENDTO mailto:` opens the inbox, not the composer.** +- [x] **B10 · P1 · S: `ACTION_SENDTO mailto:` opens the inbox, not the composer.** + Fixed in `06e8942`. - Where: `android/app/src/main/java/com/anonymous/bulwarkmobile/ShareIntentStore.kt:25` only handles SEND and SEND_MULTIPLE. RN's `Linking` forwards only VIEW. The manifest registers SENDTO anyway. - Repro: `am start -a android.intent.action.SENDTO -d mailto:bob@partner.example` → no composer. The same URI with VIEW works. - **Verified.** -- [ ] **B11 · P2 · S: `mailto:` links with a `+` address do nothing.** +- [x] **B11 · P2 · S: `mailto:` links with a `+` address do nothing.** Fixed in + `ee652d3`. - Where: `src/lib/mailto.ts:21` turns `+` into a space, validation then fails, and the parser returns null. - Web: `lib/validation.ts`. - Repro: `mailto:alice+news@partner.example` → no composer. - **Verified.** -- [ ] **B12 · P1 · S: tasks can't be completed (#958).** +- [x] **B12 · P1 · S: tasks can't be completed (#958).** Fixed in `dcdda5e`, + `a7e4e84`. - Where: `src/stores/calendar-store.ts:710-719` sends `progressUpdated`. The checkbox at `src/components/calendar/TasksSheet.tsx:442` swallows the error. - Web: `6b30e91c`, `stores/task-store.ts`. @@ -212,35 +220,38 @@ suspected, or cosmetic. stays `needs-action` and the UI shows no error. - Tasks are off by default (`src/stores/settings-store.ts:381`), which limits the reach. - **Verified.** -- [ ] **B13 · P1 · M: the Files tab stops at 500 nodes (#1069).** +- [x] **B13 · P1 · M: the Files tab stops at 500 nodes (#1069).** Fixed in + `4eb8c47`, `115e162`. - Where: `src/api/files.ts:98-112` (`FileNode/get ids:null`, which Stalwart silently caps at `maxObjectsInGet`). The same code runs at `:133-167`. - Web: `lib/jmap/client.ts` (`fetchAllFileNodes`, `9893b0a8`). - Repro: with 510 root files created before the folders, `file-0490`–`0499` are listed, while `file-0500`–`0509` and the Documents and Photos folders (and their files) never appear. - **Verified.** -- [ ] **B14 · P2 · S: bodies over 512 KB render cut off with no notice (#884).** +- [x] **B14 · P2 · S: bodies over 512 KB render cut off with no notice (#884).** + Fixed in `4767805`. - Where: `src/api/email.ts:493-499` (`maxBodyValueBytes: 512000`, `isTruncated` never read). - Web: `lib/jmap/client.ts` (`2cf7427e`, refetch of truncated bodies). - Repro: for a 586 KB HTML report, the server returns `isTruncated: true` with 59 characters. The viewer shows the heading, one line and "…"; the list preview shows the full text. - **Verified.** -- [ ] **B15 · P1 · S: a redirect that drops the Authorization header signs the user - out on launch.** +- [x] **B15 · P1 · S: a redirect that drops the Authorization header signs the user + out on launch.** Fixed in `859770b`. - Where: `src/api/jmap-client.ts:737-763`. The retry keys on `response.redirected`, which RN's fetch never sets. An empty session then throws `AuthenticationError`, and `src/stores/auth-store.ts:677-683` evicts the account. - Web: `40e38d16` (#892). - Only affects servers behind a redirecting proxy; direct Stalwart is fine. - **Suspected.** -- [ ] **B16 · P1 · S: "Save draft" discards the text when identities didn't load - (offline) or there is no Drafts folder.** +- [x] **B16 · P1 · S: "Save draft" discards the text when identities didn't load + (offline) or there is no Drafts folder.** Fixed in `92b42e4`: the text is no longer dropped and + the iOS swipe is blocked; saving a draft offline is still impossible. - Where: `src/screens/ComposeScreen.tsx:1208` returns early; `:1288-1290` closes anyway. - On iOS, the `beforeRemove` listener at `:1340` doesn't stop a native swipe-down; that needs `usePreventRemove`. - **Suspected.** -- [ ] **B17 · P1 · S: calendar reminders get cancelled when the calendar view - moves.** +- [x] **B17 · P1 · S: calendar reminders get cancelled when the calendar view + moves.** Fixed in `4b903ed`. - Where: `src/lib/calendar-notifications.ts:116-134` rebuilds the reminder set from the windowed `events` and cancels everything else. - Viewing another month drops all pending reminders. Nothing reschedules them in a session @@ -248,8 +259,8 @@ suspected, or cosmetic. - There is no `setNotificationHandler`, so reminders don't show while the app is in the foreground. - **Suspected.** -- [ ] **B18 · P1 · S: push can end up permanently off for users with ACL-shared - mailboxes.** +- [x] **B18 · P1 · S: push can end up permanently off for users with ACL-shared + mailboxes.** Fixed in `d8046a8`. - Where: `src/lib/push-notifications.ts` (HEAD `:223-229` builds the `emailPush` map from every account with mailboxes). - Stalwart rejects the whole map with `forbidden` for accounts the user doesn't own and isn't @@ -257,31 +268,34 @@ suspected, or cosmetic. fails the same way. - Web: `lib/web-push.ts:86-94` has the same code. - **Suspected.** -- [ ] **B19 · P2 · S: "Reschedule" drops Cc and Bcc.** +- [x] **B19 · P2 · S: "Reschedule" drops Cc and Bcc.** Fixed in `e67947a`, + `7e598c5`. - Where: `src/api/email.ts:1393` rebuilds recipients from `scheduled.to`; `src/screens/ScheduledScreen.tsx:140`. - Web: `lib/jmap/client.ts` (reuses the envelope). - Unreachable on Stalwart until B8 is fixed. - **Suspected.** -- [ ] **B20 · P2 · S: "Load more" skips messages in Unread and Starred views.** +- [x] **B20 · P2 · S: "Load more" skips messages in Unread and Starred views.** + Fixed in `35e0792`. - Where: `src/stores/email-store.ts:776` uses `position: emails.length`, which counts rows that were kept after they stopped matching the query. - **Suspected.** -- [ ] **B21 · P2 · S: the event editor wipes what the user typed when a calendar push - or the alias lookup arrives.** +- [x] **B21 · P2 · S: the event editor wipes what the user typed when a calendar push + or the alias lookup arrives.** Fixed in `15717f1`. - Where: `src/components/calendar/EventModal.tsx:231-273` (the reset effect depends on `calendars` and `currentUserEmails`). - **Suspected.** -- [ ] **B22 · P2 · S: an invitation's Accept sends no RSVP when the event is outside - the loaded calendar window, yet says "Added to calendar".** +- [x] **B22 · P2 · S: an invitation's Accept sends no RSVP when the event is outside + the loaded calendar window, yet says "Added to calendar".** Fixed in `c0582ab`. - Where: `src/components/email/CalendarInvitationBanner.tsx:177-188`. - **Suspected.** -- [ ] **B23 · P2 · S: "Send failed" can be shown for mail that was sent, so a retry - sends it twice.** +- [x] **B23 · P2 · S: "Send failed" can be shown for mail that was sent, so a retry + sends it twice.** Fixed in `c51a848`. - Where: `src/api/email.ts:1178-1181` throws on any `error` response. Stalwart appends one when `onSuccessUpdateEmail` fails after a successful submission. - **Suspected.** -- [ ] **B24 · P3 · S: some writes report success when the server refused them.** +- [x] **B24 · P3 · S: some writes report success when the server refused them.** + Fixed in `00ad2f4` (files), `a6ef0ab` (calendar), `ddfe85a` (push). - Where: `src/api/files.ts:199` and `:225` (rename, move, delete read `[0][1]` without checking for an `error` response); `src/api/calendar.ts:449-459` ignores `notDestroyed`; `src/api/push.ts:14,82,105`. @@ -289,7 +303,8 @@ suspected, or cosmetic. ### UI glitches -- [ ] **U1 · P2 · S: the cold-start sequence shows a blank screen and jumps twice.** +- [x] **U1 · P2 · S: the cold-start sequence shows a blank screen and jumps twice.** + Fixed in `b9db376`, `f2dd3a8`. - Where: `App.tsx:613-620`; `AppTheme` has no `windowBackground`; `PushOnboardingPrompt`. - Frames: - The dark splash is followed by about 1 s of blank white. @@ -297,36 +312,38 @@ suspected, or cosmetic. - The header then pops in and pushes the list down. - The notification card lands over the status bar and pushes the list down again. - **Verified** (`screenrecord`). -- [ ] **U2 · P2 · S: opening a message shows a skeleton, then a 120 px strip of body, - then the full body.** +- [x] **U2 · P2 · S: opening a message shows a skeleton, then a 120 px strip of body, + then the full body.** Fixed in `54b169c`, `ac8e3fb`. - Where: `src/components/EmailBodyView.tsx:588-591` (the height resets to 120 on every message). - The header data is already in the list row but isn't used. The quick-reply box jumps as the WebView grows. See PF1. - **Verified.** -- [ ] **U3 · P2 · S: sender image and table widths are overridden.** +- [x] **U3 · P2 · S: sender image and table widths are overridden.** Fixed in + `7531118`. - Where: `src/lib/email-html.ts:452-454`. `img { max-width: 100% !important }` beats inline `max-width`. - Web: `68341a0b`, `ab4bf91b` (#790). - Repro: an image with `max-width:200px; max-height:134px; width:100%` renders full width and squashed about 1.9×; a table with `max-width:300px` spans the pane. - **Verified.** -- [ ] **U4 · P2 · S: RTL mail renders left-to-right.** +- [x] **U4 · P2 · S: RTL mail renders left-to-right.** Fixed in `910c503`. - Where: `src/lib/email-html.ts:627` and `:686` (no `dir="auto"`). - Web: `e2990da5`, `48048f16`. - Repro: an Arabic plain-text body is left-aligned and its sentence-final period sits on the wrong side. - **Verified.** -- [ ] **U5 · P3 · S: list previews keep the server's newlines.** +- [x] **U5 · P3 · S: list previews keep the server's newlines.** Fixed in `d45c799`. - Rows show a dangling "…" line and have uneven heights ("Q3 revenue is up 12 %.\n\n…"). - A subject that contains CR/LF also renders over several lines in the list and the viewer. - Where: `src/screens/EmailListScreen.tsx` row. - **Verified.** -- [ ] **U6 · P3 · S: the schedule sheet offers presets, then refuses them.** +- [x] **U6 · P3 · S: the schedule sheet offers presets, then refuses them.** Fixed in + `802b199`, `4e7ae2f`. - Where: `src/screens/ComposeScreen.tsx:1846-1851`. The sheet should hide the presets. - **Verified.** -- [ ] **U7 · P3 · S: Back in Files selection mode switches to the Mail tab instead of - clearing the selection.** +- [x] **U7 · P3 · S: Back in Files selection mode switches to the Mail tab instead of + clearing the selection.** Fixed in `8d7fbfc`, `4fdf39a`. - **Verified.** - [ ] **U8 · P3 · M: icon buttons and switches have no accessibility label.** - Unlabeled controls: @@ -338,7 +355,8 @@ suspected, or cosmetic. - Web: `4947c6c7`. - Repro: `uiautomator dump` shows an empty `content-desc` on all of these. - **Verified.** -- [ ] **U9 · P3 · S: Android notifications use the stock envelope as their small icon.** +- [x] **U9 · P3 · S: Android notifications use the stock envelope as their small + icon.** Fixed in `695aa23`. - Where: `android/app/src/main/java/com/anonymous/bulwarkmobile/BulwarkFcmModule.kt:128` and `:181` (`android.R.drawable.ic_dialog_email`). - **Suspected.** @@ -348,8 +366,9 @@ suspected, or cosmetic. All numbers come from the x86_64 emulator with a release build and a local server. Use them to compare against each other, not as phone numbers. -- [ ] **PF1 · P1 · M: opening a message takes 1.65–1.87 s from tap to a settled - screen.** +- [x] **PF1 · P1 · M: opening a message takes 1.65–1.87 s from tap to a settled + screen.** Fixed in `33e303e`, `ac8e3fb`, `1348e7d`, `01fc6fb`, `6ebadf7`, `54b169c`, `7cdebc4`, + `b7a5953`; not re-timed on a device yet. - Where: `src/screens/EmailThreadScreen.tsx:161-199` (a network-first detail fetch even for cached ids, plus a thread fetch with full bodies), `:641` (the pager mounts 3 panes, each with its own WebView), `src/components/EmailBodyView.tsx:588-591` (the body is sanitized @@ -363,8 +382,11 @@ compare against each other, not as phone numbers. - One open from the Unified Inbox made 12 requests: the body twice, the thread twice, `Identity/get`, and a forbidden `x:Account/get`. - **Verified** (numbers and requests); causes suspected. -- [ ] **PF2 · P1 · M: cold start takes 3.6 / 3.8 / 4.1 s from launch to a settled - inbox (3 runs).** +- [x] **PF2 · P1 · M: cold start takes 3.6 / 3.8 / 4.1 s from launch to a settled + inbox (3 runs).** Fixed in `604eb39`, `063432b`, `5bcfe1f`, `82ca359`, `b9db376`, `9c2f819`: + modules run before the first frame 3,590 → 1,516, Hermes bundle 9.34 → 7.61 MB, a headless push + start 202 modules (`npx expo export`). The four hydrations were already awaited together + (`85f23df`). Not re-timed on a device yet. - Measured: - `am start` reports 451–564 ms to the first frame (the splash). - Cached rows at about +1.2 s. @@ -383,7 +405,9 @@ compare against each other, not as phone numbers. - The headless push task imports the whole app (`index.ts:10`). - **Verified** (device timings; bundle shares measured by rebuilding the bundle with hermesc and removing module groups one at a time). -- [ ] **PF3 · P2 · M: the mail list is heavier than the emulator floor.** +- [ ] **PF3 · P2 · M: the mail list is heavier than the emulator floor.** Partly: + `cb9a741`, `aa25075`, `ebd8dac` fix the inline callbacks, the swipe bands and the per-row date + formatters; the swipe drag still runs on the JS thread, and nothing was re-measured. - Measured over already-loaded rows (14 flings): p50 21 ms, p90 32 ms, p95 38 ms, p99 57 ms. The same flings in the system Settings list: 17 / 18 / 20 / 36 ms. - Causes: @@ -394,20 +418,24 @@ compare against each other, not as phone numbers. - Row dates build two `Intl` formatters per row (`src/lib/date-format.ts:75-97`). - The PanResponder drag runs on the JS thread (`src/components/SwipeableRow.tsx:170-172`). - **Verified** (numbers); causes suspected. -- [ ] **PF4 · P2 · S: hidden screens keep rendering.** +- [ ] **PF4 · P2 · S: hidden screens keep rendering.** Partly: `4a5d837` adds + `freezeOnBlur` and a count-only badge selector; the list directly under an open message stays live + on Fabric, and `fetchMailboxes` still sets a new array on every fetch. - Where: there is no `enableFreeze` or `freezeOnBlur` (`App.tsx:634`, `index.ts`). - The tab navigator subscribes to the whole `mailboxes` array to compute one badge (`App.tsx:127`), and `src/stores/email-store.ts:1855` sets a new array on every mailbox fetch. - So every refresh also re-renders the mail list under an open message. - **Suspected.** -- [ ] **PF5 · P2 · S–M: every store write re-serializes the whole persisted cache.** +- [x] **PF5 · P2 · S–M: every store write re-serializes the whole persisted cache.** + Fixed in `48825e9`, `e37621b`. - Where: `src/stores/email-store.ts:1723-1731` (the email cache, with the current folder stored twice), `src/stores/contacts-store.ts:824-829`, `src/stores/calendar-store.ts:769-775`. This includes `loading` flips; there is no debounce. - Opening one unread message causes about 5 full writes. - **Suspected.** The stringify cost was measured off-device: 1.25 ms for 425 rows in V8. -- [ ] **PF6 · P2 · S: requests that can be cut, all seen on the wire.** +- [x] **PF6 · P2 · S: requests that can be cut, all seen on the wire.** Fixed in + `d097ae9`, `668e010`, `1c7c2a3`, `018accd`, `3bf2c30`, `1196ad5`, `9fa931c`. - Every drawer open sends 14 `Email/query` calls for tag counts. - The Contacts tab re-downloads all cards (58 KB) on every open, although they load at startup. @@ -422,7 +450,8 @@ compare against each other, not as phone numbers. - There is a 30 s `Core/echo` on top of the SSE pings (`App.tsx:581-596`). - Backgrounding is fine: no requests during 40 s in the background. - **Verified.** -- [ ] **PF7 · P2 · S: every list page and every search is 3 sequential requests.** +- [x] **PF7 · P2 · S: every list page and every search is 3 sequential requests.** + Fixed in `d987930`, `4f3940f`, `9c2f819`. - The chain is `Email/query` → `Email/get` → `Thread/get` (the last one fired after render). First login adds two `Mailbox/get` and a 500 ms gap. - Where: `src/stores/email-store.ts:2049-2060`, `src/screens/EmailListScreen.tsx:339-358`. @@ -430,8 +459,8 @@ compare against each other, not as phone numbers. `#ids /list/*/threadId` in one request). RN's `src/api/unified-inbox.ts:383-397` already chains query and get. - **Verified.** -- [ ] **PF8 · P2 · M: each keystroke in the composer re-renders the 3,000-line - screen twice.** +- [x] **PF8 · P2 · M: each keystroke in the composer re-renders the 3,000-line + screen twice.** Fixed in `fc00781`. - Where: `src/lib/editor-html.ts:160-168` posts the full `innerHTML` on every input and on every selection change; `src/screens/ComposeScreen.tsx:2276-2277`. - `htmlToPlainText` and a `JSON.stringify` snapshot also run on every render. @@ -441,7 +470,9 @@ compare against each other, not as phone numbers. - Contents: 25.85 MB of unminified dex, 24,621 classes; the ML Kit barcode scanner accounts for 5.83 MB. The UnifiedPush work in progress adds 3,009 classes (Tink, protobuf). - **Verified** (APK inspection of the published 0.1.62). -- [ ] **PF10 · P3 · S: slow paths that need large data to show.** +- [ ] **PF10 · P3 · S: slow paths that need large data to show.** Partly: contacts + search (`e6be892`) and bulk read/star (`cb2f03b`) are fixed; upload progress and the offline-cache + index writes are unchanged. - Contacts search re-sorts with `localeCompare` on every keystroke (`src/stores/contacts-store.ts:923-925`). - Bulk mark-read and star send N requests against a concurrency limit of 4 @@ -458,12 +489,14 @@ wrongly). Items already listed under Bugs are only cross-referenced here. ### Auth and accounts -- [ ] **P2 · S · missing: adding a second OAuth account silently signs in the same user again.** +- [x] **P2 · S · missing: adding a second OAuth account silently signs in the same user again.** + Fixed in `ab84578`. - Where: `src/lib/oauth-native.ts:127-141` (no `prompt=select_account`, no ephemeral browser session). - Web: `5771a213`. - **Suspected.** -- [ ] **P3 · S · partial: a pasted `…/jmap/session` URL fails discovery with a 404.** +- [x] **P3 · S · partial: a pasted `…/jmap/session` URL fails discovery with a 404.** Fixed in + `bd42206`. - Where: `src/lib/server-discovery.ts:59-63`. - Web: `b26c1746` (#971). - **Suspected.** @@ -471,37 +504,43 @@ wrongly). Items already listed under Bugs are only cross-referenced here. ### Mail list, folders and search -- [ ] **P2 · L · diverges: "All folders" search only covers the open folder's account (#1082).** +- [x] **P2 · L · diverges: "All folders" search only covers the open folder's account (#1082).** + Fixed in `ee50418`, `edab181`, `d2066da`. - Where: `src/stores/email-store.ts:384-389`. - Web: `lib/unified-mailbox.ts` (`searchAcrossAccounts`, `9ef7068b`). - Repro: "zephyr" with All folders → `Email/query` on account `c` only → 3 hits. The 5 matches in the team inbox are missing. - **Verified.** -- [ ] **P2 · M · diverges: the tag view and tag badges only cover one account (#1038).** +- [x] **P2 · M · diverges: the tag view and tag badges only cover one account (#1038).** Fixed in + `8d5bced`, `d097ae9`. - Where: `src/stores/email-store.ts:209` and `:387`, `src/components/SidebarDrawer.tsx:426-436`. - Web: `stores/email-store.ts` (`fetchTagEmails`, `fedfc89d`). - Repro: 2 own and 2 team messages tagged Red → the Red view shows 2. - **Verified.** -- [ ] **P3 · S · missing: folders created on the phone are not subscribed.** +- [x] **P3 · S · missing: folders created on the phone are not subscribed.** Fixed in `30aea63`. - Where: `src/api/email.ts:211-221` sends no `isSubscribed: true`, so IMAP clients hide them. - Web: `2b186910` (#951). - **Suspected.** -- [ ] **P3 · S · diverges: archiving to a role-less "Archives" folder is offered but does nothing.** +- [x] **P3 · S · diverges: archiving to a role-less "Archives" folder is offered but does nothing.** + Fixed in `9f75e70`, `ad1f053`. - Where: the list matches by name (`src/screens/EmailListScreen.tsx:393-395`), but the store needs the role or the exact name (`src/stores/email-store.ts:1202-1205`). - Web: `2b32a011` (#578). - **Suspected.** -- [ ] **P3 · S · missing: no unread badge on the app icon.** +- [ ] **P3 · S · missing: no unread badge on the app icon.** Partly: `25c0883` badges the icon on + iOS; Android is left to the launcher (see the fix-pass decisions). - expo-notifications `setBadgeCountAsync` is already available. - Web: `hooks/use-app-badge.ts` (`e7d37823`). - **Suspected.** -- [ ] **P3 · S · missing: list rows show no attachment chips.** +- [x] **P3 · S · missing: list rows show no attachment chips.** Fixed in `b1fb2e9`, `edab181` (not + yet on Unified Inbox rows). - Web: `0e1c34cd`. - **Suspected.** -- [ ] **P3 · S · missing: no "clear search when switching folders" setting.** +- [x] **P3 · S · missing: no "clear search when switching folders" setting.** Fixed in `4e64261`. - Web: `12f01409`. - **Suspected.** -- [ ] **P3 · S · diverges: the Unified section shows even when it can't be populated.** +- [x] **P3 · S · diverges: the Unified section shows even when it can't be populated.** Fixed in + `af6290f`. - Where: `src/components/SidebarDrawer.tsx:639`. - Web: `f3f0127c` (#843). - **Suspected.** @@ -510,34 +549,36 @@ wrongly). Items already listed under Bugs are only cross-referenced here. ### Viewer -- [ ] **P2 · M · missing: no per-message HTML/plain-text toggle, and reopened drafts are forced into - the global format.** +- [x] **P2 · M · missing: no per-message HTML/plain-text toggle, and reopened drafts are forced into + the global format.** Fixed in `472c4d8`. - Where: `src/screens/ComposeScreen.tsx:531-536`. With plain text on, an HTML draft is flattened on its first autosave. - Web: `f6ad8a59` (#1022), `components/email/compose-format.ts`. - **Suspected.** -- [ ] **P2 · S · missing: sender avatars ignore address-book photos (#54).** +- [x] **P2 · S · missing: sender avatars ignore address-book photos (#54).** Fixed in `eca3871`. - Web: `components/ui/avatar.tsx` (looks up the sender's contact photo by email; the photo wins over favicons and initials). - Repro: Alice Nguyen's contact photo shows in Contacts; her mail shows "AN" initials. - **Verified.** -- [ ] **P2 · S · diverges: the viewer's Spam button is a plain move.** +- [x] **P2 · S · diverges: the viewer's Spam button is a plain move.** Fixed in `5e42c67`. - It sends no `$junk`/`$notjunk` flip and doesn't honour trash-and-read. - Where: `src/screens/EmailThreadScreen.tsx:395-407`. The list and swipe paths are right (`src/stores/email-store.ts:1058-1146`). - Web: `150c25ca` (#695). - **Suspected.** -- [ ] **P2 · S · diverges: viewer Archive silently does nothing for messages that are not in the - loaded list.** +- [x] **P2 · S · diverges: viewer Archive silently does nothing for messages that are not in the + loaded list.** Fixed in `33d2674`. - This covers the unified inbox, notification taps and deep links. - Where: `src/stores/email-store.ts:1196-1197`. - Web: `150c25ca`. - **Suspected.** -- [ ] **P3 · S · partial: failed actions and sends give no feedback.** +- [x] **P3 · S · partial: failed actions and sends give no feedback.** Fixed in `9e95273`, + `cd911ad`. - The store actions are called with `void`, and there is no "Email sent" toast. - Web: `ec67ab99`, `b03a0c1d`, `lib/email-action-toast.ts`. - **Verified** (no toast after send); failure path suspected. -- [ ] **P3 · S · missing: body-embedded `cid:` parts typed octet-stream appear as nameless chips.** +- [x] **P3 · S · missing: body-embedded `cid:` parts typed octet-stream appear as nameless chips.** + Fixed in `1d1d6a5`. - Where: `src/lib/attachment-display.ts:91-104`. - Web: `1c00812a`. - **Suspected.** @@ -545,26 +586,29 @@ wrongly). Items already listed under Bugs are only cross-referenced here. ### Composer -- [ ] **P2 · S · diverges: replies go out from the default identity unless "Reply from received - address" is on.** +- [x] **P2 · S · diverges: replies go out from the default identity unless "Reply from received + address" is on.** Fixed in `a0c2bd7`. - Forward also rewrites the From address, and replies to your own sent mail resolve from the other party. - Where: `src/screens/ComposeScreen.tsx:836-845`, `src/lib/reply-identity.ts:46-77,170`. - Web: `4fc7b8b5`, `lib/reply-identity.ts`. - **Suspected.** -- [ ] **P3 · S · missing: a new message in a shared folder doesn't default to that mailbox's - identity.** +- [x] **P3 · S · missing: a new message in a shared folder doesn't default to that mailbox's + identity.** Fixed in `0ffdcac`. - Where: `findComposeIdentityId` is ported but never called. - Web: `129f545a`. - **Suspected.** -- [ ] **P3 · S · missing: no exact-address vs same-domain choice for "reply from received".** +- [x] **P3 · S · missing: no exact-address vs same-domain choice for "reply from received".** Fixed + in `2d907ff`. - Web: `565d5c10` (#1000). - **Suspected.** - [ ] **P3 · M · partial: no font-size picker or background colour; 8 text colours instead of 16.** + Partly: `548b647` adds the background colour and the 16 text colours; the font-size picker is not + ported. - Where: `src/components/RichTextEditor.tsx:8-26`. - Web: `7e0a86a6`, `3957b358`. - **Suspected.** -- [ ] **P3 · S · diverges: quick replies carry no signature.** +- [x] **P3 · S · diverges: quick replies carry no signature.** Fixed in `3faac98`. - Where: `src/components/email/QuickReplyBox.tsx:79-90`. - **Suspected.** - [ ] **P3 · S · partial: the undo-send snackbar exists only on the list screen.** @@ -575,55 +619,58 @@ wrongly). Items already listed under Bugs are only cross-referenced here. ### Calendar -- [ ] **P2 · S · missing: CalDAV tasks with `COMPLETED`, `NEEDS_ACTION` or `canceled` count as - pending and toggle the wrong way.** +- [x] **P2 · S · missing: CalDAV tasks with `COMPLETED`, `NEEDS_ACTION` or `canceled` count as + pending and toggle the wrong way.** Fixed in `1b64c14`. - Web: `5f1d2795` (`normalizeCalendarTask`). - **Suspected.** -- [ ] **P3 · L · missing: no free-scrolling month, week or day views (#759) and no setting for them.** +- [x] **P3 · L · missing: no free-scrolling month, week or day views (#759) and no setting for + them.** Fixed in `caf61ec`, `de3d697`. - Where: `src/screens/CalendarScreen.tsx:89,169-171,360-374`. - Web: `15a5497a`, `ae403b06`, `hooks/use-scroll-window.ts`. - **Suspected.** -- [ ] **P3 · M · missing: the agenda is a fixed 30-day page instead of infinite scroll.** +- [x] **P3 · M · missing: the agenda is a fixed 30-day page instead of infinite scroll.** Fixed in + `71522b9`. - Where: `src/components/calendar/AgendaView.tsx:46`. - Web: `60e05c00`. - **Suspected.** -- [ ] **P3 · L · diverges: recurring events are always expanded client-side.** +- [x] **P3 · L · diverges: recurring events are always expanded client-side.** Fixed in `8454889`, + `f397ee3`, `96c5a3f`. - Where: `src/api/calendar.ts:267-304`, `src/lib/recurrence-expansion.ts`. - This matches the webmail's pre-0.16.20 fallback, but there is no server-side expansion and no per-occurrence edit through synthetic ids. - Web: `lib/recurrence-instances.ts`. - **Suspected.** -- [ ] **P3 · S · partial: participants aren't deduplicated or matched to contact names, and the - organizer's status dot is wrong.** +- [x] **P3 · S · partial: participants aren't deduplicated or matched to contact names, and the + organizer's status dot is wrong.** Fixed in `1d755fc`. - Where: `src/lib/calendar-participants.ts:130-167`. - Web: `8cbc5bc5`, `6f99c017`. - **Suspected.** -- [ ] **P3 · S · diverges: a task's due time shows the raw Europe/Berlin wall time (17:00), while - events are converted to the device zone.** +- [x] **P3 · S · diverges: a task's due time shows the raw Europe/Berlin wall time (17:00), while + events are converted to the device zone.** Fixed in `6a975b8`, `1a651a9`, `a8e6f6e`. - **Suspected.** - Links in event descriptions are fixed on GitHub `main` (`c2584c2`) but not in this checkout. - Also see B12, B17, B21, B22. ### Contacts -- [ ] **P2 · S · partial: the vCard FN (`name.full`) is missing or stale on form, "add sender" and - import writes (#430).** +- [x] **P2 · S · partial: the vCard FN (`name.full`) is missing or stale on form, "add sender" and + import writes (#430).** Fixed in `a734d0a`. - Where: `src/screens/ContactFormScreen.tsx:288-293`, `src/lib/vcard.ts:575-603`. - Web: `a210b22e`. - **Suspected.** -- [ ] **P3 · S · missing: no sort by last name (#963).** +- [x] **P3 · S · missing: no sort by last name (#963).** Fixed in `1827748`. - Where: `src/stores/contacts-store.ts:923-925`. - Web: `fb24ef5d`. - **Suspected.** -- [ ] **P3 · S · missing: a new contact made while viewing address book X lands in the default - book.** +- [x] **P3 · S · missing: a new contact made while viewing address book X lands in the default + book.** Fixed in `c888e95` (groups: `a3193eb`). - Where: `src/screens/ContactsScreen.tsx:238,396`. - Web: `494adb9b`. - **Suspected.** ### Files -- [ ] **P2 · S · diverges: sharing with other users is never offered.** +- [x] **P2 · S · diverges: sharing with other users is never offered.** Fixed in `caea3d0`. - Where: `src/api/files.ts:30-35` and `src/components/calendar/CalendarShareSheet.tsx:86` gate on `principals:owner`, which Stalwart advertises nowhere. The session only has `principals` and `principals:availability`. @@ -631,44 +678,47 @@ wrongly). Items already listed under Bugs are only cross-referenced here. - Repro: the per-file menu shows Preview/Share (OS), Download, Move, Duplicate, Rename, Delete, and no "Share with…". - **Verified.** -- [ ] **P3 · M · missing: no in-app file preview.** +- [x] **P3 · M · missing: no in-app file preview.** Fixed in `409cdb1` (images, text, and PDFs on + iOS; Android PDFs, audio and video still go to another app). - Tapping a file downloads it and opens the OS "Open with" chooser. - **Verified.** - Also see B13 (500-node cap). WOPI editing (#425) is listed under open questions. ### Filters and vacation -- [ ] **P2 · S · missing: "Keep" is still written as `keep;`.** +- [x] **P2 · S · missing: "Keep" is still written as `keep;`.** Fixed in `f63d739`. - Saving filters on the phone therefore undoes the webmail fix for allow-list rules. - Where: `src/lib/sieve/generator.ts:131-132`. - Web: `62465e1e` (#1027). - **Suspected.** -- [ ] **P3 · M · missing: no filters or vacation for shared/group accounts.** +- [x] **P3 · M · missing: no filters or vacation for shared/group accounts.** Fixed in `a86cd1d`. - Where: `src/api/sieve.ts:20-23`, `src/api/vacation.ts:26-27`. - **Suspected.** ### Settings, themes and i18n -- [ ] **P2 · M · partial: locale catalogs are stale.** +- [x] **P2 · M · partial: locale catalogs are stale.** Fixed in `55f1ec4`, `008bff2`, `67935d2`. - Last synced 2026-08-29 (`990cd84`): 2,959 keys against the webmail's 3,065. The German update changed 59 values. - `email_viewer.forward_as_attachment` is still English in about 25 locales. - The 567 RN-only keys are English in every locale (`src/i18n/index.ts:98-100`). - Fix: run `scripts/sync-locales.mjs` and translate the RN overlay. - **Suspected.** -- [ ] **P3 · S · partial: the Reading pane hard-codes English.** +- [x] **P3 · S · partial: the Reading pane hard-codes English.** Fixed in `2511df1`. - Labels such as "Message Spacing", "Read Receipts" and "Always send" don't go through `t()` (`src/components/settings/ReadingSettings.tsx:305-327`). - **Verified.** -- [ ] **P3 · S · diverges: plural forms probably fall back to English rules.** +- [x] **P3 · S · diverges: plural forms probably fall back to English rules.** Fixed in `e6549d3`. - Where: `src/i18n/format.ts:18-47`. Hermes on Android has no `Intl.PluralRules`, so Russian shows "2 писем". - **Suspected.** -- [ ] **P3 · M · missing: only 4 of the webmail's 7 built-in themes, and no "Flat fields".** +- [ ] **P3 · M · missing: only 4 of the webmail's 7 built-in themes, and no "Flat fields".** Partly: + `7964e64` adds Roundcube Elastic and Aurora Glass; "Flat fields" is not ported (a product + decision). - Where: `src/theme/builtin-themes.ts`. - Web: `ab67d9b0`, `lib/theme-flat-fields.ts`. - **Suspected.** -- [ ] **P3 · M · missing: no settings search.** +- [x] **P3 · M · missing: no settings search.** Fixed in `46e285b`. - Web: `lib/settings-search.ts`. - **Suspected.** - [ ] **P3 · L · diverges: native still uses Lucide icons; the webmail moved to Tabler (`d7548a4b`).** @@ -677,27 +727,28 @@ wrongly). Items already listed under Bugs are only cross-referenced here. ### Push -- [ ] **P1 · S · diverges: tapping a group-mailbox notification opens the message against the wrong - account.** +- [x] **P1 · S · diverges: tapping a group-mailbox notification opens the message against the wrong + account.** Fixed in `8618abf`. - The tap payload carries only the registry account, not the JMAP account. - Where: `src/lib/push-background-task.ts:448-460`, `App.tsx:85-89`. - Web: `b4f12b67` (#839). - **Suspected.** -- [ ] **P2 · S · diverges: `emailPush` is never read back, so the subscription is re-patched on - every launch.** +- [x] **P2 · S · diverges: `emailPush` is never read back, so the subscription is re-patched on + every launch.** Fixed in `ccaa24e`. - `using` also lacks the emailpush capability. - Where: `src/api/push.ts:11` (`PushSubscription/get` with default properties). - Web: `lib/jmap/client.ts` (explicit properties). - **Suspected.** -- [ ] **P2 · S · diverges: revoking a device or disabling one account doesn't stick.** +- [x] **P2 · S · diverges: revoking a device or disabling one account doesn't stick.** Fixed in + `a3d3af7`. - Setup re-runs for the active account on every launch (HEAD `App.tsx:447-453`). - **Suspected.** - UnifiedPush (#44, #48) exists only as uncommitted work in this tree. Also see B18. ### Security -- [ ] **S1 · P0 · S · missing: the GHSA-w38p fix (read-receipt header injection) was - never ported.** +- [x] **S1 · P0 · S · missing: the GHSA-w38p fix (read-receipt header injection) was + never ported.** Fixed in `cb6ddd6`. - Where: `src/lib/mdn.ts:77-81` (`encodeHeaderWord` passes pure-ASCII values, CR/LF included, through raw), `:111-113`, `:140-141`. - Web: `lib/mdn.ts` (`stripHeaderControls`, `headerAtom`; `53a6670e`). @@ -709,7 +760,9 @@ wrongly). Items already listed under Bugs are only cross-referenced here. - With B7 this becomes zero-click: the malicious message only needs to sit next to one the user opens. - **Verified.** -- [ ] **S2 · P0 · S–M: releases are signed with the public React Native debug key.** +- [x] **S2 · P0 · S–M: releases are signed with the public React Native debug key.** + Fixed in `6f0abb4`, `746572c`, `5237848`; the release key, rotation lineage and secrets still have + to be created before the next release (`docs/android-release.md`). - Where: `android/app/build.gradle:103-125`; `.github/workflows/release-android.yml:69-91` falls back to it silently when `ANDROID_KEYSTORE_BASE64` is empty; `android/app/build.gradle:98` (`versionCode 1`). @@ -721,24 +774,27 @@ wrongly). Items already listed under Bugs are only cross-referenced here. - Fix: a private key, a workflow that fails without it, v3 key rotation for existing installs, and a `versionCode` derived from `VERSION`. - **Verified.** -- [ ] **P2 · S · diverges: "Sync trusted senders to address book" trusts every contact in every - book.** +- [x] **P2 · S · diverges: "Sync trusted senders to address book" trusts every contact in every + book.** Fixed in `d89e331`. - Remote images and tracking pixels then load for any contact, including a spoofed From. - The toggle switches itself on the first time the Content & Senders pane is opened on a contacts-capable account (`src/components/settings/ContentSendersSettings.tsx:54-57`). - Where: `src/components/EmailBodyView.tsx:533-544,562-566`. - Web: `components/email/email-viewer.tsx` (only the Trusted Senders book counts). - **Suspected.** -- [ ] **P2 · S · missing: replying or forwarding loads the remote images the viewer blocked.** +- [x] **P2 · S · missing: replying or forwarding loads the remote images the viewer blocked.** Fixed + in `235f4ea`. - The editor page has no CSP (`src/components/RichTextEditor.tsx:223-253`, `src/lib/editor-html.ts:29-35`). - **Suspected.** - [ ] **P2 · S · diverges: the webmail-to-app sign-in hand-off puts the password in the - `bulwarkmobile://…#password=` fragment.** + `bulwarkmobile://…#password=` fragment.** Open: needs a one-time code exchange on the webmail + side; no app change in this pass. - Where: `src/lib/oauth.ts:139-146`. The webmail side is `app/(main)/[locale]/login/page.tsx`. - **Suspected.** - [ ] **P3 · S · diverges: list and notification favicons are fetched from icons.duckduckgo.com on - the device.** + the device.** Partly: `95c24a4` makes notifications honour the Sender Favicons switch; with it on + (still the default) the phone fetches from DuckDuckGo. - This leaks sender domains and the device IP to a third party. - Where: `src/lib/avatar-utils.ts:138-139`. - Web: server-side `/api/favicon`. @@ -753,34 +809,38 @@ spot-check covered 35 ticks plus the ones re-tested on the device. ### Ticked, but broken -- [ ] `docs/parity/03-email-viewer.md:107`, read receipts: sent unsanitized, and sent for unseen - neighbour panes (S1, B7). **Verified.** -- [ ] `docs/parity/02-mail-list-folders.md:112` and `docs/parity/03-email-viewer.md:15`, pager and +- [x] `docs/parity/03-email-viewer.md:107`, read receipts: sent unsanitized, and sent for unseen + neighbour panes (S1, B7). **Verified.** Fixed in `cb6ddd6`, `5f3f584`. +- [x] `docs/parity/02-mail-list-folders.md:112` and `docs/parity/03-email-viewer.md:15`, pager and wrong-message fixes: the body is right, but actions still hit the wrong account and message - (B3, B5). **Verified.** -- [ ] `docs/parity/05-calendar.md:268`, task edit/toggle: completing fails (B12). **Verified.** -- [ ] `docs/parity/08-settings-push-i18n-ui.md:297`, deep links, mailto and share targets: SENDTO, - shared files and `+` addresses all fail (B9–B11). **Verified.** -- [ ] `docs/parity/07-filters-vacation-files.md:177` ("Verified at parity: `FileNode/get + (B3, B5). **Verified.** Fixed in `5c7301b`, `9c31de2`. +- [x] `docs/parity/05-calendar.md:268`, task edit/toggle: completing fails (B12). **Verified.** + Fixed in `dcdda5e`. +- [x] `docs/parity/08-settings-push-i18n-ui.md:297`, deep links, mailto and share targets: SENDTO, + shared files and `+` addresses all fail (B9–B11). **Verified.** Fixed in `cd4ce9d`, `06e8942`, + `ee652d3`. +- [x] `docs/parity/07-filters-vacation-files.md:177` ("Verified at parity: `FileNode/get ids:null`"): capped at 500 (B13). Its claim that `/query` drops folders has been outdated since - Stalwart 0.16.6. **Verified.** -- [ ] `docs/parity/02-mail-list-folders.md:244`, search all folders (#788): scope is one account - (#1082 above). **Verified.** -- [ ] `docs/parity/02-mail-list-folders.md:187`, `$junk`/`$notjunk` flip: the viewer's buttons - still do a plain move. **Suspected.** -- [ ] `docs/parity/01-auth-accounts.md:57` and `docs/parity/09-jmap-core-sync-security.md:99`, - redirect with a dropped Authorization header (B15). **Suspected.** -- [ ] `docs/parity/04-composer-send.md:12`, draft autosave: loses text offline, and iOS swipe-down - bypasses the dialog (B16). **Suspected.** -- [ ] `docs/parity/04-composer-send.md:224`, reschedule: drops Cc and Bcc (B19). **Suspected.** -- [ ] `docs/parity/05-calendar.md:261`, reminders: cancelled when the view moves (B17). - **Suspected.** -- [ ] `docs/parity/06-contacts.md:259`, trusted-senders book: trusts every contact (Security). - **Suspected.** -- [ ] `docs/parity/08-settings-push-i18n-ui.md:139` and `:154`, push types and the `emailPush` - filter: never read back, and breaks for ACL-shared accounts (B18). **Suspected.** + Stalwart 0.16.6. **Verified.** Fixed in `4eb8c47`. +- [x] `docs/parity/02-mail-list-folders.md:244`, search all folders (#788): scope is one account + (#1082 above). **Verified.** Fixed in `ee50418`. +- [x] `docs/parity/02-mail-list-folders.md:187`, `$junk`/`$notjunk` flip: the viewer's buttons + still do a plain move. **Suspected.** Fixed in `5e42c67`. +- [x] `docs/parity/01-auth-accounts.md:57` and `docs/parity/09-jmap-core-sync-security.md:99`, + redirect with a dropped Authorization header (B15). **Suspected.** Fixed in `859770b`. +- [x] `docs/parity/04-composer-send.md:12`, draft autosave: loses text offline, and iOS swipe-down + bypasses the dialog (B16). **Suspected.** Fixed in `92b42e4`. +- [x] `docs/parity/04-composer-send.md:224`, reschedule: drops Cc and Bcc (B19). **Suspected.** + Fixed in `e67947a`, `7e598c5`. +- [x] `docs/parity/05-calendar.md:261`, reminders: cancelled when the view moves (B17). + **Suspected.** Fixed in `4b903ed`. +- [x] `docs/parity/06-contacts.md:259`, trusted-senders book: trusts every contact (Security). + **Suspected.** Fixed in `d89e331`. +- [x] `docs/parity/08-settings-push-i18n-ui.md:139` and `:154`, push types and the `emailPush` + filter: never read back, and breaks for ACL-shared accounts (B18). **Suspected.** Fixed in + `ccaa24e`, `d8046a8`. - [ ] `docs/parity/02-mail-list-folders.md:217`, date-locale: the tick claims a `dateLocale` setting - that doesn't exist. **Suspected.** + that doesn't exist. **Suspected.** Open: there is still no `dateLocale` setting. ### Unticked, but done or obsolete @@ -789,16 +849,16 @@ spot-check covered 35 ticks plus the ones re-tested on the device. | Item | Where it landed | |---|---| | `01:109` remove a non-active account | `6ae21d5`, `490355c` | - | `01:114` switcher error state | | - | `01:129` account cap | now 10, `src/lib/account-utils.ts:4` | - | `01:139` unified shared-account filter | | - | `02:163` permanent-delete confirm | `src/screens/EmailThreadScreen.tsx:361-386` | - | `02:168` "never" mark-as-read | | - | `04:256` mailto/share intents | Android; broken per B9–B11 | - | `06:200` add sender to contacts | | - | `06:281` auto-trust reply recipients | | - | `07:164` quota | shown in Account settings | - | `09:131` contact state changes for shared accounts | | + | `01:114` switcher error state | `6ae21d5` | + | `01:129` account cap | now 10, `src/lib/account-utils.ts:4` (`6ae21d5`) | + | `01:139` unified shared-account filter | `6ae21d5` | + | `02:163` permanent-delete confirm | `src/screens/EmailThreadScreen.tsx:361-386` (`d2ed27f`) | + | `02:168` "never" mark-as-read | `d2ed27f` | + | `04:256` mailto/share intents | Android; broken per B9–B11 (`5802cae`; fixed in `cd4ce9d`, `06e8942`, `ee652d3`) | + | `06:200` add sender to contacts | `d2ed27f` | + | `06:281` auto-trust reply recipients | `5b72c4d` | + | `07:164` quota | shown in Account settings (`490355c`) | + | `09:131` contact state changes for shared accounts | `26a34d5` | - **Obsolete (drop them):** - `05:91` natural-language event input: the webmail has no parser. - `06:294` print contact: not applicable on mobile. @@ -815,12 +875,12 @@ spot-check covered 35 ticks plus the ones re-tested on the device. | Issue | Status after this audit | |---|---| -| #57 scheduled sending unsupported | Root cause found and reproduced (B8). | -| #54 contact photos not used as avatars | Reproduced (Viewer, "sender avatars"). | +| #57 scheduled sending unsupported | Root cause found and reproduced (B8). Fixed in `e28e8b4`. | +| #54 contact photos not used as avatars | Reproduced (Viewer, "sender avatars"). Fixed in `eca3871`. | | #50 crash opening any mail | Not reproduced on 0.1.62; likely fixed by `f228257`. Ask the reporter, then close. | | #47 account security not accessible | Fixed: Security → Account Security works on 0.16.23. Close. | | #46 email preview shows CSS | Not reproduced: HTML-only mail with `