Mail UI: columns layout without selection, Mail missing from mode tray, folders stuck loading #1078

Closed
opened 2026-10-04 23:27:58 +00:00 by kayg · 10 comments
Owner

Found in the orchestrator's review of the Apple Mail acceptance screenshots (2026-10-05, branch job/applemail-accept 30ad9ce8c = production 7b + mail proxy)

  1. Columns layout without a selected message: with the columns layout active (the owner's default; first layout button highlighted), the message list renders centred in the full content width (roughly x 555–1180 at 1440 px) with no reader pane. Expected (owner: "Mail default layout needs to be column layout"): the list sits in the left column at its resizable width, and the right column shows the reader pane's empty state ("No message selected", quiet), exactly as when a message is open. Same at 820 px. Phone keeps its list → reader push.
  2. Mode tray hides Mail: while in Mail, the bottom mode tray shows Calendar, Tasks, Notes, Files, Photos and no Mail icon. The tray must include every enabled Tab and show the current one selected with its label (CLAUDE.md Chrome rules: icons only, label on the selected mode).
  3. "Loading Mail folders…" stuck: in final-trash-1440-dark.png the sidebar shows "Loading Mail folders…" under Categories while the folder list never appears (the light drafts screenshot of the same session shows the folders). Find the condition that leaves the loading state on.

Evidence: the screenshot zips attached to #1038 (drafts-, final-trash-). Check production behaviour (dev 9fb9a4bfb) for each.

## Found in the orchestrator's review of the Apple Mail acceptance screenshots (2026-10-05, branch job/applemail-accept 30ad9ce8c = production 7b + mail proxy) 1. **Columns layout without a selected message:** with the columns layout active (the owner's default; first layout button highlighted), the message list renders centred in the full content width (roughly x 555–1180 at 1440 px) with no reader pane. Expected (owner: "Mail default layout needs to be column layout"): the list sits in the left column at its resizable width, and the right column shows the reader pane's empty state ("No message selected", quiet), exactly as when a message is open. Same at 820 px. Phone keeps its list → reader push. 2. **Mode tray hides Mail:** while in Mail, the bottom mode tray shows Calendar, Tasks, Notes, Files, Photos and no Mail icon. The tray must include every enabled Tab and show the current one selected with its label (CLAUDE.md Chrome rules: icons only, label on the selected mode). 3. **"Loading Mail folders…" stuck:** in final-trash-1440-dark.png the sidebar shows "Loading Mail folders…" under Categories while the folder list never appears (the light drafts screenshot of the same session shows the folders). Find the condition that leaves the loading state on. Evidence: the screenshot zips attached to #1038 (drafts-*, final-trash-*). Check production behaviour (dev 9fb9a4bfb) for each.
Author
Owner

Starting work on branch job/mailui-1078 at base 9fb9a4bfb2 (the supplied dev / production 7b base). I am tracing and reproducing the three reported Mail UI findings against the production build and real Mail fixture before changing code.

Starting work on branch job/mailui-1078 at base 9fb9a4bfb2488152c83d50c55441ff5f43b572b2 (the supplied dev / production 7b base). I am tracing and reproducing the three reported Mail UI findings against the production build and real Mail fixture before changing code.
Author
Owner

Production reproduction (current build, local server, seeded from tests/adversarial/mail_screenshot_fixture.py): at 1440 px on /mail?layout=columns with no message selected, the page has no .mail-layout and no reader pane; the real Mail row list renders by itself. The App modes Tab Bar lists Calendar, Tasks, Notes, Files, Photos and Analytics; each has aria-selected=false, so Mail is missing and the current Tab is not selected. Holding the real fixture account's /api/v1/mail/accounts/{id}/sync response leaves the sidebar at ‘Loading Mail folders…’ with no folder links, even though account and folder reads have returned. This confirms that folder display incorrectly waits for sync-status reads.

Production reproduction (current build, local server, seeded from tests/adversarial/mail_screenshot_fixture.py): at 1440 px on /mail?layout=columns with no message selected, the page has no .mail-layout and no reader pane; the real Mail row list renders by itself. The App modes Tab Bar lists Calendar, Tasks, Notes, Files, Photos and Analytics; each has aria-selected=false, so Mail is missing and the current Tab is not selected. Holding the real fixture account's /api/v1/mail/accounts/{id}/sync response leaves the sidebar at ‘Loading Mail folders…’ with no folder links, even though account and folder reads have returned. This confirms that folder display incorrectly waits for sync-status reads.
Author
Owner

Decision for the 820 px acceptance: DESIGN §45 currently switches Columns and Split to Morph below 1200 px, but this issue explicitly asks for the two-column Mail layout at 820 px. I am following this newer acceptance and updating §45 so Columns/Split remain selected on tablets; Morph remains available as its explicit layout, and phones keep the full-screen push.

Decision for the 820 px acceptance: DESIGN §45 currently switches Columns and Split to Morph below 1200 px, but this issue explicitly asks for the two-column Mail layout at 820 px. I am following this newer acceptance and updating §45 so Columns/Split remain selected on tablets; Morph remains available as its explicit layout, and phones keep the full-screen push.
Author
Owner

Production Mail layout e2e exposed a first-visit resize bug. On a fresh User, readStoredWidth converted the absent storage value (null) to 0 and treated it as an intentionally collapsed list. The Columns separator reported aria-valuenow="0" and intercepted the first message row; Playwright timed out after 30 seconds trying to click the row. I am fixing absent-value handling while preserving an explicitly saved 0, with a focused regression test.

Production Mail layout e2e exposed a first-visit resize bug. On a fresh User, `readStoredWidth` converted the absent storage value (`null`) to `0` and treated it as an intentionally collapsed list. The Columns separator reported `aria-valuenow="0"` and intercepted the first message row; Playwright timed out after 30 seconds trying to click the row. I am fixing absent-value handling while preserving an explicitly saved `0`, with a focused regression test.
Author
Owner

Visual evidence — empty Columns. Captured from the production web build with the real Mail fixture and macOS platform emulation: 1440 px desktop and 820 px tablet, in Paper light and Tokyo Night dark. The Mail Tab is selected and labelled in each capture.

Visual evidence — empty Columns. Captured from the production web build with the real Mail fixture and macOS platform emulation: 1440 px desktop and 820 px tablet, in Paper light and Tokyo Night dark. The Mail Tab is selected and labelled in each capture.
Author
Owner

Visual evidence — open Columns. Captured from the production web build with the real Mail fixture and macOS platform emulation: 1440 px desktop and 820 px tablet, in Paper light and Tokyo Night dark. The Mail Tab is selected and labelled in each capture.

Visual evidence — open Columns. Captured from the production web build with the real Mail fixture and macOS platform emulation: 1440 px desktop and 820 px tablet, in Paper light and Tokyo Night dark. The Mail Tab is selected and labelled in each capture.
Author
Owner

Visual evidence — phone Mail list. Captured at 390 px from the production web build with the real Mail fixture and macOS platform emulation in Paper light and Tokyo Night dark. The Mail Tab is selected and labelled in each capture.

Visual evidence — phone Mail list. Captured at 390 px from the production web build with the real Mail fixture and macOS platform emulation in Paper light and Tokyo Night dark. The Mail Tab is selected and labelled in each capture.
Author
Owner

Result

Fixed all three #1078 findings with real Mail data. Empty Columns/Split views keep the message list on the left and a quiet “No message selected” reader on the right. Every enabled routed Tab stays in the Tab Bar; Mail is selected and labelled on Mail routes. Folder links appear as soon as account and folder reads finish; sync progress updates in the background, while folder read failures retain Retry.

A fresh User now gets the default Columns width. An explicitly saved 0 still means collapsed. This fixed the first-row click intercepted by the collapsed resize hit zone.

The Mail performance profile now checks the empty reader before opening a message and covers Columns at 1440 px and 820 px with its 10,000-message fixture. The profile config test passed. I did not run performance measurements: the 2026-10-02 verification policy reserves them for performance issues. docs/perf/baseline.json is unchanged.

Files

  • apps/web/src/lib/mail/MailView.svelte
  • apps/web/src/lib/mail/MailSidebar.svelte and apps/web/src/lib/mail/MailSidebar.svelte.test.ts
  • apps/web/src/lib/navigation.ts, apps/web/src/lib/navigation.test.ts, apps/web/src/lib/plugins/user-enable.ts, apps/web/src/lib/plugins/user-enable.test.ts
  • apps/web/src/lib/actions/edgeResize.ts and apps/web/src/lib/actions/edgeResize.test.ts
  • apps/web/e2e/mail-layouts.mjs
  • docs/DESIGN.md
  • bench/blaze.mjs, bench/blaze.md, bench/blaze.test.mjs
  • contracts/perf/registry.json and contracts/perf/exceptions.json

Screenshots

The production Mail e2e passed with the real Mail fixture and macOS platform emulation. It captured 24 screenshots in artifacts/mailui-1078/. The 10 requested review images are attached above in three groups: empty Columns, open Columns, and the 390 px phone list. The Tab Bar assertions verified that Mail is selected and labelled in the captures.

Gates

bun run check:

perf-lint: PASS; 0 violations; 19340 scoped exceptions
svelte-check found 0 errors and 4 warnings in 3 files

Focused Vitest:

Test Files  4 passed (4)
Tests  23 passed (23)
Start at  02:45:37
Duration  9.62s (transform 71%, environment 14%, tests 7%, import 6%, setup 2%)

Mail layout e2e:

Mail layouts e2e passed; screenshots are in /home/kayg/Developer/calternal-wt/mailui-1078/artifacts/mailui-1078

Mail performance profile config test:

3 pass
0 fail
Ran 3 tests across 1 file. [45.00ms]

Production build:

Wrote site to "build"
✔ done
Compressed 534 static variants; saved 9818495 bytes.

Cleanup:

Removed 8433 files, 6.9GiB total

The four svelte-check warnings are in untouched Calendar attachment/agenda CSS and Notes CSS. No Rust files changed, so Rust crate gates did not apply.

UX gaps closed

  • Empty Columns state is visible and announced before message selection; it has no inactive close button.
  • The Tab Bar contains every enabled routed mode, with Mail selected and labelled on Mail routes.
  • Slow or failed sync-status reads cannot keep real folders behind a loading state.
  • Missing saved widths use the default, and deliberate collapse remains available.
  • Production screenshots cover empty and open Columns at desktop/tablet widths and the phone list, in light and dark themes.

UX gaps left

None found in the requested Mail paths. Performance numbers were not collected under the verification policy above.

Decisions

  • Followed #1078’s 820 px side-by-side acceptance and updated DESIGN §45: Columns/Split stay side by side at desktop and tablet widths; Morph remains an explicit layout; phones use push. This supersedes the previous under-1200 Morph default. I recorded this choice on the issue before implementation.
  • The Plugin catalog is authoritative for enabled routed Tabs, so stale saved visibility data cannot hide one.

Commits

00eae4f58, 4cd368118, 962ed38a9, 95f759e80, 6b0df892b, d6982f4e9

Head: d6982f4e95db7b9474419cca81538a8cc5a7a750

READY FOR MERGE: yes

## Result Fixed all three #1078 findings with real Mail data. Empty Columns/Split views keep the message list on the left and a quiet “No message selected” reader on the right. Every enabled routed Tab stays in the Tab Bar; Mail is selected and labelled on Mail routes. Folder links appear as soon as account and folder reads finish; sync progress updates in the background, while folder read failures retain Retry. A fresh User now gets the default Columns width. An explicitly saved `0` still means collapsed. This fixed the first-row click intercepted by the collapsed resize hit zone. The Mail performance profile now checks the empty reader before opening a message and covers Columns at 1440 px and 820 px with its 10,000-message fixture. The profile config test passed. I did not run performance measurements: the 2026-10-02 verification policy reserves them for performance issues. `docs/perf/baseline.json` is unchanged. ## Files - `apps/web/src/lib/mail/MailView.svelte` - `apps/web/src/lib/mail/MailSidebar.svelte` and `apps/web/src/lib/mail/MailSidebar.svelte.test.ts` - `apps/web/src/lib/navigation.ts`, `apps/web/src/lib/navigation.test.ts`, `apps/web/src/lib/plugins/user-enable.ts`, `apps/web/src/lib/plugins/user-enable.test.ts` - `apps/web/src/lib/actions/edgeResize.ts` and `apps/web/src/lib/actions/edgeResize.test.ts` - `apps/web/e2e/mail-layouts.mjs` - `docs/DESIGN.md` - `bench/blaze.mjs`, `bench/blaze.md`, `bench/blaze.test.mjs` - `contracts/perf/registry.json` and `contracts/perf/exceptions.json` ## Screenshots The production Mail e2e passed with the real Mail fixture and macOS platform emulation. It captured 24 screenshots in `artifacts/mailui-1078/`. The 10 requested review images are attached above in three groups: empty Columns, open Columns, and the 390 px phone list. The Tab Bar assertions verified that Mail is selected and labelled in the captures. ## Gates `bun run check`: ```text perf-lint: PASS; 0 violations; 19340 scoped exceptions svelte-check found 0 errors and 4 warnings in 3 files ``` Focused Vitest: ```text Test Files 4 passed (4) Tests 23 passed (23) Start at 02:45:37 Duration 9.62s (transform 71%, environment 14%, tests 7%, import 6%, setup 2%) ``` Mail layout e2e: ```text Mail layouts e2e passed; screenshots are in /home/kayg/Developer/calternal-wt/mailui-1078/artifacts/mailui-1078 ``` Mail performance profile config test: ```text 3 pass 0 fail Ran 3 tests across 1 file. [45.00ms] ``` Production build: ```text Wrote site to "build" ✔ done Compressed 534 static variants; saved 9818495 bytes. ``` Cleanup: ```text Removed 8433 files, 6.9GiB total ``` The four `svelte-check` warnings are in untouched Calendar attachment/agenda CSS and Notes CSS. No Rust files changed, so Rust crate gates did not apply. ## UX gaps closed - Empty Columns state is visible and announced before message selection; it has no inactive close button. - The Tab Bar contains every enabled routed mode, with Mail selected and labelled on Mail routes. - Slow or failed sync-status reads cannot keep real folders behind a loading state. - Missing saved widths use the default, and deliberate collapse remains available. - Production screenshots cover empty and open Columns at desktop/tablet widths and the phone list, in light and dark themes. ## UX gaps left None found in the requested Mail paths. Performance numbers were not collected under the verification policy above. ## Decisions - Followed #1078’s 820 px side-by-side acceptance and updated DESIGN §45: Columns/Split stay side by side at desktop and tablet widths; Morph remains an explicit layout; phones use push. This supersedes the previous under-1200 Morph default. I recorded this choice on the issue before implementation. - The Plugin catalog is authoritative for enabled routed Tabs, so stale saved visibility data cannot hide one. ## Commits `00eae4f58`, `4cd368118`, `962ed38a9`, `95f759e80`, `6b0df892b`, `d6982f4e9` Head: `d6982f4e95db7b9474419cca81538a8cc5a7a750` **READY FOR MERGE: yes**
Author
Owner

Orchestrator review (screenshots columns-empty-desktop-paper-light, columns-desktop-columns-tokyo-night-dark): columns layout shows the list in the left column with "No message selected" on the right; the open message is in the right pane; Mail is selected and labelled in the tray. Approved. Behaviour change recorded: the tray shows every enabled routed Tab; hiding a Tab means turning its plugin off in Settings → Plugins. Ships in round 9 with the mail proxy.

Orchestrator review (screenshots columns-empty-desktop-paper-light, columns-desktop-columns-tokyo-night-dark): columns layout shows the list in the left column with "No message selected" on the right; the open message is in the right pane; Mail is selected and labelled in the tray. Approved. Behaviour change recorded: the tray shows every enabled routed Tab; hiding a Tab means turning its plugin off in Settings → Plugins. Ships in round 9 with the mail proxy.
Author
Owner

Deployed to production 2026-10-05 ~04:40 CEST in round 9 (269b1b51b). Includes the mail proxy (CalternalDAV, real Apple Mail acceptance PASS on the Mac VM), provider sync fixes, the stress-round fixes, #1067, #1068, #1078 and the Files upload identity repair. Staging healthy first; production healthy in 18 s; Auth 14 and Mail 17 migrations applied; change events 0/30 s; no expired leases.

Deployed to production 2026-10-05 ~04:40 CEST in round 9 (269b1b51b). Includes the mail proxy (CalternalDAV, real Apple Mail acceptance PASS on the Mac VM), provider sync fixes, the stress-round fixes, #1067, #1068, #1078 and the Files upload identity repair. Staging healthy first; production healthy in 18 s; Auth 14 and Mail 17 migrations applied; change events 0/30 s; no expired leases.
kayg closed this issue 2026-10-05 03:08:52 +00:00
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
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#1078
No description provided.