Mail: closing the sidebar leaves its skeleton rows and dividers on top of the list #1094

Closed
opened 2026-10-05 04:57:38 +00:00 by kayg · 22 comments
Owner

Owner report (2026-10-05, production 269b1b51b, narrow window, dark)

"When the sidebar is closed on the Mail Tab, it leaves its dividers and rows like an OLED burn-in."

With the sidebar collapsed, faint grey bars stay in the top-left of the message list. They are the sidebar's loading-placeholder rows and dividers (skeleton bars at the sidebar's position, overlapping the first list rows), plus a stray vertical line through the list near the date column. Collapsing the sidebar must remove all of its content: no skeletons, dividers or lines remain. Check that the folder-loading skeleton never renders outside the sidebar, and that the vertical line is not a leftover column separator from the columns layout at this width.

Related: #1078 (folder loading Retry, columns layout) shipped in round 9.

## Owner report (2026-10-05, production 269b1b51b, narrow window, dark) "When the sidebar is closed on the Mail Tab, it leaves its dividers and rows like an OLED burn-in." With the sidebar collapsed, faint grey bars stay in the top-left of the message list. They are the sidebar's loading-placeholder rows and dividers (skeleton bars at the sidebar's position, overlapping the first list rows), plus a stray vertical line through the list near the date column. Collapsing the sidebar must remove all of its content: no skeletons, dividers or lines remain. Check that the folder-loading skeleton never renders outside the sidebar, and that the vertical line is not a leftover column separator from the columns layout at this width. Related: #1078 (folder loading Retry, columns layout) shipped in round 9.
Author
Owner

Owner update: "actually happens everywhere on all tabs". So this is the shared sidebar component (collapse leaves its skeleton/dividers/rows painted), not Mail only. Fix it once in the shared sidebar/collapse primitive and verify on every Tab (Calendar, Tasks, Notes, Files, Photos, Mail, Money, Analytics, Settings).

Owner update: "actually happens everywhere on all tabs". So this is the shared sidebar component (collapse leaves its skeleton/dividers/rows painted), not Mail only. Fix it once in the shared sidebar/collapse primitive and verify on every Tab (Calendar, Tasks, Notes, Files, Photos, Mail, Money, Analytics, Settings).
Author
Owner

Started investigation on branch job/mailghost-1094, based on origin/dev at 269b1b51b5774d79de08bfb31d058b3d248a7e7b. I am tracing the shared sidebar collapse path and will add a regression check for hidden and unfocusable content.

Started investigation on branch `job/mailghost-1094`, based on `origin/dev` at `269b1b51b5774d79de08bfb31d058b3d248a7e7b`. I am tracing the shared sidebar collapse path and will add a regression check for hidden and unfocusable content.
Author
Owner

Finding: apps/web/src/routes/layout.css moved the shared sidebar off-canvas and set opacity to 0, while .sidebar-shell retained its glass-overlay backdrop-filter plane. The aside was already inert and aria-hidden, but it had no post-transition visibility state; its separate immediate display: none rule also bypassed the intended exit. I added delayed visibility: hidden at the end of the existing transform motion and kept the reduced-motion path immediate. The source fix is now covered by a production-build sweep across all Tabs, both themes and both widths.

Finding: `apps/web/src/routes/layout.css` moved the shared sidebar off-canvas and set opacity to 0, while `.sidebar-shell` retained its `glass-overlay` backdrop-filter plane. The aside was already inert and aria-hidden, but it had no post-transition visibility state; its separate immediate `display: none` rule also bypassed the intended exit. I added delayed `visibility: hidden` at the end of the existing transform motion and kept the reduced-motion path immediate. The source fix is now covered by a production-build sweep across all Tabs, both themes and both widths.
Author
Owner

Fixed the shared sidebar collapse for #1094.

Cause and fix

The desktop sidebar stayed mounted after collapse. Its off-canvas transform and zero opacity left the backdrop-filter glass plane painting over the page. The sidebar also had an immediate display: none rule that skipped the exit motion. The layout now hides it with visibility after the existing --dur-open motion. The existing inert and aria-hidden state still applies at the start of collapse. Reduced motion hides it immediately.

Files

  • apps/web/src/routes/layout.css
  • apps/web/src/lib/components/app-sidebar.svelte
  • apps/web/e2e/sidebar-collapse-1094.mjs
  • apps/web/package.json

