Calendar day selection has expensive script and layout work #1492

Open
opened 2026-10-08 23:30:31 +00:00 by kayg · 24 comments
Owner

Evidence

This reproduces on origin/dev revision cc1af3c12b68ad26c8403adde1be39c096b9ddea with Linux headless Chrome and 84 indexed Calendar Events plus 84 indexed calendar Tasks. Ten trusted MiniMonth day picks took 265.3 ms p50 / 471.9 ms p95, above the 150 ms Action budget in DESIGN §59. The host had 12 CPUs and a 1-minute load average of 14.38 before the capture and 14.05 during it; these are local Linux traces, not perf-VM numbers.

Per selection, Chrome recorded:

  • Script: FunctionCall was 56.13 ms p50 / 150.26 ms p95. The largest frame was an anonymous function in the shared Svelte runtime chunk BIPLcumV.js, 44.97 ms p50 / 99.61 ms p95. The production chunk is minified, so the trace does not map that frame to a source component.
  • Style and layout: UpdateLayoutTree plus Layout was 31.61 ms p50 / 48.63 ms p95. The respective p50 values were 15.38 ms and 16.23 ms.
  • Pointer dispatch: EventDispatch was 0.009 ms p50 / 2.232 ms p95. Most of the traced work occurs after pointer dispatch.

Trace output: target/tmp/1392-calendar-audit.json and target/tmp/1392-interaction-trace-calendar-select-calendar-day-{1..10}.json.gz in worktree slowsel-1392.

Expected result

The selected day is visible within 150 ms, as DESIGN §59 requires for an accepted Action.

Suggested direction

Keep the MiniMonth selected-date update narrow and synchronous. Review the Calendar page and MiniMonth Svelte effects for broad invalidation or style/layout work when the date changes. Preserve the loaded Calendar grid and update only the changed date state before background data refresh.

## Evidence This reproduces on `origin/dev` revision `cc1af3c12b68ad26c8403adde1be39c096b9ddea` with Linux headless Chrome and 84 indexed Calendar Events plus 84 indexed calendar Tasks. Ten trusted MiniMonth day picks took **265.3 ms p50 / 471.9 ms p95**, above the **150 ms Action budget** in DESIGN §59. The host had 12 CPUs and a 1-minute load average of 14.38 before the capture and 14.05 during it; these are local Linux traces, not perf-VM numbers. Per selection, Chrome recorded: - **Script:** `FunctionCall` was 56.13 ms p50 / 150.26 ms p95. The largest frame was an anonymous function in the shared Svelte runtime chunk `BIPLcumV.js`, 44.97 ms p50 / 99.61 ms p95. The production chunk is minified, so the trace does not map that frame to a source component. - **Style and layout:** `UpdateLayoutTree` plus `Layout` was **31.61 ms p50 / 48.63 ms p95**. The respective p50 values were 15.38 ms and 16.23 ms. - **Pointer dispatch:** `EventDispatch` was 0.009 ms p50 / 2.232 ms p95. Most of the traced work occurs after pointer dispatch. Trace output: `target/tmp/1392-calendar-audit.json` and `target/tmp/1392-interaction-trace-calendar-select-calendar-day-{1..10}.json.gz` in worktree `slowsel-1392`. ## Expected result The selected day is visible within 150 ms, as DESIGN §59 requires for an accepted Action. ## Suggested direction Keep the MiniMonth selected-date update narrow and synchronous. Review the Calendar page and MiniMonth Svelte effects for broad invalidation or style/layout work when the date changes. Preserve the loaded Calendar grid and update only the changed date state before background data refresh.
Author
Owner

Source-map finding from the 10 production traces: the 28.71–79.89 ms anonymous frame in BIPLcumV.js:2:4903 maps to Svelte 5.57.1 internal/client/dom/blocks/each.js, reconcile(), line 467. That is the EACH_IS_ANIMATED keyed-list path; it calls each animated node's measure() before reconciliation. The Calendar Top row passes a freshly allocated array from calendarViewOptions(compact) into the shared SegmentedControl, whose options use animate:flip. A date change therefore made an unchanged view switcher run those FLIP measurements. I am keeping option identity stable until the shortcut signature changes, and will compare script/layout costs after the change.

Source-map finding from the 10 production traces: the 28.71–79.89 ms anonymous frame in `BIPLcumV.js:2:4903` maps to Svelte 5.57.1 `internal/client/dom/blocks/each.js`, `reconcile()`, line 467. That is the `EACH_IS_ANIMATED` keyed-list path; it calls each animated node's `measure()` before reconciliation. The Calendar Top row passes a freshly allocated array from `calendarViewOptions(compact)` into the shared `SegmentedControl`, whose options use `animate:flip`. A date change therefore made an unchanged view switcher run those FLIP measurements. I am keeping option identity stable until the shortcut signature changes, and will compare script/layout costs after the change.
Author
Owner

