Bug bash: mail #1218

Open
opened 2026-10-06 19:01:34 +00:00 by kayg · 8 comments
Owner

AREA: Mail Tab. Account connect (only the local test IMAP/SMTP setup the repo has, never real accounts), mailbox list, thread view, read/unread/flag/archive/delete/move, compose/reply/forward with attachments, draft autosave, mail search, 10k-message mailbox scroll, HTML mail rendering safety (remote content blocked by default), offline, Copy link for threads.

Tracking issue for the 2026-10-07 bug bash. Every bug found gets its own issue, linked here.

AREA: Mail Tab. Account connect (only the local test IMAP/SMTP setup the repo has, never real accounts), mailbox list, thread view, read/unread/flag/archive/delete/move, compose/reply/forward with attachments, draft autosave, mail search, 10k-message mailbox scroll, HTML mail rendering safety (remote content blocked by default), offline, Copy link for threads. Tracking issue for the 2026-10-07 bug bash. Every bug found gets its own issue, linked here.
Author
Owner

Started Mail Tab bug bash on branch job/bash-mail, based at ff53d7b8b4da5a21f862d57dcc3496f8c019f647 (origin/dev at start). I am mapping the existing local IMAP/SMTP fixture and Mail UI/API flows before running the production-build interaction matrix.

Started Mail Tab bug bash on branch `job/bash-mail`, based at `ff53d7b8b4da5a21f862d57dcc3496f8c019f647` (origin/dev at start). I am mapping the existing local IMAP/SMTP fixture and Mail UI/API flows before running the production-build interaction matrix.
Author
Owner

Finding #1241 (major): Mail exposes only Open, Copy link, and message read-state actions. Archive, Move, Trash/Delete, and Flag are absent from the list and reader UI, although DESIGN §45 requires them. Evidence: apps/web/src/lib/mail/MailView.svelte, threadMenu() / messageMenu(). I will verify the menu contents against the production UI in the local-provider browser run. This is filed only because the bash rules prohibit new feature work.

Finding #1241 (major): Mail exposes only Open, Copy link, and message read-state actions. Archive, Move, Trash/Delete, and Flag are absent from the list and reader UI, although DESIGN §45 requires them. Evidence: `apps/web/src/lib/mail/MailView.svelte`, `threadMenu()` / `messageMenu()`. I will verify the menu contents against the production UI in the local-provider browser run. This is filed only because the bash rules prohibit new feature work.
Author
Owner

Finding #1244 (major): Read/unread writes require a live IMAP connection for normal indexed messages; a stopped provider causes change_read_state to fail before any durable queue or Index update. The Mail UI also waits for that response before changing the row. Evidence: crates/plugins/mail/src/routes.rs (change_read_state) and apps/web/src/lib/mail/MailView.svelte (markRead). I am testing this against the local TLS provider and checking the existing queue path for a bounded fix.

Finding #1244 (major): Read/unread writes require a live IMAP connection for normal indexed messages; a stopped provider causes `change_read_state` to fail before any durable queue or Index update. The Mail UI also waits for that response before changing the row. Evidence: `crates/plugins/mail/src/routes.rs` (`change_read_state`) and `apps/web/src/lib/mail/MailView.svelte` (`markRead`). I am testing this against the local TLS provider and checking the existing queue path for a bounded fix.
Author
Owner

Found and filed #1269: Mail Morph remains visible after Escape following ArrowUp/ArrowDown selection. The production-build mail-layouts.mjs flow times out waiting for .mail-morph-card to detach at line 210; the preceding selection assertions pass. Severity: major (keyboard users cannot close the modal reader). I am checking whether the fix is contained in Mail-owned code.

Found and filed #1269: Mail Morph remains visible after Escape following ArrowUp/ArrowDown selection. The production-build `mail-layouts.mjs` flow times out waiting for `.mail-morph-card` to detach at line 210; the preceding selection assertions pass. Severity: major (keyboard users cannot close the modal reader). I am checking whether the fix is contained in Mail-owned code.
Author
Owner

Found a Mail layout fixture failure after the viewport and theme captures: the run reaches apps/web/e2e/mail-layouts.mjs:311, then mail_screenshot_fixture.py exits with unknown fixture action: prepared-images. Filed as #1277 (minor). The completed captures are in apps/web/artifacts/bash-mail/mail-layouts/. I will fix this harness defect so the remaining image safety checks can run.