UX gaps closed

  • The collapsed sidebar no longer paints. Its descendants are hidden from assistive technology, inert, and cannot receive focus.
  • The e2e check covers the exit motion and reduced motion.
  • The production-browser sweep covers Calendar, Tasks, Notes, Files, Photos, Mail, Money, Analytics, and Settings at 390, 600, 820, and 1440 px, in light and dark, during loading and after the real API responds. All 144 screenshots are attached: sidebar-collapse-1094-screenshots.zip.

UX gaps left

  • None found for this issue. The empty test User has no Daily note for 2026-10-05, so the Notes route returns its normal 404 empty state.

Decision not specified in DESIGN

Use the existing --dur-open interval to delay visibility:hidden. This lets the current exit motion finish while removing the glass plane as soon as it ends. Reduced motion removes the delay.

Gates

bun run check — exit 2. It stops in the existing perf-lint check before svelte-check:

$ ../../scripts/perf-lint --check && node scripts/check-user-storage.mjs && node scripts/check-glass-tokens.mjs && node scripts/check-type-tokens.mjs && node scripts/check-focus-tokens.mjs && node scripts/check-motion-tokens.mjs && svelte-kit sync && svelte-check --tsconfig ./tsconfig.json
perf-lint: parse Rust product sources
perf-lint: parse browser product sources
perf-lint: validate coverage and architecture
perf-lint: INVALID: ('render.bound', 'apps/web/src/lib/components/app-sidebar.svelte', 'apps/web/src/lib/components/app-sidebar.svelte#each:10a1aaf3137a2426:1'): unused or changed exception

Focused Vitest — exit 0:

 RUN  v5.0.1 /home/kayg/Developer/calternal-wt/mailghost-1094/apps/web

Not implemented: navigation to another Document

 Test Files  1 passed (1)
      Tests  17 passed (17)
   Start at  08:24:14
   Duration  16.99s (transform 59%, environment 17%, tests 13%, setup 5%, import 4%)

  Transform  |component| transforming modules took 9.82s · 59% of tracked time, re-done on every run
             persist transforms across runs with fsModuleCache: true
             learn more: https://vitest.dev/guide/improving-performance#caching-between-reruns

bun run test:e2e:sidebar-collapse-1094 — exit 0:

$ bun e2e/sidebar-collapse-1094.mjs
Observed 404 response paths: /api/v1/notes/journal/2026-10-05

The merged-tree calternal-server build succeeded. No Rust source files changed in this job, so Rust clippy and test gates were not run.

Known gap

bun run check remains blocked by the stale render.bound exception above. The same perf-lint failure was present before merging origin/dev; this change does not edit that loop or its exception.

Head: 6dfc2f2618ad1717e95a7b0ca4871a2c210e6742

READY FOR MERGE: no — the required bun run check gate still fails on that exception.