Chrome traces from ten Calendar day selections show Svelte 5.57.1 keyed each reconciliation in each.js:467 spending 29–80 ms per measured selection on the baseline, with UpdateLayoutTree at 15–21 ms and Layout at 11–20 ms. An opt-in bounding-box probe mapped the FLIP measurement to the global Settings row in SidebarLinks: it received a new literal items array on route updates even when the href and current state did not change. I stabilized that input and the fixed Calendar source row. AppToaster also reads the toast dock and tabbar bounds after route updates; I have not changed that shared positioning behavior.

Chrome traces from ten Calendar day selections show Svelte 5.57.1 keyed each reconciliation in `each.js:467` spending 29–80 ms per measured selection on the baseline, with `UpdateLayoutTree` at 15–21 ms and `Layout` at 11–20 ms. An opt-in bounding-box probe mapped the FLIP measurement to the global Settings row in `SidebarLinks`: it received a new literal `items` array on route updates even when the href and current state did not change. I stabilized that input and the fixed Calendar source row. `AppToaster` also reads the toast dock and tabbar bounds after route updates; I have not changed that shared positioning behavior.
Author
Owner

#1492 implementation status

Implemented the shared Calendar selection and layout work on job/calsel-1491, head fc99fab050bbb3fd549c2924aff6c00d86b2f54d.

Calendar day selection now reuses a complete matching cached range, paints the selected date and detail immediately, and defers repair reads. It makes zero critical requests before selected-day visibility. Stable option identities and toaster measurement guards also remove unrelated selection-time script and layout work.

Five interleaved Linux rounds measured input-to-visible at 304.3/457.2 ms p50/p95 on origin/dev and 257.6/393.7 ms on the candidate. The candidate improves both measures but remains above the 100 ms p95 budget. The shared perf VM was held by another job, so it was not measured. The screenshot harness's keyboard Undo assertion timed out after captures; see the #1491 report for the remaining gaps, gate output, and the complete Day/Week/Month screenshot set at 390/820/1440 px in light/dark with macOS emulation.

Final source checks passed: bun run check (perf-lint 0 violations; svelte-check 0 errors and 4 existing warnings) and focused Vitest (3 files, 80 tests). Full cd apps/web && bun run test -- --maxWorkers=2 remains for the merge round. The branch is clean and no issue was closed.

# #1492 implementation status Implemented the shared Calendar selection and layout work on `job/calsel-1491`, head `fc99fab050bbb3fd549c2924aff6c00d86b2f54d`. Calendar day selection now reuses a complete matching cached range, paints the selected date and detail immediately, and defers repair reads. It makes zero critical requests before selected-day visibility. Stable option identities and toaster measurement guards also remove unrelated selection-time script and layout work. Five interleaved Linux rounds measured input-to-visible at 304.3/457.2 ms p50/p95 on `origin/dev` and 257.6/393.7 ms on the candidate. The candidate improves both measures but remains above the 100 ms p95 budget. The shared perf VM was held by another job, so it was not measured. The screenshot harness's keyboard Undo assertion timed out after captures; see the #1491 report for the remaining gaps, gate output, and the complete Day/Week/Month screenshot set at 390/820/1440 px in light/dark with macOS emulation. Final source checks passed: `bun run check` (perf-lint 0 violations; svelte-check 0 errors and 4 existing warnings) and focused Vitest (3 files, 80 tests). Full `cd apps/web && bun run test -- --maxWorkers=2` remains for the merge round. The branch is clean and no issue was closed.
Author
Owner

Partial improvement deployed in merge round 35c (build 5a2c02c13). Left open: target not yet met.

Partial improvement deployed in merge round 35c (build 5a2c02c13). Left open: target not yet met.
Author
Owner

Started #1492 on job/calscript-1492, based on origin/dev 5a2c02c1300dd2f591b177395e0d8c94fc2f8df9. I am reproducing production selection traces across Day, Week and Month, attributing script and layout work, then I will compare seven interleaved origin/candidate pairs at 1440 px and 390 px and capture the selected state.

Started #1492 on `job/calscript-1492`, based on `origin/dev` `5a2c02c1300dd2f591b177395e0d8c94fc2f8df9`. I am reproducing production selection traces across Day, Week and Month, attributing script and layout work, then I will compare seven interleaved origin/candidate pairs at 1440 px and 390 px and capture the selected state.
Author
Owner