Found a Mail layout fixture failure after the viewport and theme captures: the run reaches `apps/web/e2e/mail-layouts.mjs:311`, then `mail_screenshot_fixture.py` exits with `unknown fixture action: prepared-images`. Filed as #1277 (minor). The completed captures are in `apps/web/artifacts/bash-mail/mail-layouts/`. I will fix this harness defect so the remaining image safety checks can run.
Author
Owner

Post-merge cargo test -p calternal-server found a read-state regression in the shared-account migration checks. The queue path returns 204 for a message whose shared credential is valid but whose IMAP host is empty; the tests expect local endpoint validation to return 400 without provider I/O. Filed as #1294 (minor). I am fixing this by resolving the shared credential and validating host syntax locally before journaling.

Post-merge `cargo test -p calternal-server` found a read-state regression in the shared-account migration checks. The queue path returns 204 for a message whose shared credential is valid but whose IMAP host is empty; the tests expect local endpoint validation to return 400 without provider I/O. Filed as #1294 (minor). I am fixing this by resolving the shared credential and validating host syntax locally before journaling.
Author
Owner

Filed shared-component web check failure as #1308. After the Mail perf pin was refreshed, bun run check reported 0 errors and 1 warning but exited 1 on the empty .attachment-row:focus ruleset in packages/ui/src/components/calendar/AttachmentDeck.svelte:1055. This is outside Mail ownership, so it is filed only.

Filed shared-component web check failure as #1308. After the Mail perf pin was refreshed, `bun run check` reported 0 errors and 1 warning but exited 1 on the empty `.attachment-row:focus` ruleset in `packages/ui/src/components/calendar/AttachmentDeck.svelte:1055`. This is outside Mail ownership, so it is filed only.
Author
Owner

