BUGS from the fresh audit capture (#261): phone hit targets, CLS, mobile timeouts, Analytics inset #278

Closed
opened 2026-09-27 22:11:20 +00:00 by kayg · 18 comments
Owner

From the #261 fresh capture on HEAD (see docs/audits/consistency-237.md):

  1. Phone hit targets below 44 px: Search palette actions 35×35 px, Ask mode rows 43 px high; Calendar Week and Agenda controls fail edge hit tests. Fix via the shared control sizes (tokens), not per call site.
  2. Layout shift: Calendar Month on phone records CLS 0.119 while loading (budget ≤ 0.05): reserve the grid's final size before data arrives (skeleton with the real geometry).
  3. Mobile interaction timeouts: folder navigation, photo viewer, Admin sign-in, Calendar preview, Files selection/toast checks time out in the probe. Reproduce each; fix real hangs; fix flaky probes without weakening them.
  4. Analytics StatRow controls 12 px from the card edge (18 px expected) — same as #252; close #252 with this.
    (Icon/label vertical offsets are covered by #253.)
    Regression: the layout sweep assertions for 1, 2 and 4 must pass at 390 and 1440, light + dark.
From the #261 fresh capture on HEAD (see docs/audits/consistency-237.md): 1. **Phone hit targets** below 44 px: Search palette actions 35×35 px, Ask mode rows 43 px high; Calendar Week and Agenda controls fail edge hit tests. Fix via the shared control sizes (tokens), not per call site. 2. **Layout shift**: Calendar Month on phone records CLS 0.119 while loading (budget ≤ 0.05): reserve the grid's final size before data arrives (skeleton with the real geometry). 3. **Mobile interaction timeouts**: folder navigation, photo viewer, Admin sign-in, Calendar preview, Files selection/toast checks time out in the probe. Reproduce each; fix real hangs; fix flaky probes without weakening them. 4. **Analytics StatRow** controls 12 px from the card edge (18 px expected) — same as #252; close #252 with this. (Icon/label vertical offsets are covered by #253.) Regression: the layout sweep assertions for 1, 2 and 4 must pass at 390 and 1440, light + dark.
Author
Owner

Started work on #278 and the linked #252 inset issue on job/audit-bugs, based on dev at 4787d78f8f788c3fee9477ba4474beb1f9c91747. I will reproduce the phone target, Month CLS, mobile interaction timeout, and Analytics inset findings, then commit each fix with its regression coverage.

Started work on #278 and the linked #252 inset issue on `job/audit-bugs`, based on `dev` at `4787d78f8f788c3fee9477ba4474beb1f9c91747`. I will reproduce the phone target, Month CLS, mobile interaction timeout, and Analytics inset findings, then commit each fix with its regression coverage.
Author
Owner

Finding from #252 / #278: StatRow.svelte gave the floated comparison control margin-right: -6px. Card supplies 18px horizontal padding, so this moved the control to 12px from the card edge. Removed the negative margin and added a regression assertion that the control stays on the card content edge. Focused result: 13 StatRow tests passed.

Finding from #252 / #278: `StatRow.svelte` gave the floated comparison control `margin-right: -6px`. `Card` supplies 18px horizontal padding, so this moved the control to 12px from the card edge. Removed the negative margin and added a regression assertion that the control stays on the card content edge. Focused result: 13 StatRow tests passed.
Author
Owner

Finding from the current production build: node e2e/layout-sweep.mjs --only calendar-month reproduces FAIL calendar-month 390 open paper: calendar layout shift: CLS 0.122 while loading. The existing browser harness measured this route on the real app and server; I am tracing the Month view's loading geometry and will add the 0.05 assertion for phone and desktop themes.

Finding from the current production build: `node e2e/layout-sweep.mjs --only calendar-month` reproduces `FAIL calendar-month 390 open paper: calendar layout shift: CLS 0.122 while loading`. The existing browser harness measured this route on the real app and server; I am tracing the Month view's loading geometry and will add the 0.05 assertion for phone and desktop themes.
Author
Owner

Reproduced the 390 px Month CLS in the production layout sweep: before the fix it reached 0.112, with populated week tracks moving later cells down by up to 123 px. The mobile grid used minmax(72px, auto), so data expanded the tracks after first paint. The tracks now use the same fixed, viewport-aware size before and after data arrives. node e2e/layout-sweep.mjs --only calendar-month --screenshots artifacts/audit-bugs/month passes its 0.05 Month budget across 390 px and 1440 px in both themes (8 screens). Screenshots are in apps/web/artifacts/audit-bugs/month/.

Reproduced the 390 px Month CLS in the production layout sweep: before the fix it reached 0.112, with populated week tracks moving later cells down by up to 123 px. The mobile grid used `minmax(72px, auto)`, so data expanded the tracks after first paint. The tracks now use the same fixed, viewport-aware size before and after data arrives. `node e2e/layout-sweep.mjs --only calendar-month --screenshots artifacts/audit-bugs/month` passes its 0.05 Month budget across 390 px and 1440 px in both themes (8 screens). Screenshots are in `apps/web/artifacts/audit-bugs/month/`.
Author
Owner

Correction to my previous CLS comment: those eight “passing” screens used target/debug/calternal-server with the older embedded web bundle. The sweep needs a server rebuild after bun run build; that was missing. I am rebuilding the embedded server and will post the valid CLS result after rerunning the production probe.

Correction to my previous CLS comment: those eight “passing” screens used `target/debug/calternal-server` with the older embedded web bundle. The sweep needs a server rebuild after `bun run build`; that was missing. I am rebuilding the embedded server and will post the valid CLS result after rerunning the production probe.
Author
Owner

Phone hit-test and timeout findings reproduced on the rebuilt production app. Calendar Week used a 43.86 px track for a 44 px target; its edge probe hit the next day. The shared --hit token is now the minimum track width. SearchResultRow now uses the shared --row-h and touch-hit helper; the 390 px Ask and Search palette probes pass.

Three timeout probes were stale after shared component markup changed: Calendar Day exposes a phone Agenda .stack and .popover-sheet while desktop uses a TimeGrid .pile and .cal-popover; Files and Photos SelectionBar uses .selection-bar and .selection-count. I updated these selectors and corrected AppToaster's selection-bar lookup. The Calendar preview now opens on phone. The four Files stacked-toast probes pass (1440/390, Paper/Tokyo Night).

The Calendar preview layout check still reports the 1.0–1.4 px icon offsets tracked by #253; this is separate from the preview interaction timeout.

Phone hit-test and timeout findings reproduced on the rebuilt production app. Calendar Week used a 43.86 px track for a 44 px target; its edge probe hit the next day. The shared `--hit` token is now the minimum track width. SearchResultRow now uses the shared `--row-h` and `touch-hit` helper; the 390 px Ask and Search palette probes pass. Three timeout probes were stale after shared component markup changed: Calendar Day exposes a phone Agenda `.stack` and `.popover-sheet` while desktop uses a TimeGrid `.pile` and `.cal-popover`; Files and Photos SelectionBar uses `.selection-bar` and `.selection-count`. I updated these selectors and corrected AppToaster's selection-bar lookup. The Calendar preview now opens on phone. The four Files stacked-toast probes pass (1440/390, Paper/Tokyo Night). The Calendar preview layout check still reports the 1.0–1.4 px icon offsets tracked by #253; this is separate from the preview interaction timeout.
Author
Owner

Photos deep-link finding: after a cold /p/<id> for 2024-05-11, closing the viewer left the viewport at the right date but rendered no month headings. Browser evidence showed scrollY 3027, timeline height 4153 px, and virtual window top 4950 px, so the render window remained past the end of the timeline. PhotoTimeline.jumpTo now recomputes the render window on the next animation frame after the browser commits scrollTo; cold-item and loaded-item paths also retain the group key and date. The Photos E2E now passes the cold-link return and /photos/<year>/<month> checks. I also fixed the Photos runner’s cleanup race (wait for server exit before removing Tantivy data) and scoped a duplicate Tags heading locator without changing its required state.

The full Photos E2E proceeds past deep links, media browsing, and selection, then times out in its HLS fallback media-metadata probe (readyState: 4, no HLS master/variant/segment requests, two direct source GETs). That remains a separate probe gap; no timeout was weakened.

Photos deep-link finding: after a cold `/p/<id>` for 2024-05-11, closing the viewer left the viewport at the right date but rendered no month headings. Browser evidence showed scrollY 3027, timeline height 4153 px, and virtual window top 4950 px, so the render window remained past the end of the timeline. `PhotoTimeline.jumpTo` now recomputes the render window on the next animation frame after the browser commits `scrollTo`; cold-item and loaded-item paths also retain the group key and date. The Photos E2E now passes the cold-link return and `/photos/<year>/<month>` checks. I also fixed the Photos runner’s cleanup race (wait for server exit before removing Tantivy data) and scoped a duplicate Tags heading locator without changing its required state. The full Photos E2E proceeds past deep links, media browsing, and selection, then times out in its HLS fallback media-metadata probe (`readyState: 4`, no HLS master/variant/segment requests, two direct source GETs). That remains a separate probe gap; no timeout was weakened.
Author
Owner

Mobile folder probe finding: layout-sweep --only files-folder timed out clicking “Show sidebar” on /files?path=Projects. That nested phone view intentionally has “Back to Home” in the mode header, which replaces the sidebar toggle; the navigation sheet remains available by the documented edge swipe. The probe now uses that edge swipe when the toggle is absent and still requires .sidebar-sheet-content to open. The rebuilt production sweep passes all 8 folder route variants (390/1440 px, both themes, open/collapsed where applicable).

Mobile folder probe finding: `layout-sweep --only files-folder` timed out clicking “Show sidebar” on `/files?path=Projects`. That nested phone view intentionally has “Back to Home” in the mode header, which replaces the sidebar toggle; the navigation sheet remains available by the documented edge swipe. The probe now uses that edge swipe when the toggle is absent and still requires `.sidebar-sheet-content` to open. The rebuilt production sweep passes all 8 folder route variants (390/1440 px, both themes, open/collapsed where applicable).
Author
Owner

Post-merge production probe finding: Search action targets measured 43.46px during the palette's 0.985 entrance scale, below the 44px touch minimum. I increased the shared feed-toolbar hit token by 2px; the 390px layout sweep now passes all 8 screens. The sweep selector also targets the visible .surface.search-window, since the merged overlay renders a pointer-transparent backdrop with the same class.

Post-merge production probe finding: Search action targets measured 43.46px during the palette's 0.985 entrance scale, below the 44px touch minimum. I increased the shared feed-toolbar hit token by 2px; the 390px layout sweep now passes all 8 screens. The sweep selector also targets the visible `.surface.search-window`, since the merged overlay renders a pointer-transparent backdrop with the same class.
Author
Owner

Resuming in . Current head is ; the last shared base is . I am reviewing the in-progress layout sweep and Files text alignment changes, then I will merge current once and run the final gates.

Resuming in . Current head is ; the last shared base is . I am reviewing the in-progress layout sweep and Files text alignment changes, then I will merge current once and run the final gates.
Author
Owner

Correction to my start note: the branch is job/audit-bugs at cef0939743, based on 71ff5e11ec. I am reviewing the in-progress layout sweep and Files text alignment changes, then I will merge current dev once and run the final gates.

Correction to my start note: the branch is job/audit-bugs at cef0939743f2041b654ddd862e145906f3142e95, based on 71ff5e11ecdaf4e37e3558242df383b7a54f14a. I am reviewing the in-progress layout sweep and Files text alignment changes, then I will merge current dev once and run the final gates.
Author
Owner

Finding after the current dev merge: files-folder measured the phone Projects breadcrumb text ink 1.0 px below its ellipsis clipping box in both sidebar states. I applied the existing .optical-caps helper to the breadcrumb labels; the layout sweep keeps the same clipping assertion. Rebuilt the production web bundle and embedded server. The rerun passed all 8 Files folder variants at 390/1440 px in both themes.

Finding after the current dev merge: `files-folder` measured the phone Projects breadcrumb text ink 1.0 px below its ellipsis clipping box in both sidebar states. I applied the existing `.optical-caps` helper to the breadcrumb labels; the layout sweep keeps the same clipping assertion. Rebuilt the production web bundle and embedded server. The rerun passed all 8 Files folder variants at 390/1440 px in both themes.
Author
Owner

Post-merge Search e2e evidence: phone search action hit-target checks passed, as did palette growth and open/close behavior. The run then failed its existing sticky-paint equality assertion: .group-head computed to rgb(255, 255, 255) and .surface.search-window to rgba(0, 0, 0, 0). The heading uses var(--glass-tint, var(--surface)); OverlaySurface paints its clear-glass layer in a sibling background element. I left the assertion unchanged. This paint check remains for owner review.

Post-merge Search e2e evidence: phone search action hit-target checks passed, as did palette growth and open/close behavior. The run then failed its existing sticky-paint equality assertion: `.group-head` computed to `rgb(255, 255, 255)` and `.surface.search-window` to `rgba(0, 0, 0, 0)`. The heading uses `var(--glass-tint, var(--surface))`; OverlaySurface paints its clear-glass layer in a sibling background element. I left the assertion unchanged. This paint check remains for owner review.
Author
Owner

Adversarial finding on the merged tree: the editor browser probe found that Ctrl+Z followed by Ctrl+Shift+Z after hostile paste and IME input changed textContent from Anchor headingparent... to Anchor heading parent... (three added spaces between adjacent blocks). The probe stops before its later save assertion, so saved Markdown impact is not yet established. I did not change the assertion. The rest of the one-round API probe is still running; this finding needs separate editor triage.

Adversarial finding on the merged tree: the editor browser probe found that Ctrl+Z followed by Ctrl+Shift+Z after hostile paste and IME input changed `textContent` from `Anchor headingparent...` to `Anchor heading parent...` (three added spaces between adjacent blocks). The probe stops before its later save assertion, so saved Markdown impact is not yet established. I did not change the assertion. The rest of the one-round API probe is still running; this finding needs separate editor triage.
Author
Owner

Post-merge production screenshots from the rebuilt web bundle and local calternal-server: Month, Analytics, the Files folder and Search palette. These captures stay in the ignored apps/web/artifacts/audit-bugs directory and are attached here for visual review.

Post-merge production screenshots from the rebuilt web bundle and local calternal-server: Month, Analytics, the Files folder and Search palette. These captures stay in the ignored apps/web/artifacts/audit-bugs directory and are attached here for visual review.
Author
Owner

Completed

Finished #278 on job/audit-bugs. Merged the current local dev once (104b7db2) and pushed HEAD 988efe9beae77b9c128c72670df7a4af8f10b66c.

What changed

  • Fixed the Analytics StatRow inset and added a regression assertion.
  • Reserved Calendar Month row geometry before data loads and tightened the CLS budget.
  • Kept Search and Calendar phone controls above the 44 px target during motion; corrected stale mobile probes for Search, Calendar preview, Files selection/toasts, and folder edge-swipe navigation.
  • Fixed cold Photos deep-link return-to-timeline behavior.
  • Improved layout failure geometry output, and used the existing .optical-caps helper for Files and folder breadcrumb labels where the production sweep found clipped ink.

Files changed: apps/web/e2e/{header-sweep,layout-sweep,photos,popover-screenshots}.mjs; apps/web/src/calternal-app.css; apps/web/src/lib/components/AppToaster.svelte; apps/web/src/lib/components/analytics/widgets/{StatRow.svelte,StatRow.svelte.test.ts}; apps/web/src/lib/photos/{PhotoTimeline.svelte,PhotosView.svelte}; apps/web/src/lib/search/SearchResultRow.svelte; packages/ui/src/components/{ModeHeader.svelte,calendar/MonthGrid.svelte,calendar/TimeGrid.svelte,files/FileCollection.svelte}; packages/ui/src/tokens.css.

The five production screenshots are attached in the screenshot comment. They are not committed.

Gates and production probes

Verbatim gate output excerpts:

cargo fmt --check
(no stdout; exit code 0)

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 1m 16s

test result: ok. 486 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.21s
test result: ok. 117 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 29.70s
test result: ok. 40 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 20.92s

svelte-check found 0 errors and 0 warnings
 Test Files  103 passed (103)
      Tests  677 passed (677)

The production Month, Analytics day, and Files folder sweeps each ended with checked 8 screens and LAYOUT SWEEP PASSED. The Search browser probe printed PASS phone search action hit targets before its separate sticky-paint assertion failed (see remaining work). cargo clean output: Removed 17069 files, 14.7GiB total. apps/web/build was deleted.

Remaining work

  • Search E2E measures the sticky .group-head as opaque white and .surface.search-window as transparent, so its existing shared-paint assertion fails. I left the assertion unchanged; reconcile the probe with the sibling clear-glass background in OverlaySurface.
  • The one-round adversarial script reached its 7-minute cap (exit 124) after the auth matrix and several API probes. It reported the DAV incremental sync probe as SLOW 5.1s. The editor undo/redo probe found three spaces inserted between adjacent blocks after hostile paste and IME input; saved Markdown impact was not established because the probe stopped at its text assertion. This is recorded on existing issue #280, with no duplicate issue created.
  • The earlier Photos E2E HLS fallback metadata probe gap remains as reported in the prior #278 comments.

Decisions

Reused .optical-caps for the two clipped label surfaces. No design-doc decision or test expectation changed. The browser probe needed the host Nix libstdc++ path for sharp; this was a process-local environment setting and did not change the repo.

## Completed Finished #278 on `job/audit-bugs`. Merged the current local `dev` once (`104b7db2`) and pushed HEAD `988efe9beae77b9c128c72670df7a4af8f10b66c`. ## What changed - Fixed the Analytics `StatRow` inset and added a regression assertion. - Reserved Calendar Month row geometry before data loads and tightened the CLS budget. - Kept Search and Calendar phone controls above the 44 px target during motion; corrected stale mobile probes for Search, Calendar preview, Files selection/toasts, and folder edge-swipe navigation. - Fixed cold Photos deep-link return-to-timeline behavior. - Improved layout failure geometry output, and used the existing `.optical-caps` helper for Files and folder breadcrumb labels where the production sweep found clipped ink. Files changed: `apps/web/e2e/{header-sweep,layout-sweep,photos,popover-screenshots}.mjs`; `apps/web/src/calternal-app.css`; `apps/web/src/lib/components/AppToaster.svelte`; `apps/web/src/lib/components/analytics/widgets/{StatRow.svelte,StatRow.svelte.test.ts}`; `apps/web/src/lib/photos/{PhotoTimeline.svelte,PhotosView.svelte}`; `apps/web/src/lib/search/SearchResultRow.svelte`; `packages/ui/src/components/{ModeHeader.svelte,calendar/MonthGrid.svelte,calendar/TimeGrid.svelte,files/FileCollection.svelte}`; `packages/ui/src/tokens.css`. The five production screenshots are attached in [the screenshot comment](https://git.kayg.org/kayg/calternal/issues/278#issuecomment-10012). They are not committed. ## Gates and production probes Verbatim gate output excerpts: ```text cargo fmt --check (no stdout; exit code 0) Finished `dev` profile [unoptimized + debuginfo] target(s) in 1m 16s test result: ok. 486 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.21s test result: ok. 117 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 29.70s test result: ok. 40 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 20.92s svelte-check found 0 errors and 0 warnings Test Files 103 passed (103) Tests 677 passed (677) ``` The production Month, Analytics day, and Files folder sweeps each ended with `checked 8 screens` and `LAYOUT SWEEP PASSED`. The Search browser probe printed `PASS phone search action hit targets` before its separate sticky-paint assertion failed (see remaining work). `cargo clean` output: `Removed 17069 files, 14.7GiB total`. `apps/web/build` was deleted. ## Remaining work - Search E2E measures the sticky `.group-head` as opaque white and `.surface.search-window` as transparent, so its existing shared-paint assertion fails. I left the assertion unchanged; reconcile the probe with the sibling clear-glass background in `OverlaySurface`. - The one-round adversarial script reached its 7-minute cap (exit 124) after the auth matrix and several API probes. It reported the DAV incremental sync probe as `SLOW 5.1s`. The editor undo/redo probe found three spaces inserted between adjacent blocks after hostile paste and IME input; saved Markdown impact was not established because the probe stopped at its text assertion. This is recorded on existing issue #280, with no duplicate issue created. - The earlier Photos E2E HLS fallback metadata probe gap remains as reported in the prior #278 comments. ## Decisions Reused `.optical-caps` for the two clipped label surfaces. No design-doc decision or test expectation changed. The browser probe needed the host Nix `libstdc++` path for `sharp`; this was a process-local environment setting and did not change the repo.
Author
Owner

Gate timing detail: the full Rust and web gates ran after the dev merge but before the final three-class breadcrumb optical-caps correction. After that correction, I rebuilt the production SPA and embedded server and reran the Files folder production sweep; both passed. I did not repeat the full gates.

Gate timing detail: the full Rust and web gates ran after the dev merge but before the final three-class breadcrumb optical-caps correction. After that correction, I rebuilt the production SPA and embedded server and reran the Files folder production sweep; both passed. I did not repeat the full gates.
Author
Owner

Merged in 6c2f3b41.

Merged in 6c2f3b41.
kayg closed this issue 2026-09-28 02:55:42 +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#278
No description provided.