Finding: the shared selection auditor was hard-coded to Calendar Week at 1440 px. Its opt-in trace probe recorded geometry reads but not computed-style reads. I extended it to cover Day, Week and Month at the requested viewport and color scheme, open the phone sidebar when needed, capture selected state only after real Event rows are visible, and record computed-style access stacks. node --check bench/interaction-audit-1392.mjs and git diff --check pass.

Finding: the shared selection auditor was hard-coded to Calendar Week at 1440 px. Its opt-in trace probe recorded geometry reads but not computed-style reads. I extended it to cover Day, Week and Month at the requested viewport and color scheme, open the phone sidebar when needed, capture selected state only after real Event rows are visible, and record computed-style access stacks. `node --check bench/interaction-audit-1392.mjs` and `git diff --check` pass.
Author
Owner

Finding: the shared server binary exits before readiness. Its output is calternal server listening address=127.0.0.1:31999 followed by Error: NotFound; /readyz returns no HTTP status and the process is gone. crates/calternal-server/src/main.rs::retain_frontend_assets returns NotFound when embedded _app/version.json is missing. I will build the local baseline server with the production web build before continuing the trace.

Finding: the shared server binary exits before readiness. Its output is `calternal server listening address=127.0.0.1:31999` followed by `Error: NotFound`; `/readyz` returns no HTTP status and the process is gone. `crates/calternal-server/src/main.rs::retain_frontend_assets` returns `NotFound` when embedded `_app/version.json` is missing. I will build the local baseline server with the production web build before continuing the trace.
Author
Owner

Finding: bun run check reports that the existing render.bound pin for packages/ui/src/components/calendar/MonthGrid.svelte#each:1db0155a6795b294:1 is unused or changed after the row renderer update. I am refreshing the exact source pin without changing its budget before continuing the checks.

Finding: `bun run check` reports that the existing `render.bound` pin for `packages/ui/src/components/calendar/MonthGrid.svelte#each:1db0155a6795b294:1` is unused or changed after the row renderer update. I am refreshing the exact source pin without changing its budget before continuing the checks.
Author
Owner