Final report — bash-mail (#1218)

Branch: job/bash-mail
Base: origin/dev merged at 98052e392
Head: 8b5535000d37e9becc0e4a0994532c0787466f35
Worktree: clean. No push, deploy, or merge was performed.

What changed

  • Read-state edits now validate the linked Connected Account credential and local IMAP host/port, update the Mail Index, and enqueue provider delivery through the existing durable proxy journal. The request no longer waits for IMAP. Proxy UID mapping covers only the target Message's live memberships and pending transfers, with at most four mutations in flight.
  • Morph now handles Escape when focus has left its card, while nested modal/menu overlays retain Escape.
  • The Mail production e2e fixture accepts the prepared-images setup action. The sync flow can seed up to 100,000 messages, records first content and sync timing, exercises thread Copy link and offline read state, and includes wheel scrolling to the oldest Thread.
  • Added local Mail proxy profiles for read-state writes at 10,000 and 100,000 messages, including three callers sharing one Index. Refreshed the exact mutation performance pin and OpenAPI/API client contract.

Issues found

Issue Symptom Severity Result
#1241 Standard thread actions are missing from the list and reader menus Major Filed only; remains open
#1244 Read-state changes fail offline instead of entering the durable queue Major Fixed in c7ba68b09
#1269 Escape does not close Morph after focus leaves the card Major Fixed in 389d3d2c3
#1277 Screenshot fixture rejects the prepared-images action Minor Fixed in 45b26bf15; setup now succeeds, but the later reader screenshot flow still failed before capture
#1294 Queued read-state skips shared account validation Minor Fixed in ade3457c5
#1308 Web check fails on the shared AttachmentDeck empty ruleset Major Filed only; outside Mail ownership

Files

  • apps/web/e2e/mail-layouts.mjs, apps/web/e2e/mail-sync-613.mjs, apps/web/src/lib/mail/MailMorphCard.svelte
  • bench/mail-sync.py, contracts/openapi.json, contracts/perf/exceptions.json, packages/api-client/src/generated.ts
  • crates/plugins/mail/src/cache.rs, crates/plugins/mail/src/cache/store.rs, crates/plugins/mail/src/imap.rs, crates/plugins/mail/src/proxy.rs, crates/plugins/mail/src/proxy_tests.rs, crates/plugins/mail/src/proxy_transfers.rs, crates/plugins/mail/src/routes.rs
  • tests/adversarial/mail_screenshot_fixture.py

UX gaps closed

  • An accepted read/unread change remains visible in the local Mail Index while the test IMAP provider is offline; the durable job can deliver it after the provider returns.
  • Read-state no longer snapshots the full mailbox per click. Work is bounded to the account's folder-name lookup plus this Message's active memberships and pending transfers; no other cached Messages receive proxy UIDs. Mutation delivery has a concurrency limit of four.
  • Morph Escape works after focus loss and does not steal Escape from a nested overlay.
  • The 10,000-message scroll and stable thread Copy link / offline read-state checks are now in the real production e2e flow.

UX gaps left

  • #1241 remains open. The 10,000-message Dovecot backfill did not finish, so the oldest-Thread scroll assertion and the later Copy link/offline UI steps were not reached in that run. One later Mail layout rerun stopped with “This message could not be opened” before screenshots. The full connect, compose/reply/forward, draft, search, action, and accessibility/network matrix was not completed.
  • The saved Mac-emulated layout evidence contains 24 screenshots under artifacts/bash-mail/mail-layouts/ (390/820/1440 px, light/dark). It is not a complete post-change visual set for the failed prepared-image reader flow.
  • bun run check remains red on #1308. The warning is in the shared Calendar AttachmentDeck.svelte; I did not edit that shared component.

Performance

Measured locally on the shared build host; no matching Mail proxy baseline exists in docs/perf/baseline.json. The host was busy (load average before [20.82177734375, 19.9755859375, 22.87548828125], after [16.8505859375, 18.15673828125, 20.390625]).

  • 10,000-message read-state: median cold p50 15.52 ms; median warm p50 26.95 ms, median warm p95 60.64 ms. Three-caller same-Index bursts had median per-client p50 about 15–28 ms and worst reported per-client p95 82.72 ms.
  • 100,000-message read-state: cold p50 50.73 ms; warm p50 80.51 ms, p95 120.79 ms. Three-caller same-Index burst median p50 158.98 ms, median p95 269.61 ms.
  • The 100,000-message profile process averaged about 920 MiB RSS, peaked near 1.24 GiB, and used about 127% CPU. These are local, high-load measurements, not perf-VM results. The JSON remains in ignored target/tmp/mail-proxy-profile-local.json.
  • The 10,000-message UI sync showed first content at 16.517 s; one run reached 8,880/10,000 at 180 s, and a scaled run reached 8,440/10,000 at 350 s before timing out. This is incomplete worst-case UI evidence, not a passing scroll measurement.

Gates

cargo fmt --all --check — exit 0, no output.

cargo clippy -p calternal-plugin-mail --all-targets -- -D warnings output:

    Checking calternal-plugin-mail v0.0.1 (/home/kayg/Developer/calternal-wt/bash-mail/crates/plugins/mail)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 23.66s

cargo test -p calternal-plugin-mail output:

test result: ok. 129 passed; 0 failed; 6 ignored; 0 measured; 0 filtered out; finished in 39.26s

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

cargo clippy -p calternal-server --all-targets -- -D warnings — exit 0, no lint diagnostics. Focused server tests migrated_mail_read_state_reaches_endpoint_validation and later_mail_merges_with_existing_shared_calendar passed. Full cargo test -p calternal-server had one SLOW Search startup failure on the shared host; 271 passed and 12 were ignored. Failure output:

search_reconcile_calendar_write_profile files=20000 writes=32 p50_ms=4512 p95_ms=4963 p95_budget_ms=10000
startup Search reconciliation did not finish
test wire::tests::live_apps_run_in_separate_processes ... FAILED

cd apps/web && bun run check — exit 1. The perf check passed with PASS; 0 violations; 22548 scoped exceptions; Svelte reported:

Warn: Do not use empty rulesets (css)
    }
    .attachment-row:focus {

====================================
svelte-check found 0 errors and 1 warning in 1 file

cd apps/web && bun run test:

 Test Files  287 passed (287)
      Tests  2035 passed (2035)
   Start at  05:04:50
   Duration  318.72s (transform 31%, import 28%, environment 22%, tests 15%, setup 4%)

cargo clean output: Removed 18883 files, 14.5GiB total. Web build output was deleted. Screenshots remain untracked/ignored and were not committed.

Decisions

No OPEN DESIGN decision was used. The implementation extends the existing Mail proxy journal (DESIGN §§45, 49 I6, 53), validates the linked Connected Account locally, and lets the existing provider worker perform delivery. This keeps the request offline-safe without adding a new user-facing control. No shared visual primitive was created or restyled; existing Mail menus and MailMorphCard remain in use.

For the merge round

  • cd apps/web && bun run build && CALTERNAL_MAIL_SYNC_MESSAGES=10000 bun run test:e2e:mail-sync-613 — prove 10,000-message sync completes and reaches the oldest Thread, then exercise Copy link and offline read-state.
  • cd apps/web && bun run test:e2e:mail-layouts — capture the macOS-emulated 390/820/1440 light/dark Mail layouts and complete the prepared-image reader flow.
  • bash tests/adversarial/run.sh — run the deferred cross-User, authorization, and robustness matrices against the merged build.
## Final report — bash-mail (#1218) **Branch:** `job/bash-mail` **Base:** `origin/dev` merged at `98052e392` **Head:** `8b5535000d37e9becc0e4a0994532c0787466f35` **Worktree:** clean. No push, deploy, or merge was performed. ### What changed - Read-state edits now validate the linked Connected Account credential and local IMAP host/port, update the Mail Index, and enqueue provider delivery through the existing durable proxy journal. The request no longer waits for IMAP. Proxy UID mapping covers only the target Message's live memberships and pending transfers, with at most four mutations in flight. - Morph now handles Escape when focus has left its card, while nested modal/menu overlays retain Escape. - The Mail production e2e fixture accepts the prepared-images setup action. The sync flow can seed up to 100,000 messages, records first content and sync timing, exercises thread Copy link and offline read state, and includes wheel scrolling to the oldest Thread. - Added local Mail proxy profiles for read-state writes at 10,000 and 100,000 messages, including three callers sharing one Index. Refreshed the exact mutation performance pin and OpenAPI/API client contract. ### Issues found | Issue | Symptom | Severity | Result | |---|---|---:|---| | #1241 | Standard thread actions are missing from the list and reader menus | Major | Filed only; remains open | | #1244 | Read-state changes fail offline instead of entering the durable queue | Major | Fixed in `c7ba68b09` | | #1269 | Escape does not close Morph after focus leaves the card | Major | Fixed in `389d3d2c3` | | #1277 | Screenshot fixture rejects the prepared-images action | Minor | Fixed in `45b26bf15`; setup now succeeds, but the later reader screenshot flow still failed before capture | | #1294 | Queued read-state skips shared account validation | Minor | Fixed in `ade3457c5` | | #1308 | Web check fails on the shared AttachmentDeck empty ruleset | Major | Filed only; outside Mail ownership | ### Files - `apps/web/e2e/mail-layouts.mjs`, `apps/web/e2e/mail-sync-613.mjs`, `apps/web/src/lib/mail/MailMorphCard.svelte` - `bench/mail-sync.py`, `contracts/openapi.json`, `contracts/perf/exceptions.json`, `packages/api-client/src/generated.ts` - `crates/plugins/mail/src/cache.rs`, `crates/plugins/mail/src/cache/store.rs`, `crates/plugins/mail/src/imap.rs`, `crates/plugins/mail/src/proxy.rs`, `crates/plugins/mail/src/proxy_tests.rs`, `crates/plugins/mail/src/proxy_transfers.rs`, `crates/plugins/mail/src/routes.rs` - `tests/adversarial/mail_screenshot_fixture.py` ### UX gaps closed - An accepted read/unread change remains visible in the local Mail Index while the test IMAP provider is offline; the durable job can deliver it after the provider returns. - Read-state no longer snapshots the full mailbox per click. Work is bounded to the account's folder-name lookup plus this Message's active memberships and pending transfers; no other cached Messages receive proxy UIDs. Mutation delivery has a concurrency limit of four. - Morph Escape works after focus loss and does not steal Escape from a nested overlay. - The 10,000-message scroll and stable thread Copy link / offline read-state checks are now in the real production e2e flow. ### UX gaps left - #1241 remains open. The 10,000-message Dovecot backfill did not finish, so the oldest-Thread scroll assertion and the later Copy link/offline UI steps were not reached in that run. One later Mail layout rerun stopped with “This message could not be opened” before screenshots. The full connect, compose/reply/forward, draft, search, action, and accessibility/network matrix was not completed. - The saved Mac-emulated layout evidence contains 24 screenshots under `artifacts/bash-mail/mail-layouts/` (390/820/1440 px, light/dark). It is not a complete post-change visual set for the failed prepared-image reader flow. - `bun run check` remains red on #1308. The warning is in the shared Calendar `AttachmentDeck.svelte`; I did not edit that shared component. ### Performance Measured locally on the shared build host; no matching Mail proxy baseline exists in `docs/perf/baseline.json`. The host was busy (load average before `[20.82177734375, 19.9755859375, 22.87548828125]`, after `[16.8505859375, 18.15673828125, 20.390625]`). - 10,000-message read-state: median cold p50 **15.52 ms**; median warm p50 **26.95 ms**, median warm p95 **60.64 ms**. Three-caller same-Index bursts had median per-client p50 about **15–28 ms** and worst reported per-client p95 **82.72 ms**. - 100,000-message read-state: cold p50 **50.73 ms**; warm p50 **80.51 ms**, p95 **120.79 ms**. Three-caller same-Index burst median p50 **158.98 ms**, median p95 **269.61 ms**. - The 100,000-message profile process averaged about **920 MiB RSS**, peaked near **1.24 GiB**, and used about **127% CPU**. These are local, high-load measurements, not perf-VM results. The JSON remains in ignored `target/tmp/mail-proxy-profile-local.json`. - The 10,000-message UI sync showed first content at **16.517 s**; one run reached **8,880/10,000** at 180 s, and a scaled run reached **8,440/10,000** at 350 s before timing out. This is incomplete worst-case UI evidence, not a passing scroll measurement. ### Gates `cargo fmt --all --check` — exit 0, no output. `cargo clippy -p calternal-plugin-mail --all-targets -- -D warnings` output: ```text Checking calternal-plugin-mail v0.0.1 (/home/kayg/Developer/calternal-wt/bash-mail/crates/plugins/mail) Finished `dev` profile [unoptimized + debuginfo] target(s) in 23.66s ``` `cargo test -p calternal-plugin-mail` output: ```text test result: ok. 129 passed; 0 failed; 6 ignored; 0 measured; 0 filtered out; finished in 39.26s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` `cargo clippy -p calternal-server --all-targets -- -D warnings` — exit 0, no lint diagnostics. Focused server tests `migrated_mail_read_state_reaches_endpoint_validation` and `later_mail_merges_with_existing_shared_calendar` passed. Full `cargo test -p calternal-server` had one SLOW Search startup failure on the shared host; 271 passed and 12 were ignored. Failure output: ```text search_reconcile_calendar_write_profile files=20000 writes=32 p50_ms=4512 p95_ms=4963 p95_budget_ms=10000 startup Search reconciliation did not finish test wire::tests::live_apps_run_in_separate_processes ... FAILED ``` `cd apps/web && bun run check` — exit 1. The perf check passed with `PASS; 0 violations; 22548 scoped exceptions`; Svelte reported: ```text Warn: Do not use empty rulesets (css) } .attachment-row:focus { ==================================== svelte-check found 0 errors and 1 warning in 1 file ``` `cd apps/web && bun run test`: ```text Test Files 287 passed (287) Tests 2035 passed (2035) Start at 05:04:50 Duration 318.72s (transform 31%, import 28%, environment 22%, tests 15%, setup 4%) ``` `cargo clean` output: `Removed 18883 files, 14.5GiB total`. Web build output was deleted. Screenshots remain untracked/ignored and were not committed. ### Decisions No OPEN DESIGN decision was used. The implementation extends the existing Mail proxy journal (DESIGN §§45, 49 I6, 53), validates the linked Connected Account locally, and lets the existing provider worker perform delivery. This keeps the request offline-safe without adding a new user-facing control. No shared visual primitive was created or restyled; existing Mail menus and `MailMorphCard` remain in use. ### For the merge round - `cd apps/web && bun run build && CALTERNAL_MAIL_SYNC_MESSAGES=10000 bun run test:e2e:mail-sync-613` — prove 10,000-message sync completes and reaches the oldest Thread, then exercise Copy link and offline read-state. - `cd apps/web && bun run test:e2e:mail-layouts` — capture the macOS-emulated 390/820/1440 light/dark Mail layouts and complete the prepared-image reader flow. - `bash tests/adversarial/run.sh` — run the deferred cross-User, authorization, and robustness matrices against the merged build.
Commenting is not possible because the repository is archived.
No labels
No milestone
No project
No assignees
1 participant
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
kayg/calternal-v0#1218
No description provided.