Fixed the shared sidebar collapse for #1094. **Cause and fix** The desktop sidebar stayed mounted after collapse. Its off-canvas transform and zero opacity left the `backdrop-filter` glass plane painting over the page. The sidebar also had an immediate `display: none` rule that skipped the exit motion. The layout now hides it with `visibility` after the existing `--dur-open` motion. The existing `inert` and `aria-hidden` state still applies at the start of collapse. Reduced motion hides it immediately. **Files** - `apps/web/src/routes/layout.css` - `apps/web/src/lib/components/app-sidebar.svelte` - `apps/web/e2e/sidebar-collapse-1094.mjs` - `apps/web/package.json` **UX gaps closed** - The collapsed sidebar no longer paints. Its descendants are hidden from assistive technology, inert, and cannot receive focus. - The e2e check covers the exit motion and reduced motion. - The production-browser sweep covers Calendar, Tasks, Notes, Files, Photos, Mail, Money, Analytics, and Settings at 390, 600, 820, and 1440 px, in light and dark, during loading and after the real API responds. All 144 screenshots are attached: [sidebar-collapse-1094-screenshots.zip](https://git.kayg.org/attachments/b4504e85-31ed-4541-ace1-4dd60c7cc540). **UX gaps left** - None found for this issue. The empty test User has no Daily note for 2026-10-05, so the Notes route returns its normal 404 empty state. **Decision not specified in DESIGN** Use the existing `--dur-open` interval to delay `visibility:hidden`. This lets the current exit motion finish while removing the glass plane as soon as it ends. Reduced motion removes the delay. **Gates** `bun run check` — exit 2. It stops in the existing perf-lint check before `svelte-check`: ```text $ ../../scripts/perf-lint --check && node scripts/check-user-storage.mjs && node scripts/check-glass-tokens.mjs && node scripts/check-type-tokens.mjs && node scripts/check-focus-tokens.mjs && node scripts/check-motion-tokens.mjs && svelte-kit sync && svelte-check --tsconfig ./tsconfig.json perf-lint: parse Rust product sources perf-lint: parse browser product sources perf-lint: validate coverage and architecture perf-lint: INVALID: ('render.bound', 'apps/web/src/lib/components/app-sidebar.svelte', 'apps/web/src/lib/components/app-sidebar.svelte#each:10a1aaf3137a2426:1'): unused or changed exception ``` Focused Vitest — exit 0: ```text RUN v5.0.1 /home/kayg/Developer/calternal-wt/mailghost-1094/apps/web Not implemented: navigation to another Document Test Files 1 passed (1) Tests 17 passed (17) Start at 08:24:14 Duration 16.99s (transform 59%, environment 17%, tests 13%, setup 5%, import 4%) Transform |component| transforming modules took 9.82s · 59% of tracked time, re-done on every run persist transforms across runs with fsModuleCache: true learn more: https://vitest.dev/guide/improving-performance#caching-between-reruns ``` `bun run test:e2e:sidebar-collapse-1094` — exit 0: ```text $ bun e2e/sidebar-collapse-1094.mjs Observed 404 response paths: /api/v1/notes/journal/2026-10-05 ``` The merged-tree `calternal-server` build succeeded. No Rust source files changed in this job, so Rust clippy and test gates were not run. **Known gap** `bun run check` remains blocked by the stale `render.bound` exception above. The same perf-lint failure was present before merging `origin/dev`; this change does not edit that loop or its exception. Head: `6dfc2f2618ad1717e95a7b0ca4871a2c210e6742` **READY FOR MERGE: no** — the required `bun run check` gate still fails on that exception.
Author
Owner

Shipped to production 2026-10-05 08:24 CEST as hotfix 27644444a (cherry-pick of 411497071). The job verified all nine Tabs at 390/600/820/1440, light and dark, during and after loading: nothing from the collapsed sidebar renders or takes focus. Follow-up: the perf-lint exception for app-sidebar.svelte#each needs its fingerprint refreshed on dev (next landing).

Shipped to production 2026-10-05 08:24 CEST as hotfix 27644444a (cherry-pick of 411497071). The job verified all nine Tabs at 390/600/820/1440, light and dark, during and after loading: nothing from the collapsed sidebar renders or takes focus. Follow-up: the perf-lint exception for app-sidebar.svelte#each needs its fingerprint refreshed on dev (next landing).
kayg closed this issue 2026-10-05 06:39:13 +00:00
Author
Owner

Owner, after the 27644444a hotfix: "sidebar burn in is still there?" New screenshot (Calendar Day view, narrow window ~540 px, dark): five grey rounded bars at the top left (x 68–350, y 210–470) and a translucent vertical plane (x 120–250) over the hour grid, after closing the sidebar. The visibility fix on .desktop-sidebar did not remove these, so they come from a different element: likely a loading placeholder or glass plate rendered outside .desktop-sidebar, the narrow-width sidebar variant, or an overlay sheet used below a breakpoint. Reopening.

Owner, after the 27644444a hotfix: "sidebar burn in is still there?" New screenshot (Calendar Day view, narrow window ~540 px, dark): five grey rounded bars at the top left (x 68–350, y 210–470) and a translucent vertical plane (x 120–250) over the hour grid, after closing the sidebar. The visibility fix on .desktop-sidebar did not remove these, so they come from a different element: likely a loading placeholder or glass plate rendered outside .desktop-sidebar, the narrow-width sidebar variant, or an overlay sheet used below a breakpoint. Reopening.
Author
Owner

Continuing the #1094 hotfix on branch job/mailghost-1094. The working tree is based on origin/dev 27644444a9; HEAD is 6dfc2f2618. I am reproducing the reported Calendar Day ghost at 540 px and 600 px, in Chromium and WebKit, and will trace the bars and glass plane with elementsFromPoint before changing the shared sidebar path.