Finding: the focused Vitest run showed that MonthGrid can receive a new tasks array on an existing CalendarDay object (Month Task title placement #867), so a WeakMap keyed only by the day object returns stale rows. I am changing the cache to validate all four row-array identities and adding coverage for collection replacement.

Finding: the focused Vitest run showed that MonthGrid can receive a new `tasks` array on an existing `CalendarDay` object (`Month Task title placement #867`), so a WeakMap keyed only by the day object returns stale rows. I am changing the cache to validate all four row-array identities and adding coverage for collection replacement.
Author
Owner

Merged-dev Week trace finding (#1492): with the 84 Event + 84 Task fixture, 10 day picks measured p50 179.1 ms and p95 253.2 ms at 1440 px. The source-mapped traces contain no geometry or computed-style reads before visibility. The largest app FunctionCall was scheduleGridWindowRead in apps/web/src/routes/calendar/[view]/[date]/+page.svelte:1204 (150.89 ms summed across the 20 Day + Week traces); Svelte each reconciliation in its runtime also dominates the aggregate CPU trace. Week sample 3 started and completed /api/v1/notes/tasks/day (32 ms), /api/v1/calendar/range (23 ms) and /api/v1/calendar/items (12 ms) before the selected day became visible. I am measuring Month and candidate comparisons next.

Merged-dev Week trace finding (#1492): with the 84 Event + 84 Task fixture, 10 day picks measured p50 179.1 ms and p95 253.2 ms at 1440 px. The source-mapped traces contain no geometry or computed-style reads before visibility. The largest app FunctionCall was `scheduleGridWindowRead` in `apps/web/src/routes/calendar/[view]/[date]/+page.svelte:1204` (150.89 ms summed across the 20 Day + Week traces); Svelte `each` reconciliation in its runtime also dominates the aggregate CPU trace. Week sample 3 started and completed `/api/v1/notes/tasks/day` (32 ms), `/api/v1/calendar/range` (23 ms) and `/api/v1/calendar/items` (12 ms) before the selected day became visible. I am measuring Month and candidate comparisons next.
Author
Owner

Merged-dev Month trace finding (#1492): at 1440 px, 10 selected-day updates measured p50 83.6 ms and p95 99.6 ms, within the 100 ms target. Three samples started /api/v1/notes/tasks/day, /api/v1/calendar/range and /api/v1/calendar/items before visibility; two of those requests completed before the selected state was visible. The source-mapped traces contain zero geometry or computed-style reads before visibility. This adds Month evidence to the Day/Week request and reconciliation findings.

Merged-dev Month trace finding (#1492): at 1440 px, 10 selected-day updates measured p50 83.6 ms and p95 99.6 ms, within the 100 ms target. Three samples started `/api/v1/notes/tasks/day`, `/api/v1/calendar/range` and `/api/v1/calendar/items` before visibility; two of those requests completed before the selected state was visible. The source-mapped traces contain zero geometry or computed-style reads before visibility. This adds Month evidence to the Day/Week request and reconciliation findings.
Author
Owner

#1492 finding: the first strict Day comparison rejects this candidate at 1440 px.

The 7 interleaved pairs ran on the perf VM under perf-run with 84 Calendar Events and 84 Tasks. Baseline input-to-visible p50/p95 was 231.2/306.4 ms; candidate was 318.9/444.6 ms. The candidate therefore fails the requested p50/p95 rule and remains over the 100 ms p95 budget. The run also recorded API requests before the audit's visible marker in candidate runs 4, 5 and 7; the audit exited 1 on that invariant. Input-event dispatch and handler time stayed under 8 ms, while candidate animation-frame gaps reached 156.5 ms. I am checking the candidate trace and marker/request ordering before retaining any Calendar changes.

#1492 finding: the first strict Day comparison rejects this candidate at 1440 px. The 7 interleaved pairs ran on the perf VM under `perf-run` with 84 Calendar Events and 84 Tasks. Baseline input-to-visible p50/p95 was 231.2/306.4 ms; candidate was 318.9/444.6 ms. The candidate therefore fails the requested p50/p95 rule and remains over the 100 ms p95 budget. The run also recorded API requests before the audit's visible marker in candidate runs 4, 5 and 7; the audit exited 1 on that invariant. Input-event dispatch and handler time stayed under 8 ms, while candidate animation-frame gaps reached 156.5 ms. I am checking the candidate trace and marker/request ordering before retaining any Calendar changes.
Author
Owner

Correction to the Day 1440 finding: that first paired run used the candidate production build with source maps enabled, while the embedded baseline uses its normal build. I have preserved the mapped build for source attribution and staged a matching candidate production build without maps. I will repeat Day 1440 and use the normal build for the remaining acceptance measurements; the prior timings are diagnostic and will not be used as the final comparison.

Correction to the Day 1440 finding: that first paired run used the candidate production build with source maps enabled, while the embedded baseline uses its normal build. I have preserved the mapped build for source attribution and staged a matching candidate production build without maps. I will repeat Day 1440 and use the normal build for the remaining acceptance measurements; the prior timings are diagnostic and will not be used as the final comparison.
Author
Owner

#1492 normal-build finding: Day selection still rejects at 1440 px.

The final no-source-map production A/B phase ran seven interleaved pairs on the perf VM under perf-run with 84 Events and 84 Tasks. Baseline p50/p95 was 229.2/368.2 ms; candidate was 265.1/454.6 ms. The strict p50/p95 rule rejects the candidate, and candidate p95 remains above the 100 ms budget. The run also exited 1 because three candidate samples started API requests before the audit's visible marker. Load average was 5.79/5.40/4.82 before and 5.94/5.44/4.89 after. I am tracing the normal production candidate to attribute the frame gaps before changing the implementation.

#1492 normal-build finding: Day selection still rejects at 1440 px. The final no-source-map production A/B phase ran seven interleaved pairs on the perf VM under `perf-run` with 84 Events and 84 Tasks. Baseline p50/p95 was 229.2/368.2 ms; candidate was 265.1/454.6 ms. The strict p50/p95 rule rejects the candidate, and candidate p95 remains above the 100 ms budget. The run also exited 1 because three candidate samples started API requests before the audit's visible marker. Load average was 5.79/5.40/4.82 before and 5.94/5.44/4.89 after. I am tracing the normal production candidate to attribute the frame gaps before changing the implementation.
Author
Owner

The Day 390 px candidate run stopped before producing a timing report: the build-update notice remained attached after the audit sent Escape, and dismissBuildUpdateToast timed out after 2 seconds. I updated that helper to use the shared toast dismissal button when present, retaining Escape as the fallback for the controller notice. The clean-capture assertion remains enabled. Fix committed as 3862a28c2.

The Day 390 px candidate run stopped before producing a timing report: the build-update notice remained attached after the audit sent Escape, and `dismissBuildUpdateToast` timed out after 2 seconds. I updated that helper to use the shared toast dismissal button when present, retaining Escape as the fallback for the controller notice. The clean-capture assertion remains enabled. Fix committed as 3862a28c2.
Author
Owner

The source-map baseline has 10 traced selections each for Day, Week and Month at 1440 px. Across the 30 traces, scheduleGridWindowRead accounts for 150.9 ms of aggregate FunctionCall time and Svelte keyed-each reconciliation accounts for 913.1 ms of aggregate inclusive CPU. The audit recorded no geometry, computed-style or CSS-property reads before the selected state became visible. TimeGrid.measure() reads --gutter and --hit only during resize; the selection path did not show pill-feedback style reads or SegmentedControl FLIP work.

The first normal-build Day/1440 candidate comparison rejected the prior candidate: baseline 229.2/368.2 ms p50/p95, candidate 265.1/454.6 ms. Three candidate samples also began API requests before the mini-month selection marker was visible. I moved the optimistic main-grid date update to the existing second animation frame; the mini-month selection still updates immediately. This lets the changed date cell paint before the larger derived grid update and route navigation. Commit: ad426cce47. bun run check and bun run test -- --maxWorkers=2 now pass; I will measure this revision against origin/dev after the perf VM lock is available.

The source-map baseline has 10 traced selections each for Day, Week and Month at 1440 px. Across the 30 traces, `scheduleGridWindowRead` accounts for 150.9 ms of aggregate FunctionCall time and Svelte keyed-each reconciliation accounts for 913.1 ms of aggregate inclusive CPU. The audit recorded no geometry, computed-style or CSS-property reads before the selected state became visible. `TimeGrid.measure()` reads `--gutter` and `--hit` only during resize; the selection path did not show pill-feedback style reads or SegmentedControl FLIP work. The first normal-build Day/1440 candidate comparison rejected the prior candidate: baseline 229.2/368.2 ms p50/p95, candidate 265.1/454.6 ms. Three candidate samples also began API requests before the mini-month selection marker was visible. I moved the optimistic main-grid date update to the existing second animation frame; the mini-month selection still updates immediately. This lets the changed date cell paint before the larger derived grid update and route navigation. Commit: ad426cce47f3386a412fca18fe917920882cb61f. `bun run check` and `bun run test -- --maxWorkers=2` now pass; I will measure this revision against origin/dev after the perf VM lock is available.
Author
Owner

Screenshot-profile findings for #1492 (captured on Linux Chromium with macOS platform emulation):

  • The first MiniMonth lookup could resolve a hidden duplicate on narrow layouts. The selection target then timed out in the visible sidebar locator. The profile now reads the target from the visible MiniMonth.
  • The original neighbor choice selected tomorrow, after the 84-day Event fixture ended. The captured Day/390 image showed an empty timeline. The profile now chooses the previous in-fixture day, checks the pointer click's :focus-visible state at the click event, waits for the route and list requests, and requires a visible Event row before saving a screenshot.
  • The route navigation remounts MiniMonth on some widths, so the profile checks focus state at the trusted pointer click instead of dereferencing the old element after navigation.

These are audit-profile fixes; app source remains the committed candidate. The strict seven-pair A/B run is active on the locked perf VM. Candidate commit: 7fd8b9ed651d3a3a1a38f8ec9f6519409cf80a36.

Screenshot-profile findings for #1492 (captured on Linux Chromium with macOS platform emulation): - The first MiniMonth lookup could resolve a hidden duplicate on narrow layouts. The selection target then timed out in the visible sidebar locator. The profile now reads the target from the visible MiniMonth. - The original neighbor choice selected tomorrow, after the 84-day Event fixture ended. The captured Day/390 image showed an empty timeline. The profile now chooses the previous in-fixture day, checks the pointer click's `:focus-visible` state at the click event, waits for the route and list requests, and requires a visible Event row before saving a screenshot. - The route navigation remounts MiniMonth on some widths, so the profile checks focus state at the trusted pointer click instead of dereferencing the old element after navigation. These are audit-profile fixes; app source remains the committed candidate. The strict seven-pair A/B run is active on the locked perf VM. Candidate commit: `7fd8b9ed651d3a3a1a38f8ec9f6519409cf80a36`.
Author
Owner

First post-change strict A/B result for #1492 (7 interleaved pairs per width, 84 Events + 84 Tasks; perf VM load before/after 4.29/2.29/3.06 and 3.94/2.67/3.10):

  • Day, 1440 px: baseline p50/p95 181.2/248.4 ms; candidate 224.0/407.9 ms. Candidate is slower at both percentiles.
  • Day, 390 px: baseline 93.6/170.1 ms; candidate 79.9/119.5 ms. p50 improved, but p95 is still above the 100 ms target.

The candidate is rejected by the strict profile. Several 1440 px candidate samples also started Calendar API reads before the selected marker became visible. Week and Month runs remain.

First post-change strict A/B result for #1492 (7 interleaved pairs per width, 84 Events + 84 Tasks; perf VM load before/after 4.29/2.29/3.06 and 3.94/2.67/3.10): - Day, 1440 px: baseline p50/p95 181.2/248.4 ms; candidate 224.0/407.9 ms. Candidate is slower at both percentiles. - Day, 390 px: baseline 93.6/170.1 ms; candidate 79.9/119.5 ms. p50 improved, but p95 is still above the 100 ms target. The candidate is rejected by the strict profile. Several 1440 px candidate samples also started Calendar API reads before the selected marker became visible. Week and Month runs remain.
Author
Owner

Week A/B result for #1492 (7 interleaved pairs per width; 84 Events + 84 Tasks):

  • 1440 px: baseline p50/p95 218.6/381.1 ms; candidate 298.1/547.2 ms. Candidate is slower, and 3/7 candidate samples started Calendar reads before the selected marker was visible.
  • 390 px: baseline 125.9/143.8 ms; candidate 105.4/125.6 ms. Both percentiles improved, but candidate p95 remains above the 100 ms target.

The remaining Month matrix is pending.

Week A/B result for #1492 (7 interleaved pairs per width; 84 Events + 84 Tasks): - 1440 px: baseline p50/p95 218.6/381.1 ms; candidate 298.1/547.2 ms. Candidate is slower, and 3/7 candidate samples started Calendar reads before the selected marker was visible. - 390 px: baseline 125.9/143.8 ms; candidate 105.4/125.6 ms. Both percentiles improved, but candidate p95 remains above the 100 ms target. The remaining Month matrix is pending.
Author
Owner

Complete initial strict A/B matrix for #1492 (7 interleaved pairs per cell; 84 Events + 84 Tasks; perf VM; candidate 7fd8b9ed651d3a3a1a38f8ec9f6519409cf80a36). Values are p50/p95 ms:

View Width origin/dev candidate
Day 1440 181.2 / 248.4 224.0 / 407.9
Day 390 93.6 / 170.1 79.9 / 119.5
Week 1440 218.6 / 381.1 298.1 / 547.2
Week 390 125.9 / 143.8 105.4 / 125.6
Month 1440 192.4 / 210.1 186.7 / 210.9
Month 390 70.7 / 88.6 62.5 / 78.9

The candidate fails the requested rule: desktop Day/Week p50 and p95 regress; Month/1440 p95 is 0.8 ms slower; Day/Week 390 p95 remain above 100 ms. Candidate Calendar reads began before marker visibility in 4/7 Day/1440, 3/7 Week/1440 and 1/7 Month/1440 samples. I am reverting the route deferral that caused the desktop regressions, keeping only the measured cache changes for a second comparison. The profile budget rule also treated unrequested Calendar/select Calendar Event as a failure; I will scope it to requested interactions.

Complete initial strict A/B matrix for #1492 (7 interleaved pairs per cell; 84 Events + 84 Tasks; perf VM; candidate `7fd8b9ed651d3a3a1a38f8ec9f6519409cf80a36`). Values are p50/p95 ms: | View | Width | origin/dev | candidate | | --- | ---: | ---: | ---: | | Day | 1440 | 181.2 / 248.4 | 224.0 / 407.9 | | Day | 390 | 93.6 / 170.1 | 79.9 / 119.5 | | Week | 1440 | 218.6 / 381.1 | 298.1 / 547.2 | | Week | 390 | 125.9 / 143.8 | 105.4 / 125.6 | | Month | 1440 | 192.4 / 210.1 | 186.7 / 210.9 | | Month | 390 | 70.7 / 88.6 | 62.5 / 78.9 | The candidate fails the requested rule: desktop Day/Week p50 and p95 regress; Month/1440 p95 is 0.8 ms slower; Day/Week 390 p95 remain above 100 ms. Candidate Calendar reads began before marker visibility in 4/7 Day/1440, 3/7 Week/1440 and 1/7 Month/1440 samples. I am reverting the route deferral that caused the desktop regressions, keeping only the measured cache changes for a second comparison. The profile budget rule also treated unrequested `Calendar/select Calendar Event` as a failure; I will scope it to requested interactions.
Author
Owner

Audit correction for #1492: review of the 390 px route showed that a MiniMonth click closes the phone sidebar, so the old visible probe could see a hidden selected cell. The 390 px timings above are preliminary and are superseded. The profile now measures the visible phone Calendar title for Day/Week, and selects the nearest adjacent month in Month view so that its phone title changes. Desktop continues to use the visible MiniMonth marker. The route deferral was removed after the first A/B matrix; the retained app candidate contains only the timezone and MonthGrid caches. I will rerun the corrected matrix when the perf VM lock is free.

Audit correction for #1492: review of the 390 px route showed that a MiniMonth click closes the phone sidebar, so the old visible probe could see a hidden selected cell. The 390 px timings above are preliminary and are superseded. The profile now measures the visible phone Calendar title for Day/Week, and selects the nearest adjacent month in Month view so that its phone title changes. Desktop continues to use the visible MiniMonth marker. The route deferral was removed after the first A/B matrix; the retained app candidate contains only the timezone and MonthGrid caches. I will rerun the corrected matrix when the perf VM lock is free.
Author
Owner

#1492 result

Head: ca0ae707d7fcd9196405a950182dbd1a7850a186 (Record Calendar selection profile and reject slower caches). No push, merge, or deploy.

I extended bench/interaction-audit-1392.mjs with a strict seven-pair, interleaved Calendar-only profile, source-map/layout diagnostics, macOS platform emulation, and selected-state screenshots. The profile is filtered to requested Calendar actions, checks pointer focus state, dismisses the build notice, and requires a visible real Event before capture. docs/perf/baseline.json records the source-map findings, origin/dev baseline, rejected-candidate results, and profile CPU/RSS.

Trace and layout findings

The production trace covers ten Day, ten Week, and ten Month selections at 1440 px. scheduleGridWindowRead() accounts for 150.9 ms of aggregate FunctionCall time; Svelte keyed-each reconciliation accounts for 913.1 ms inclusive CPU. The audit found zero geometry, computed-style, or CSS-property reads before selection became visible. TimeGrid.measure() reads --gutter and --hit only on resize. It found no pill-feedback getPropertyValue() or SegmentedControl FLIP work on selection.

Seven-pair A/B (p50/p95 ms)

View Width origin/dev Candidate Result
Day 390 68.7 / 77.2 68.1 / 88.2 Reject
Day 1440 207.4 / 315.9 212.3 / 270.3 Reject
Week 390 80.4 / 104.4 78.4 / 97.3 Accept
Week 1440 175.5 / 231.5 204.8 / 317.4 Reject
Month 390 96.1 / 108.1 96.8 / 153.4 Reject
Month 1440 127.4 / 202.1 133.3 / 167.9 Reject

I reverted the time-zone and Month row-cache changes because the candidate failed the p50/p95 retention rule in five cases. The one passing Week/390 case is not enough to keep a shared runtime change. Calendar selection still exceeds the 100 ms p95 target on desktop. Some desktop candidate samples also started Calendar reads before the selected marker became visible; this needs follow-up against the #1491 cache-first behavior.

Screenshots

Six Day screenshots were captured in Chromium with macOS platform emulation. Each shows real Events; the click probe found no focus-visible ring. The Week/Month phone capture route did not produce a visible Event row, so those screenshots are not attached.

Gates

bun run check — exit code 0:

perf-lint: PASS; 0 violations; 22247 scoped exceptions
svelte-check found 0 errors and 3 warnings in 1 file

bun run test -- --maxWorkers=2 — exit code 0:

 Test Files  310 passed (310)
      Tests  2273 passed (2273)
   Start at  14:55:19
   Duration  201.67s (environment 29%, transform 24%, import 21%, tests 21%, setup 5%)

node --check bench/interaction-audit-1392.mjs and git diff --check passed. No Rust code changed.

UX gaps

Closed: Day pointer-selected state is captured at 390, 820, and 1440 px in light and dark; the harness verifies no pointer focus ring, no update notice, and a visible Event.

Left: Day/Week desktop selection remains above the 100 ms p95 target. The Week/Month phone screenshot matrix needs a fixture date range that makes real Events visible in the selected route. No runtime UI optimization is retained.

Decisions not covered by DESIGN

I applied the requested strict rule to the full view/viewport matrix: any p50 regression or p95 regression rejects the shared candidate, even when another percentile or viewport improves. On phone Week, the range title can stay unchanged when the anchor date changes within the same week; the harness uses the changed route anchor as selection evidence. No API, visual, or interaction behavior was changed.

## #1492 result Head: `ca0ae707d7fcd9196405a950182dbd1a7850a186` (`Record Calendar selection profile and reject slower caches`). No push, merge, or deploy. I extended `bench/interaction-audit-1392.mjs` with a strict seven-pair, interleaved Calendar-only profile, source-map/layout diagnostics, macOS platform emulation, and selected-state screenshots. The profile is filtered to requested Calendar actions, checks pointer focus state, dismisses the build notice, and requires a visible real Event before capture. `docs/perf/baseline.json` records the source-map findings, origin/dev baseline, rejected-candidate results, and profile CPU/RSS. ## Trace and layout findings The production trace covers ten Day, ten Week, and ten Month selections at 1440 px. `scheduleGridWindowRead()` accounts for 150.9 ms of aggregate FunctionCall time; Svelte keyed-each reconciliation accounts for 913.1 ms inclusive CPU. The audit found zero geometry, computed-style, or CSS-property reads before selection became visible. `TimeGrid.measure()` reads `--gutter` and `--hit` only on resize. It found no pill-feedback `getPropertyValue()` or `SegmentedControl` FLIP work on selection. ## Seven-pair A/B (p50/p95 ms) | View | Width | origin/dev | Candidate | Result | |---|---:|---:|---:|---| | Day | 390 | 68.7 / 77.2 | 68.1 / 88.2 | Reject | | Day | 1440 | 207.4 / 315.9 | 212.3 / 270.3 | Reject | | Week | 390 | 80.4 / 104.4 | 78.4 / 97.3 | Accept | | Week | 1440 | 175.5 / 231.5 | 204.8 / 317.4 | Reject | | Month | 390 | 96.1 / 108.1 | 96.8 / 153.4 | Reject | | Month | 1440 | 127.4 / 202.1 | 133.3 / 167.9 | Reject | I reverted the time-zone and Month row-cache changes because the candidate failed the p50/p95 retention rule in five cases. The one passing Week/390 case is not enough to keep a shared runtime change. Calendar selection still exceeds the 100 ms p95 target on desktop. Some desktop candidate samples also started Calendar reads before the selected marker became visible; this needs follow-up against the #1491 cache-first behavior. ## Screenshots Six Day screenshots were captured in Chromium with macOS platform emulation. Each shows real Events; the click probe found no focus-visible ring. The Week/Month phone capture route did not produce a visible Event row, so those screenshots are not attached. - [Day, phone, light](https://git.kayg.org/attachments/4c9db9f0-ce72-4888-bf79-c9bef7e8e318) - [Day, phone, dark](https://git.kayg.org/attachments/d2994515-a8d9-4290-acc9-e6d14a7ddbe3) - [Day, tablet, light](https://git.kayg.org/attachments/b0a9f783-4d33-40bd-8eab-354d95d3c264) - [Day, tablet, dark](https://git.kayg.org/attachments/de26b65c-e0ad-4bb9-abb7-015d3c264abb) - [Day, desktop, light](https://git.kayg.org/attachments/d639b125-a3c3-49f1-a1d6-9d48af00d89c) - [Day, desktop, dark](https://git.kayg.org/attachments/022117fb-1642-48ee-bb44-c853aeea8b83) ## Gates `bun run check` — exit code 0: ```text perf-lint: PASS; 0 violations; 22247 scoped exceptions svelte-check found 0 errors and 3 warnings in 1 file ``` `bun run test -- --maxWorkers=2` — exit code 0: ```text Test Files 310 passed (310) Tests 2273 passed (2273) Start at 14:55:19 Duration 201.67s (environment 29%, transform 24%, import 21%, tests 21%, setup 5%) ``` `node --check bench/interaction-audit-1392.mjs` and `git diff --check` passed. No Rust code changed. ## UX gaps Closed: Day pointer-selected state is captured at 390, 820, and 1440 px in light and dark; the harness verifies no pointer focus ring, no update notice, and a visible Event. Left: Day/Week desktop selection remains above the 100 ms p95 target. The Week/Month phone screenshot matrix needs a fixture date range that makes real Events visible in the selected route. No runtime UI optimization is retained. ## Decisions not covered by DESIGN I applied the requested strict rule to the full view/viewport matrix: any p50 regression or p95 regression rejects the shared candidate, even when another percentile or viewport improves. On phone Week, the range title can stay unchanged when the anchor date changes within the same week; the harness uses the changed route anchor as selection evidence. No API, visual, or interaction behavior was changed.
Author
Owner

Correction to the previous report: the Day tablet/light attachment is https://git.kayg.org/attachments/b0a9f783-4d33-40bd-8eab-d7a8ad354d95.

Correction to the previous report: the Day tablet/light attachment is https://git.kayg.org/attachments/b0a9f783-4d33-40bd-8eab-d7a8ad354d95.
Author
Owner

Orchestrator: candidate rejected (p50/p95 retention failed in 5 of 6 view/width cases). Only the strict audit harness and its baseline (ca0ae707d) go into the next merge round. Desktop selection is still over the 100 ms p95 target; the trace points at Svelte keyed-each reconciliation (913 ms inclusive) and scheduleGridWindowRead. Issue stays open.

Orchestrator: candidate rejected (p50/p95 retention failed in 5 of 6 view/width cases). Only the strict audit harness and its baseline (ca0ae707d) go into the next merge round. Desktop selection is still over the 100 ms p95 target; the trace points at Svelte keyed-each reconciliation (913 ms inclusive) and scheduleGridWindowRead. Issue stays open.
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#1492
No description provided.