Continuing the #1094 hotfix on branch job/mailghost-1094. The working tree is based on origin/dev 27644444a91dad244073113b0ec8ec7a61f2a212; HEAD is 6dfc2f2618ad1717e95a7b0ca4871a2c210e6742. I am reproducing the reported Calendar Day ghost at 540 px and 600 px, in Chromium and WebKit, and will trace the bars and glass plane with elementsFromPoint before changing the shared sidebar path.
Author
Owner

Correction to my kickoff note: merge-base HEAD origin/dev is df92d4da12. HEAD includes the visibility fix as first parent 411497071e, but the current origin/dev hotfix 27644444a9 is not an ancestor. I will merge the current origin/dev once before the final gates, as required.

Correction to my kickoff note: `merge-base HEAD origin/dev` is df92d4da129bfead879d417aef6e0514fc56ee96. HEAD includes the visibility fix as first parent 411497071e623f384c97d8947a5d46535b0b38d2, but the current origin/dev hotfix 27644444a91dad244073113b0ec8ec7a61f2a212 is not an ancestor. I will merge the current origin/dev once before the final gates, as required.
Author
Owner

Finding during reproduction: at 540 and 600 px, an open Calendar sheet contributes .sidebar-sheet-content and the separate .sidebar-sheet-glass (backdrop-filter: blur(16px) saturate(1.5)) to elementsFromPoint over the grid. After the spring settles, both sheet nodes and the scrim are gone; stacks at the reported x=68–350 sample points contain only Calendar grid nodes. The local empty User does not yet show the reported grey rows after close. The earlier regression sweep initialized the saved sidebar preference as collapsed and never opened/closed the narrow sheet, so it could not exercise this layer lifetime. I am extending the reproduction to cover the expanded preference, close completion, real pixel samples and both engines before applying the mobile cleanup fix.

Finding during reproduction: at 540 and 600 px, an open Calendar sheet contributes `.sidebar-sheet-content` and the separate `.sidebar-sheet-glass` (`backdrop-filter: blur(16px) saturate(1.5)`) to `elementsFromPoint` over the grid. After the spring settles, both sheet nodes and the scrim are gone; stacks at the reported x=68–350 sample points contain only Calendar grid nodes. The local empty User does not yet show the reported grey rows after close. The earlier regression sweep initialized the saved sidebar preference as collapsed and never opened/closed the narrow sheet, so it could not exercise this layer lifetime. I am extending the reproduction to cover the expanded preference, close completion, real pixel samples and both engines before applying the mobile cleanup fix.
Author
Owner

Finding after the required merge: bun run check exited 2 in perf-lint because the incoming origin/dev change 04da1147f updated apps/web/src/lib/notes/NotesExplorer.svelte while its 12 matching exception hashes still referenced the old Svelte syntax. I refreshed those exact hashes in contracts/perf/exceptions.json; no NotesExplorer product code changed in this branch. I am rerunning the gate with the #1094 sidebar fingerprint refresh.

Finding after the required merge: `bun run check` exited 2 in perf-lint because the incoming `origin/dev` change `04da1147f` updated `apps/web/src/lib/notes/NotesExplorer.svelte` while its 12 matching exception hashes still referenced the old Svelte syntax. I refreshed those exact hashes in `contracts/perf/exceptions.json`; no NotesExplorer product code changed in this branch. I am rerunning the gate with the #1094 sidebar fingerprint refresh.
Author
Owner

The follow-up fingerprint scan found 41 more stale Svelte hashes from files changed by the required merge (origin/dev 4a8e226): Calendar Day, Settings, AgendaList.svelte, ItemPreview.svelte, and tokens.css. The list and style identities still match the current source; only component-level syntax hashes changed. I am refreshing those exact ledger records so the check validates the merged branch.

The follow-up fingerprint scan found 41 more stale Svelte hashes from files changed by the required merge (`origin/dev` 4a8e226): Calendar Day, Settings, `AgendaList.svelte`, `ItemPreview.svelte`, and `tokens.css`. The list and style identities still match the current source; only component-level syntax hashes changed. I am refreshing those exact ledger records so the check validates the merged branch.
Author
Owner

The next bun run check pass reached the adoption checkpoint and found two stale hashes for the same packages/ui/src/tokens.css glass-filter scopes. Their rule, file, symbol, owner, reason and replacement-test metadata still match the live exception records. I synced only those two hashes in contracts/perf/adoption-1058.json and will run the final check.

The next `bun run check` pass reached the adoption checkpoint and found two stale hashes for the same `packages/ui/src/tokens.css` glass-filter scopes. Their rule, file, symbol, owner, reason and replacement-test metadata still match the live exception records. I synced only those two hashes in `contracts/perf/adoption-1058.json` and will run the final check.
Author
Owner

The route-contract follow-up found four stale fingerprints from the merged Calendar Day and Settings page edits (two contract scopes per route). Their route identities and contract metadata are unchanged. I refreshed those four hashes; no adoption checkpoint entry refers to these scopes.

The route-contract follow-up found four stale fingerprints from the merged Calendar Day and Settings page edits (two contract scopes per route). Their route identities and contract metadata are unchanged. I refreshed those four hashes; no adoption checkpoint entry refers to these scopes.
Author
Owner

Perf-lint then reached four coverage.profile / coverage.readiness records on the changed Calendar Day and Settings pages. Their route metadata is unchanged; the gate keys these checks to the page syntax hash. I refreshed the four matching hashes. No adoption checkpoint rows refer to them.

Perf-lint then reached four `coverage.profile` / `coverage.readiness` records on the changed Calendar Day and Settings pages. Their route metadata is unchanged; the gate keys these checks to the page syntax hash. I refreshed the four matching hashes. No adoption checkpoint rows refer to them.
Author
Owner

The final bun run check still exits 2 before Svelte type-checking. It stops on the first stale fingerprint from merged origin/dev: NotesExplorer.svelte#each:3c7baf2164751d7e:1. A complete perf-lint scan found 97 changed-scope hashes and five unregistered findings in merged code, including three new notes API call sites and a changed Calendar list identity. I restored the cross-feature ledger edits and kept only the 26 app-sidebar.svelte fingerprint updates for #1094. These merge-wide findings remain for the merge round to resolve.

The final `bun run check` still exits 2 before Svelte type-checking. It stops on the first stale fingerprint from merged `origin/dev`: `NotesExplorer.svelte#each:3c7baf2164751d7e:1`. A complete perf-lint scan found 97 changed-scope hashes and five unregistered findings in merged code, including three new notes API call sites and a changed Calendar list identity. I restored the cross-feature ledger edits and kept only the 26 `app-sidebar.svelte` fingerprint updates for #1094. These merge-wide findings remain for the merge round to resolve.
Author
Owner

Starting #1094 hotfix on job/mailghost-1094. Initial branch head: f75a68001f. Required base: origin/dev 559e05cb92.

Starting #1094 hotfix on job/mailghost-1094. Initial branch head: f75a68001fdb3a28a2c7bbcb11f3714e81a40dd6. Required base: origin/dev 559e05cb9292080684cd65a5c1adcf871c1d0647.
Author
Owner

Owner clarification (2026-10-05): every sidebar report in this issue is from a DESKTOP browser window (various widths), never the phone. Latest screenshot (Money Tab, sidebar OFF): placeholder bars at the top left and a vertical line through the content at the sidebar edge. The mobile-sheet fix shipped in 570e084c8 does not apply to this. Fix the desktop collapsed state and remove the placeholder rows.

Owner clarification (2026-10-05): every sidebar report in this issue is from a DESKTOP browser window (various widths), never the phone. Latest screenshot (Money Tab, sidebar OFF): placeholder bars at the top left and a vertical line through the content at the sidebar edge. The mobile-sheet fix shipped in 570e084c8 does not apply to this. Fix the desktop collapsed state and remove the placeholder rows.
Author
Owner

Finding for #1094: the collapsed shell only delays visibility:hidden until the end of the transform, so its backdrop-filter layer can keep painting over the content during that interval. The sidebar also emits pending rows in Mail, Calendar, Photos, Tasks and the Notes explorer before real data exists. The owner screenshots show the stale rows over Inbox messages and a vertical seam; the E2E now probes the actual collapsed DOM and pixels.

Finding for #1094: the collapsed shell only delays `visibility:hidden` until the end of the transform, so its backdrop-filter layer can keep painting over the content during that interval. The sidebar also emits pending rows in Mail, Calendar, Photos, Tasks and the Notes explorer before real data exists. The owner screenshots show the stale rows over Inbox messages and a vertical seam; the E2E now probes the actual collapsed DOM and pixels.
Author
Owner

Gate finding after the required origin/dev merge: the source inventory reports 349 existing performance exception fingerprints that no longer match current source, plus 13 exception scopes whose source identity no longer exists. The first current bun run check failure after the changed sidebar pins were refreshed is an unchanged Settings route loop (apps/web/src/routes/settings/[...path]/+page.svelte#each:a177ee267c3527f1:1). This affects unrelated Calendar, Settings, Rust and UI files. I’m keeping #1094 limited to the five sidebar fingerprints and leaving the unrelated ledger debt for the merge round.

Gate finding after the required `origin/dev` merge: the source inventory reports 349 existing performance exception fingerprints that no longer match current source, plus 13 exception scopes whose source identity no longer exists. The first current `bun run check` failure after the changed sidebar pins were refreshed is an unchanged Settings route loop (`apps/web/src/routes/settings/[...path]/+page.svelte#each:a177ee267c3527f1:1`). This affects unrelated Calendar, Settings, Rust and UI files. I’m keeping #1094 limited to the five sidebar fingerprints and leaving the unrelated ledger debt for the merge round.
Author
Owner

Root cause found by the orchestrator (2026-10-05): the "fake sidebar" (pill + 5 bars), the sidebar divider line and the header hairline came from #app-boot-skeleton in apps/web/src/app.html. It sat fixed (z-index 1) OUTSIDE %sveltekit.body% and nothing removed it after hydration, so it showed through every collapsed or glass sidebar on every Tab. Hotfix 63818a5e1 removes it (boot paints only the themed background) and the reload-423 e2e now asserts it is absent. Running sidebar3 work (Tags loading row etc.) still applies; rebase on dev before finishing.

Root cause found by the orchestrator (2026-10-05): the "fake sidebar" (pill + 5 bars), the sidebar divider line and the header hairline came from `#app-boot-skeleton` in apps/web/src/app.html. It sat fixed (z-index 1) OUTSIDE %sveltekit.body% and nothing removed it after hydration, so it showed through every collapsed or glass sidebar on every Tab. Hotfix 63818a5e1 removes it (boot paints only the themed background) and the reload-423 e2e now asserts it is absent. Running sidebar3 work (Tags loading row etc.) still applies; rebase on dev before finishing.
Author
Owner

Finding for #1094: Chromium accepted the test session cookie on HTTP localhost, but WebKit did not. Its collapsed-sidebar probe redirected to /login before mounting the sidebar. The e2e now serves the same real local API through the existing HTTPS test front, so both engines use the same Secure session. WebKit also kept the app-wide text/event-stream open while normal API reads were paused; the harness now leaves EventSource streams live and waits for ordinary reads. The focused WebKit Calendar probe at 600 px passes. The full screenshot and width matrix is running.

Finding for #1094: Chromium accepted the test session cookie on HTTP localhost, but WebKit did not. Its collapsed-sidebar probe redirected to `/login` before mounting the sidebar. The e2e now serves the same real local API through the existing HTTPS test front, so both engines use the same Secure session. WebKit also kept the app-wide `text/event-stream` open while normal API reads were paused; the harness now leaves EventSource streams live and waits for ordinary reads. The focused WebKit Calendar probe at 600 px passes. The full screenshot and width matrix is running.
Author
Owner

#1094 is complete.

Branch and HEAD: job/mailghost-1094 — c8a1940022679136e84f9db84048f9a8837bae59

What changed

  • Removed synthetic loading rows from the Calendar Tags, Mail folders, Notes folders, Photos library roots and Task Tags sidebar sections. Pending reads show no invented rows; real data, confirmed empty states and errors still render.
  • A collapsed desktop sidebar now uses display: none immediately. It does not leave a divider, glass plane, row paint, focus target or hit-test target. Reopening retains its entry motion.
  • Added a Mail sidebar loading regression test and extended the production e2e with real API holds, pixel comparisons, hit tests, accessibility checks and the requested width/browser matrix.
  • Refreshed the perf fingerprints for the changed sidebar source files.

Files: apps/web/src/routes/layout.css; apps/web/src/lib/components/app-sidebar.svelte; apps/web/src/lib/mail/MailSidebar.svelte and its test; apps/web/src/lib/notes/NotesExplorer.svelte; apps/web/src/lib/photos/PhotosSidebar.svelte; apps/web/src/lib/tasks/TasksSidebar.svelte; apps/web/e2e/sidebar-collapse-1094.mjs; contracts/perf/exceptions.json.

Verification

bun run check stops before Svelte diagnostics on a stale exception for the untouched merged-base SearchPreview.svelte source. The sidebar fingerprints are current. Exact output:

$ ../../scripts/perf-lint --check && node scripts/check-user-storage.mjs && node scripts/check-glass-tokens.mjs && node scripts/check-type-tokens.mjs && node scripts/check-focus-tokens.mjs && node scripts/check-motion-tokens.mjs && svelte-kit sync && svelte-check --tsconfig ./tsconfig.json
perf-lint: parse Rust product sources
perf-lint: parse browser product sources
perf-lint: validate coverage and architecture
perf-lint: INVALID: ('render.bound', 'apps/web/src/lib/search/SearchPreview.svelte', 'apps/web/src/lib/search/SearchPreview.svelte#each:002fe5cdc680c8ed:1'): unused or changed exception

Focused Vitest passed:

 Test Files  1 passed (1)
      Tests  6 passed (6)
   Start at  13:35:17
   Duration  39.23s (transform 78%, tests 8%, environment 7%, import 5%, setup 2%)

  Transform  |component| transforming modules took 30.44s · 78% of tracked time, re-done on every run
             persist transforms across runs with fsModuleCache: true
             learn more at https://vitest.dev/guide/improving-performance#caching-between-reruns

The unfiltered production e2e passed with exit code 0. It covered 9 Tabs × 390/820/1440 px × light/dark × loading/settled screenshots, plus Chromium and WebKit at 600/1024/1440/1700 px for every Tab. It used macOS platform metadata. Exact output:

$ bun e2e/sidebar-collapse-1094.mjs
Observed 404 response paths: /api/v1/notes/journal/2026-10-05
61 | 		"test:e2e:sidebar-collapse-1094": "bun e2e/sidebar-collapse-1094.mjs",
       ^
warn: Duplicate key "test:e2e:sidebar-collapse-1094" in object literal
   at /home/kayg/Developer/calternal-wt/mailghost-1094/apps/web/package.json:61:3

The Notes journal 404 is the empty test Instance's missing daily journal. It produced no page error or 5xx. The direct Svelte check passed: svelte-check found 0 errors and 4 warnings in 3 files; the warnings are in unchanged AttachmentDeck, AgendaList and Notes page styles.

The 108 screenshot set is attached: sidebar-collapse-1094-final-green.zip. The PNGs and ZIP remain under ignored artifacts/ and are not committed.

UX gaps closed / left

Closed: loading rows no longer imply data exists before a response; Task Tags retains a real retry state on error; all requested collapsed views are absent from pixels, focus, accessibility and pointer hit testing during and after loading.

Left: none found in this issue's sidebar scope.

Decisions and known gaps

  • The design document does not define a delayed sidebar exit. The collapsed state removes the sidebar immediately to guarantee zero paint; reopening keeps its entry motion.
  • WebKit does not send the Secure session cookie from HTTP localhost, so the e2e uses the existing HTTPS test front. The test leaves EventSource streams live while it holds ordinary API reads.
  • bun run check remains blocked by the stale, untouched SearchPreview.svelte fingerprint above. The direct Svelte check passes with four pre-existing warnings.
  • No Rust source or API route changed; Rust gates and an adversarial API round were not applicable.

For the merge round

Run bun run check after the merged perf ledger baseline is reconciled, then run bun run test for the combined web suite.

READY FOR HOTFIX: yes, with the existing perf-lint baseline failure recorded above. No push, deploy or final merge was done.

#1094 is complete. **Branch and HEAD:** `job/mailghost-1094` — `c8a1940022679136e84f9db84048f9a8837bae59` ## What changed - Removed synthetic loading rows from the Calendar Tags, Mail folders, Notes folders, Photos library roots and Task Tags sidebar sections. Pending reads show no invented rows; real data, confirmed empty states and errors still render. - A collapsed desktop sidebar now uses `display: none` immediately. It does not leave a divider, glass plane, row paint, focus target or hit-test target. Reopening retains its entry motion. - Added a Mail sidebar loading regression test and extended the production e2e with real API holds, pixel comparisons, hit tests, accessibility checks and the requested width/browser matrix. - Refreshed the perf fingerprints for the changed sidebar source files. **Files:** `apps/web/src/routes/layout.css`; `apps/web/src/lib/components/app-sidebar.svelte`; `apps/web/src/lib/mail/MailSidebar.svelte` and its test; `apps/web/src/lib/notes/NotesExplorer.svelte`; `apps/web/src/lib/photos/PhotosSidebar.svelte`; `apps/web/src/lib/tasks/TasksSidebar.svelte`; `apps/web/e2e/sidebar-collapse-1094.mjs`; `contracts/perf/exceptions.json`. ## Verification `bun run check` stops before Svelte diagnostics on a stale exception for the untouched merged-base `SearchPreview.svelte` source. The sidebar fingerprints are current. Exact output: ```text $ ../../scripts/perf-lint --check && node scripts/check-user-storage.mjs && node scripts/check-glass-tokens.mjs && node scripts/check-type-tokens.mjs && node scripts/check-focus-tokens.mjs && node scripts/check-motion-tokens.mjs && svelte-kit sync && svelte-check --tsconfig ./tsconfig.json perf-lint: parse Rust product sources perf-lint: parse browser product sources perf-lint: validate coverage and architecture perf-lint: INVALID: ('render.bound', 'apps/web/src/lib/search/SearchPreview.svelte', 'apps/web/src/lib/search/SearchPreview.svelte#each:002fe5cdc680c8ed:1'): unused or changed exception ``` Focused Vitest passed: ```text Test Files 1 passed (1) Tests 6 passed (6) Start at 13:35:17 Duration 39.23s (transform 78%, tests 8%, environment 7%, import 5%, setup 2%) Transform |component| transforming modules took 30.44s · 78% of tracked time, re-done on every run persist transforms across runs with fsModuleCache: true learn more at https://vitest.dev/guide/improving-performance#caching-between-reruns ``` The unfiltered production e2e passed with exit code 0. It covered 9 Tabs × 390/820/1440 px × light/dark × loading/settled screenshots, plus Chromium and WebKit at 600/1024/1440/1700 px for every Tab. It used macOS platform metadata. Exact output: ```text $ bun e2e/sidebar-collapse-1094.mjs Observed 404 response paths: /api/v1/notes/journal/2026-10-05 61 | "test:e2e:sidebar-collapse-1094": "bun e2e/sidebar-collapse-1094.mjs", ^ warn: Duplicate key "test:e2e:sidebar-collapse-1094" in object literal at /home/kayg/Developer/calternal-wt/mailghost-1094/apps/web/package.json:61:3 ``` The Notes journal 404 is the empty test Instance's missing daily journal. It produced no page error or 5xx. The direct Svelte check passed: `svelte-check found 0 errors and 4 warnings in 3 files`; the warnings are in unchanged AttachmentDeck, AgendaList and Notes page styles. The 108 screenshot set is attached: [sidebar-collapse-1094-final-green.zip](https://git.kayg.org/attachments/3c138350-f46d-42e0-8042-56ada581531f). The PNGs and ZIP remain under ignored `artifacts/` and are not committed. ## UX gaps closed / left Closed: loading rows no longer imply data exists before a response; Task Tags retains a real retry state on error; all requested collapsed views are absent from pixels, focus, accessibility and pointer hit testing during and after loading. Left: none found in this issue's sidebar scope. ## Decisions and known gaps - The design document does not define a delayed sidebar exit. The collapsed state removes the sidebar immediately to guarantee zero paint; reopening keeps its entry motion. - WebKit does not send the Secure session cookie from HTTP localhost, so the e2e uses the existing HTTPS test front. The test leaves EventSource streams live while it holds ordinary API reads. - `bun run check` remains blocked by the stale, untouched `SearchPreview.svelte` fingerprint above. The direct Svelte check passes with four pre-existing warnings. - No Rust source or API route changed; Rust gates and an adversarial API round were not applicable. ## For the merge round Run `bun run check` after the merged perf ledger baseline is reconciled, then run `bun run test` for the combined web suite. **READY FOR HOTFIX: yes**, with the existing perf-lint baseline failure recorded above. No push, deploy or final merge was done.
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#1094
No description provided.