PERF: Week view horizontal scrolling is laggy with real-size data (7k entries) #1018

Open
opened 2026-10-03 15:36:32 +00:00 by kayg · 19 comments
Owner

Owner report (2026-10-03, production with #724: 7,207 Log entries over 503 days)

"With so many entries, horizontal scrolling in the week view of the calendar is very laggy!"

Week view scrolls horizontally through days; with real-size data (up to ~30 entries per day, tags, attachment counts) it janks. Owner rule: performance first, instant everywhere (#663 rules, §59 on 7b), measured on real-shaped data.

Tasks

  1. Reproduce with a generated fixture shaped like the owner's data: 650 days, 7,200 Log entries (2–30 per day, overlapping clusters, tags, some attachments) on a production build. Record a Performance trace of continuous horizontal scrolling (trackpad-like wheel deltas and touch fling) at 1440 and 820: frame times, long tasks, layout/style recalc counts, GC, and which code runs per frame (cite file:line).
  2. Fix the causes, likely candidates: rendering more day columns than visible (virtualise columns with a small overscan), per-frame layout reads (getBoundingClientRect/offsetWidth in scroll handlers), lane packing recomputed on scroll instead of once per day and cached, reactive state updates per scroll event, heavy per-card DOM (tooltips, deck markup) mounted off-screen, non-composited animations, fetching per scroll tick instead of by range with a cache.
  3. Targets: p95 frame time ≤ 16.7 ms and no long task > 50 ms during a 5 s fling at 1440 on the build VM's Chrome with 4x CPU throttle off; memory stable while scrolling across 2 years.
  4. Bench profile in bench/ (week-scroll with the fixture) + baseline in docs/perf/; e2e that scrolls 60 days and asserts frame budget roughly (non-flaky thresholds).
    Report before/after numbers and the trace findings.
## Owner report (2026-10-03, production with #724: 7,207 Log entries over 503 days) "With so many entries, horizontal scrolling in the week view of the calendar is very laggy!" Week view scrolls horizontally through days; with real-size data (up to ~30 entries per day, tags, attachment counts) it janks. Owner rule: performance first, instant everywhere (#663 rules, §59 on 7b), measured on real-shaped data. ## Tasks 1. Reproduce with a generated fixture shaped like the owner's data: 650 days, 7,200 Log entries (2–30 per day, overlapping clusters, tags, some attachments) on a production build. Record a Performance trace of continuous horizontal scrolling (trackpad-like wheel deltas and touch fling) at 1440 and 820: frame times, long tasks, layout/style recalc counts, GC, and which code runs per frame (cite file:line). 2. Fix the causes, likely candidates: rendering more day columns than visible (virtualise columns with a small overscan), per-frame layout reads (getBoundingClientRect/offsetWidth in scroll handlers), lane packing recomputed on scroll instead of once per day and cached, reactive state updates per scroll event, heavy per-card DOM (tooltips, deck markup) mounted off-screen, non-composited animations, fetching per scroll tick instead of by range with a cache. 3. Targets: p95 frame time ≤ 16.7 ms and no long task > 50 ms during a 5 s fling at 1440 on the build VM's Chrome with 4x CPU throttle off; memory stable while scrolling across 2 years. 4. Bench profile in bench/ (week-scroll with the fixture) + baseline in docs/perf/; e2e that scrolls 60 days and asserts frame budget roughly (non-flaky thresholds). Report before/after numbers and the trace findings.
Author
Owner

Started #1018 on job/weekscroll-1018 at bd11bacb51 (origin/dev base). Reproduce on a production SPA with 650 days and 7,200 Log entries; use the same deterministic fixture for before and after. No new dependencies planned. Shared prebuilt server CURRENT is absent; build a local server.

Started #1018 on job/weekscroll-1018 at bd11bacb5189d39176e7cd48d5e977f1694321c1 (origin/dev base). Reproduce on a production SPA with 650 days and 7,200 Log entries; use the same deterministic fixture for before and after. No new dependencies planned. Shared prebuilt server CURRENT is absent; build a local server.
Author
Owner

Owner detail (2026-10-03): 'Empty places in the calendar are decent to scroll but when there are events, it hogs down.' So the cost scales with rendered Event/Log cards, not with the scroll container itself: profile per-card cost first (mount/update work, layout reads, style recalc, filters/backdrop blur/shadows on cards, per-card reactive effects, tooltips/hover listeners, deck markup) and whether cards re-render or re-layout on every scroll frame. Compare a dense week vs an empty week in the same trace.

Owner detail (2026-10-03): 'Empty places in the calendar are decent to scroll but when there are events, it hogs down.' So the cost scales with rendered Event/Log cards, not with the scroll container itself: profile per-card cost first (mount/update work, layout reads, style recalc, filters/backdrop blur/shadows on cards, per-card reactive effects, tooltips/hover listeners, deck markup) and whether cards re-render or re-layout on every scroll frame. Compare a dense week vs an empty week in the same trace.
Author
Owner

Reproduction profile committed in 116d7588e and 46d8d6553. A server built from the job base is seeding the deterministic 650-day / 7,200-Log fixture through tus and Notes reconcile. An older prebuilt server failed fixture setup with 500 upload state failed after explicit 412 conflicts; the base-built server has passed that point. This setup failure is separate from the Week scroll path.

Source finding: TimeGrid renders 21 Week columns and declares 2,001 CSS grid columns for each header/body track, plus the outer grid. Prepared a bounded painted window (11 columns, local indices), retaining the original native scroll extent and week-aligned data prefetch. Before traces still use the unchanged production build. bun run check reports svelte-check found 0 errors and 0 warnings; existing focused tests report Test Files 2 passed (2) and Tests 24 passed (24).

Reproduction profile committed in 116d7588e and 46d8d6553. A server built from the job base is seeding the deterministic 650-day / 7,200-Log fixture through tus and Notes reconcile. An older prebuilt server failed fixture setup with `500 upload state failed` after explicit 412 conflicts; the base-built server has passed that point. This setup failure is separate from the Week scroll path. Source finding: TimeGrid renders 21 Week columns and declares 2,001 CSS grid columns for each header/body track, plus the outer grid. Prepared a bounded painted window (11 columns, local indices), retaining the original native scroll extent and week-aligned data prefetch. Before traces still use the unchanged production build. `bun run check` reports `svelte-check found 0 errors and 0 warnings`; existing focused tests report `Test Files 2 passed (2)` and `Tests 24 passed (24)`.
Author
Owner

Reproduction profile committed in 116d7588e and 46d8d6553. A server built from the job base is seeding the deterministic 650-day / 7,200-Log fixture through tus and Notes reconcile. An older prebuilt server failed fixture setup with 500 upload state failed after explicit 412 conflicts; the base-built server has passed that point. This setup failure is separate from the Week scroll path.

Source finding: TimeGrid renders 21 Week columns and declares 2,001 CSS grid columns for each header/body track, plus the outer grid. Prepared a bounded painted window (11 columns, local indices), retaining the original native scroll extent and week-aligned data prefetch. Before traces still use the unchanged production build. bun run check reports svelte-check found 0 errors and 0 warnings; existing focused tests report Test Files 2 passed (2) and Tests 24 passed (24).

Reproduction profile committed in 116d7588e and 46d8d6553. A server built from the job base is seeding the deterministic 650-day / 7,200-Log fixture through tus and Notes reconcile. An older prebuilt server failed fixture setup with `500 upload state failed` after explicit 412 conflicts; the base-built server has passed that point. This setup failure is separate from the Week scroll path. Source finding: TimeGrid renders 21 Week columns and declares 2,001 CSS grid columns for each header/body track, plus the outer grid. Prepared a bounded painted window (11 columns, local indices), retaining the original native scroll extent and week-aligned data prefetch. Before traces still use the unchanged production build. `bun run check` reports `svelte-check found 0 errors and 0 warnings`; existing focused tests report `Test Files 2 passed (2)` and `Tests 24 passed (24)`.
Author
Owner

A valid continuous native mouse/wheel gesture crossed 10.002 days on the unchanged production build at 1440. Its trace recorded p95 rAF frame time 333.3 ms, 15 long tasks (maximum 229 ms), 115 layout passes (424.9 ms total; maximum 33.6 ms), 157 style recalculations (223.8 ms total), and 21 mounted columns. CPU throttle was off on the shared build VM. This reproduces the reported lag.

The separate-packet wheel experiment moved zero days because each packet could settle and snap; it is excluded. The touch gesture currently moves zero days and dispatches a drag sequence; the probe now records pointer types and touch policy to identify this setup problem before accepting timings. Both production builds will use one running server and the same retained 650-day / 7,200-entry fixture, with valid stable block IDs and attachment metadata verified through the real API.

A valid continuous native mouse/wheel gesture crossed 10.002 days on the unchanged production build at 1440. Its trace recorded p95 rAF frame time 333.3 ms, 15 long tasks (maximum 229 ms), 115 layout passes (424.9 ms total; maximum 33.6 ms), 157 style recalculations (223.8 ms total), and 21 mounted columns. CPU throttle was off on the shared build VM. This reproduces the reported lag. The separate-packet wheel experiment moved zero days because each packet could settle and snap; it is excluded. The touch gesture currently moves zero days and dispatches a drag sequence; the probe now records pointer types and touch policy to identify this setup problem before accepting timings. Both production builds will use one running server and the same retained 650-day / 7,200-entry fixture, with valid stable block IDs and attachment metadata verified through the real API.
Author
Owner

The bounded-grid comparison completed on the same retained fixture (Chrome 153, CPU throttle off, build-VM load 43–47 before, recorded loads included in results). Mounted columns fell from 21 to 11 and desktop DOM nodes from 2,244 to 1,414. The 60-day burst layout time fell from 681.5 to 531.7 ms, but p95 rAF frame time remained 716.6 ms; the 16.7 ms target is not met.

Sampled CPU stacks identify a second cost: Svelte list animation apply/measure/fix calls read getBoundingClientRect while Calendar sidebar view href keys change with the visible date. Calendar view rows now have stable view IDs and a stable array; date destinations and aria-current update in place. The focused test confirms that a changed destination preserves the row, its link, and keyboard focus. This needs a new measured pass because it changes the identified hot path.

The bounded-grid comparison completed on the same retained fixture (Chrome 153, CPU throttle off, build-VM load 43–47 before, recorded loads included in results). Mounted columns fell from 21 to 11 and desktop DOM nodes from 2,244 to 1,414. The 60-day burst layout time fell from 681.5 to 531.7 ms, but p95 rAF frame time remained 716.6 ms; the 16.7 ms target is not met. Sampled CPU stacks identify a second cost: Svelte list animation apply/measure/fix calls read getBoundingClientRect while Calendar sidebar view href keys change with the visible date. Calendar view rows now have stable view IDs and a stable array; date destinations and aria-current update in place. The focused test confirms that a changed destination preserves the row, its link, and keyboard focus. This needs a new measured pass because it changes the identified hot path.
Author
Owner

Job handoff: weekscroll-1018. The performance target is not met. Keep #1018 open. This is a tested partial improvement with measured remaining work, at the four-hour job limit.

Branch: job/weekscroll-1018. Base: bd11bacb5189d39176e7cd48d5e977f1694321c1 (origin/dev). Head: 21df908086afe2a1cb094a30850d5df4c8177253. Final application measurement: f1f9ea9fe; later commits fix screenshot capture and add the report. git fetch origin && git merge origin/dev ran once before final gates and returned Already up to date. No push, deploy or repository merge was made.

Built

  • Week renders 11 date columns instead of 21, with two buffer days per side. The native spacer still spans 2,001 days. Empty dates create no CSS grid tracks.
  • Retained date columns keep fixed absolute positions. Chrome's native x scroll timeline aligns the header and body while the main thread mounts entering dates. Other browsers use the existing shared animation-frame offsets.
  • Calendar sidebar destinations update in place. Stable view IDs preserve rows and focus, and avoid Svelte list-animation rectangle reads for each date change.
  • The shared ModeHeader skips geometry work when a known inner scroller changes only its horizontal offset.
  • Added a real API profile with 650 Daily notes, 7,200 Log entries, 2–30 entries per day, overlaps, Tags and API-uploaded attachments. Added fixture and focused regression tests, before/after results and a baseline profile entry.

Files

apps/web/e2e/week-scroll-1018.mjs
apps/web/src/lib/calendar/TimeGrid.svelte.test.ts
apps/web/src/lib/components/SidebarLinks.svelte
apps/web/src/lib/components/SidebarLinks.svelte.test.ts
apps/web/src/lib/components/app-sidebar.svelte
apps/web/src/lib/modeHeader.svelte.test.ts
bench/week-scroll-1018.mjs
bench/week-scroll-1018.test.mjs
docs/perf/baseline.json
docs/perf/week-scroll-1018.json
docs/perf/week-scroll-1018.md
packages/ui/src/components/ModeHeader.svelte
packages/ui/src/components/calendar/GridColumn.svelte
packages/ui/src/components/calendar/TimeGrid.svelte

Before and after

Both SPAs use the same real fixture, Home and server binary. Canonical Log lines were checked again after measurement. Fixture SHA: 2a21af28cbe71ec36beb11e17496c2c5f3a9a8216a66712f32a139482cc85ac2.

Chrome 153.0.8010.12, CPU throttle off. Perf VM sessions held /root/perf.lock; load was recorded inside the lock (before 0.08, after 0.00). No compilation ran there. The real API was forwarded from the build VM.

Locked perf VM Frame p95 before → after Layout passes before → after Renderer task CPU before → after
1440 wheel, 10 days 216.6 → 183.4 ms 117 → 24 1.446 → 0.931 s
1440 touch 133.3 → 116.6 ms 70 → 16 0.928 → 0.697 s
820 wheel, 10 days 83.3 → 83.4 ms 117 → 24 0.928 → 0.623 s
820 touch 66.7 → 66.7 ms 50 → 13 0.520 → 0.465 s
1440 wheel, 60 days 200.0 → 150.1 ms 473 → 128 3.024 → 2.281 s

The 60-day result reduces renderer task CPU by 24.6% and layout passes by 72.9%. Paint duration falls 210.2 → 155.7 ms. Summed raster thread wall duration rises 1,135.5 → 1,467.9 ms (+29.3%); #1026 tracks this finding. Raster durations overlap across threads and are not CPU durations. This is one measured pair.

Final 10-day perf VM runs have no >50 ms long task. The 60-day run has a 76 ms long task. All p95 frame results exceed 16.7 ms. The focused coarse regression fails its 50 ms p95 bound. This failure is retained.

Browser RSS after the 60-day run: 893.1 → 815.6 MiB. GC heap during the final 650-day traversal: 9.88 → 11.26 MB, with 11 mounted columns. Before: 12.13 → 12.66 MB. DOM remains bounded; 1440 desktop 10-day node count falls 2,244 → 1,414.

Build VM results are also recorded. Final 1440 wheel p95 is 166.7 ms with a 108 ms long task; final 60-day p95 is 166.6 ms. Before host load was 43.01 and after load was 4.57. Do not use the elapsed-time change on that pair as an isolated code result.

Gates (verbatim)

cargo fmt --check: exit 0, no output. Rust code and API contracts were not changed; per-crate Rust clippy/test are not applicable.

bun run check:

$ node scripts/check-user-storage.mjs && node scripts/check-type-tokens.mjs && node scripts/check-motion-tokens.mjs && svelte-kit sync && svelte-check --tsconfig ./tsconfig.json
User browser caches use userStorage; only documented device/public-link exceptions remain.
Text sizes and UI shape values use shared role tokens.
UI transitions and animation options use shared motion tokens or documented exceptions.
Loading svelte-check in workspace: /home/kayg/Developer/calternal-wt/weekscroll-1018/apps/web
Getting Svelte diagnostics...

svelte-check found 0 errors and 0 warnings

bunx vitest run src/lib/calendar/TimeGrid.svelte.test.ts src/lib/calendar/grid.test.ts src/lib/modeHeader.svelte.test.ts src/lib/components/SidebarLinks.svelte.test.ts --maxWorkers=2:

 Test Files  4 passed (4)
      Tests  42 passed (42)

node --test bench/week-scroll-1018.test.mjs:

# tests 1
# suites 0
# pass 1
# fail 0
# cancelled 0
# skipped 0
# todo 0

bun apps/web/e2e/week-scroll-1018.mjs --results artifacts/weekscroll-1018/perf-final/results.json: exit 1.

AssertionError: 60-day busy-host frame budget

Production web build passed. No existing test expectations were changed. Full gate logs are attached. Comments in touched modules and functions were read again. Build cleanup:

Removed 7238 files, 4.6GiB total

Web build output, detached baseline worktree, private fixture/session and the dedicated remote browser profile were removed. The working tree is clean.

UX gaps closed

  • Calendar sidebar focus no longer disappears when date-bearing destinations change.
  • Retained dates keep their DOM nodes and positions as a day enters the window.
  • Header and body track alignment is exact in the measured native-input runs, keyboard date navigation and reduced motion. ArrowRight settles the expected date URL with both motion settings.
  • Fixed the screenshot method: Playwright disabling animations finishes native scroll timelines at the far edge. Review images now keep them active and show the real fixture. No screenshot changes the application.

UX gaps left / known gaps

  • The frame target and focused 60-day performance assertion remain unresolved.
  • Safari native timeline behavior, the unsupported-browser fallback and actual Apple-client fling momentum need merge-round checks. The touch profile sends a fast swipe and release; frame samples include the remaining idle frames and scheduler stalls.
  • Full existing action, Undo, context-menu, Copy link, loading/error/offline and accessibility suites were deferred under the latest verification policy. Their completeness is not claimed here.
  • Claude must review the attached production screenshots. Week and Day are captured at 390, 820 and 1440 in Paper and Tokyo Night with the Mac platform enabled. No new icon/text alignment was introduced.

Decisions

  • Two buffer days per side, independent of existing week-sized data prefetch, is the smallest shared overscan that covers partial columns and retains adjacent keyboard targets.
  • Use fixed absolute date positions inside native-width anchors. A zero-width experiment caused Chrome to cull the children; it was removed and its measurements are excluded.
  • Feature-detect native scroll timelines once. Keep the existing frame callback as a fallback. The timeline represents scrollbar position and remains linear with reduced motion; navigation uses the shared motion durations.
  • Give Calendar view rows semantic IDs while preserving href keys for callers that do not supply an ID. Keep the Calendar view array stable to avoid unnecessary list FLIP work.
  • Add no dependency and change no server behavior. Existing locked packages were used.

For the merge round

Run on the combined branch with a production build and its server:

  • cd apps/web && bun run test --maxWorkers=2: full web regressions.
  • cd apps/web && bun run test:e2e:calendar && bun run test:e2e:weekstate-609: primary actions, native scroll settlement, resize, URL restoration and keyboard behavior.
  • cd apps/web && bun run test:e2e:calendar-crossday && bun run test:e2e:calendar-task-overflow && bun run test:e2e:calendar-doc-stack: retained columns, cross-day identities, narrow overflow actions and attachment decks.
  • cd apps/web && bun run test:e2e:a11y && bun run test:e2e:deeplinks: accessible names/states/focus and stable item links.
  • CALTERNAL_E2E_ASSET_OVERRIDE=1 CALTERNAL_SERVER_BIN=<combined-server> bun apps/web/e2e/week-scroll-1018.mjs --out artifacts/weekscroll-1018/merge-round: focused production 60-day budget after the remaining performance work. It is expected to fail on this head.

Check Safari on the locked Mac VM and the fallback in a browser without scroll timelines. Performance measurements must hold /root/perf.lock on the perf VM. No API endpoint was added, so no endpoint-specific adversarial probe was needed in this job.

Evidence

Job handoff: weekscroll-1018. **The performance target is not met. Keep #1018 open.** This is a tested partial improvement with measured remaining work, at the four-hour job limit. Branch: `job/weekscroll-1018`. Base: `bd11bacb5189d39176e7cd48d5e977f1694321c1` (origin/dev). Head: `21df908086afe2a1cb094a30850d5df4c8177253`. Final application measurement: `f1f9ea9fe`; later commits fix screenshot capture and add the report. `git fetch origin && git merge origin/dev` ran once before final gates and returned `Already up to date.` No push, deploy or repository merge was made. ### Built - Week renders 11 date columns instead of 21, with two buffer days per side. The native spacer still spans 2,001 days. Empty dates create no CSS grid tracks. - Retained date columns keep fixed absolute positions. Chrome's native x scroll timeline aligns the header and body while the main thread mounts entering dates. Other browsers use the existing shared animation-frame offsets. - Calendar sidebar destinations update in place. Stable view IDs preserve rows and focus, and avoid Svelte list-animation rectangle reads for each date change. - The shared ModeHeader skips geometry work when a known inner scroller changes only its horizontal offset. - Added a real API profile with 650 Daily notes, 7,200 Log entries, 2–30 entries per day, overlaps, Tags and API-uploaded attachments. Added fixture and focused regression tests, before/after results and a baseline profile entry. ### Files ```text apps/web/e2e/week-scroll-1018.mjs apps/web/src/lib/calendar/TimeGrid.svelte.test.ts apps/web/src/lib/components/SidebarLinks.svelte apps/web/src/lib/components/SidebarLinks.svelte.test.ts apps/web/src/lib/components/app-sidebar.svelte apps/web/src/lib/modeHeader.svelte.test.ts bench/week-scroll-1018.mjs bench/week-scroll-1018.test.mjs docs/perf/baseline.json docs/perf/week-scroll-1018.json docs/perf/week-scroll-1018.md packages/ui/src/components/ModeHeader.svelte packages/ui/src/components/calendar/GridColumn.svelte packages/ui/src/components/calendar/TimeGrid.svelte ``` ### Before and after Both SPAs use the same real fixture, Home and server binary. Canonical Log lines were checked again after measurement. Fixture SHA: `2a21af28cbe71ec36beb11e17496c2c5f3a9a8216a66712f32a139482cc85ac2`. Chrome 153.0.8010.12, CPU throttle off. Perf VM sessions held `/root/perf.lock`; load was recorded inside the lock (before 0.08, after 0.00). No compilation ran there. The real API was forwarded from the build VM. | Locked perf VM | Frame p95 before → after | Layout passes before → after | Renderer task CPU before → after | | --- | --- | --- | --- | | 1440 wheel, 10 days | 216.6 → 183.4 ms | 117 → 24 | 1.446 → 0.931 s | | 1440 touch | 133.3 → 116.6 ms | 70 → 16 | 0.928 → 0.697 s | | 820 wheel, 10 days | 83.3 → 83.4 ms | 117 → 24 | 0.928 → 0.623 s | | 820 touch | 66.7 → 66.7 ms | 50 → 13 | 0.520 → 0.465 s | | 1440 wheel, 60 days | 200.0 → 150.1 ms | 473 → 128 | 3.024 → 2.281 s | The 60-day result reduces renderer task CPU by 24.6% and layout passes by 72.9%. Paint duration falls 210.2 → 155.7 ms. Summed raster thread wall duration rises 1,135.5 → 1,467.9 ms (+29.3%); [#1026](https://git.kayg.org/kayg/calternal/issues/1026) tracks this finding. Raster durations overlap across threads and are not CPU durations. This is one measured pair. Final 10-day perf VM runs have no >50 ms long task. The 60-day run has a 76 ms long task. All p95 frame results exceed 16.7 ms. The focused coarse regression fails its 50 ms p95 bound. This failure is retained. Browser RSS after the 60-day run: 893.1 → 815.6 MiB. GC heap during the final 650-day traversal: 9.88 → 11.26 MB, with 11 mounted columns. Before: 12.13 → 12.66 MB. DOM remains bounded; 1440 desktop 10-day node count falls 2,244 → 1,414. Build VM results are also recorded. Final 1440 wheel p95 is 166.7 ms with a 108 ms long task; final 60-day p95 is 166.6 ms. Before host load was 43.01 and after load was 4.57. Do not use the elapsed-time change on that pair as an isolated code result. ### Gates (verbatim) `cargo fmt --check`: exit 0, no output. Rust code and API contracts were not changed; per-crate Rust clippy/test are not applicable. `bun run check`: ```text $ node scripts/check-user-storage.mjs && node scripts/check-type-tokens.mjs && node scripts/check-motion-tokens.mjs && svelte-kit sync && svelte-check --tsconfig ./tsconfig.json User browser caches use userStorage; only documented device/public-link exceptions remain. Text sizes and UI shape values use shared role tokens. UI transitions and animation options use shared motion tokens or documented exceptions. Loading svelte-check in workspace: /home/kayg/Developer/calternal-wt/weekscroll-1018/apps/web Getting Svelte diagnostics... svelte-check found 0 errors and 0 warnings ``` `bunx vitest run src/lib/calendar/TimeGrid.svelte.test.ts src/lib/calendar/grid.test.ts src/lib/modeHeader.svelte.test.ts src/lib/components/SidebarLinks.svelte.test.ts --maxWorkers=2`: ```text Test Files 4 passed (4) Tests 42 passed (42) ``` `node --test bench/week-scroll-1018.test.mjs`: ```text # tests 1 # suites 0 # pass 1 # fail 0 # cancelled 0 # skipped 0 # todo 0 ``` `bun apps/web/e2e/week-scroll-1018.mjs --results artifacts/weekscroll-1018/perf-final/results.json`: exit 1. ```text AssertionError: 60-day busy-host frame budget ``` Production web build passed. No existing test expectations were changed. Full gate logs are attached. Comments in touched modules and functions were read again. Build cleanup: ```text Removed 7238 files, 4.6GiB total ``` Web build output, detached baseline worktree, private fixture/session and the dedicated remote browser profile were removed. The working tree is clean. ### UX gaps closed - Calendar sidebar focus no longer disappears when date-bearing destinations change. - Retained dates keep their DOM nodes and positions as a day enters the window. - Header and body track alignment is exact in the measured native-input runs, keyboard date navigation and reduced motion. ArrowRight settles the expected date URL with both motion settings. - Fixed the screenshot method: Playwright disabling animations finishes native scroll timelines at the far edge. Review images now keep them active and show the real fixture. No screenshot changes the application. ### UX gaps left / known gaps - The frame target and focused 60-day performance assertion remain unresolved. - Safari native timeline behavior, the unsupported-browser fallback and actual Apple-client fling momentum need merge-round checks. The touch profile sends a fast swipe and release; frame samples include the remaining idle frames and scheduler stalls. - Full existing action, Undo, context-menu, Copy link, loading/error/offline and accessibility suites were deferred under the latest verification policy. Their completeness is not claimed here. - Claude must review the attached production screenshots. Week and Day are captured at 390, 820 and 1440 in Paper and Tokyo Night with the Mac platform enabled. No new icon/text alignment was introduced. ### Decisions - Two buffer days per side, independent of existing week-sized data prefetch, is the smallest shared overscan that covers partial columns and retains adjacent keyboard targets. - Use fixed absolute date positions inside native-width anchors. A zero-width experiment caused Chrome to cull the children; it was removed and its measurements are excluded. - Feature-detect native scroll timelines once. Keep the existing frame callback as a fallback. The timeline represents scrollbar position and remains linear with reduced motion; navigation uses the shared motion durations. - Give Calendar view rows semantic IDs while preserving href keys for callers that do not supply an ID. Keep the Calendar view array stable to avoid unnecessary list FLIP work. - Add no dependency and change no server behavior. Existing locked packages were used. ### For the merge round Run on the combined branch with a production build and its server: - `cd apps/web && bun run test --maxWorkers=2`: full web regressions. - `cd apps/web && bun run test:e2e:calendar && bun run test:e2e:weekstate-609`: primary actions, native scroll settlement, resize, URL restoration and keyboard behavior. - `cd apps/web && bun run test:e2e:calendar-crossday && bun run test:e2e:calendar-task-overflow && bun run test:e2e:calendar-doc-stack`: retained columns, cross-day identities, narrow overflow actions and attachment decks. - `cd apps/web && bun run test:e2e:a11y && bun run test:e2e:deeplinks`: accessible names/states/focus and stable item links. - `CALTERNAL_E2E_ASSET_OVERRIDE=1 CALTERNAL_SERVER_BIN=<combined-server> bun apps/web/e2e/week-scroll-1018.mjs --out artifacts/weekscroll-1018/merge-round`: focused production 60-day budget after the remaining performance work. It is expected to fail on this head. Check Safari on the locked Mac VM and the fallback in a browser without scroll timelines. Performance measurements must hold `/root/perf.lock` on the perf VM. No API endpoint was added, so no endpoint-specific adversarial probe was needed in this job. ### Evidence - [day-1440-paper.png](https://git.kayg.org/attachments/5a90d20e-b8fa-4633-a4d3-b61c388bc175) - [day-1440-tokyo-night.png](https://git.kayg.org/attachments/c523b488-012f-4b3d-9b6e-a28c0aebabe2) - [day-390-paper.png](https://git.kayg.org/attachments/db66365d-9bc0-47d7-8b0a-2c6d5fba40c7) - [day-390-tokyo-night.png](https://git.kayg.org/attachments/aa370661-50c3-4844-8d16-4e45e52eaeba) - [day-820-paper.png](https://git.kayg.org/attachments/aa1c101f-d922-405f-b067-d2ad43f8b4aa) - [day-820-tokyo-night.png](https://git.kayg.org/attachments/33d8ac4d-854f-44a1-bf4c-75aa585d535b) - [week-1440-paper.png](https://git.kayg.org/attachments/0eb4c3ce-76a0-4c45-88d8-6ad0b5641990) - [week-1440-tokyo-night.png](https://git.kayg.org/attachments/e163030b-17e7-4bb3-9913-2c57c43d3740) - [week-390-paper.png](https://git.kayg.org/attachments/e6ff3e70-f82c-4749-bc5c-4091dbf78c6b) - [week-390-tokyo-night.png](https://git.kayg.org/attachments/f69bc035-6702-486c-a5bc-f9fa3e89fe3d) - [week-820-paper.png](https://git.kayg.org/attachments/21e86429-ecf5-418a-8f7f-ccc16ac79b9c) - [week-820-tokyo-night.png](https://git.kayg.org/attachments/5d7e8847-30dd-43a8-80ba-873c9cdfc872) - [weekscroll-1018-evidence.zip](https://git.kayg.org/attachments/2211e809-d15f-4869-9c3b-9c4f8e86c29d)
Author
Owner

Round 2 starts on job/weekscroll-1018 at 21df90808. Measure paint and compositor layers first, then per-frame work, containment and native scrolling. Use the locked perf VM and the real 650-day / 7,200-Log fixture. No dependency changes planned.

Round 2 starts on job/weekscroll-1018 at 21df90808. Measure paint and compositor layers first, then per-frame work, containment and native scrolling. Use the locked perf VM and the real 650-day / 7,200-Log fixture. No dependency changes planned.
Author
Owner

Round 2 findings: GridColumn layout is a day-data/zoom derived value; stable date keys retain it. TimeGrid reads native scrollLeft once per frame and changes the mounted window only at day edges. There is no per-card scroll state or text measurement. Cards have no idle backdrop filter or shadow. Each card does have sticky text and rounded overflow clipping. Only the two shared tracks declare will-change. The first diagnostic comparison is excluded: before capture left the saved theme dark for after measurement. The probe now restores Paper per phase and listens for layers before navigation.

Round 2 findings: GridColumn layout is a day-data/zoom derived value; stable date keys retain it. TimeGrid reads native scrollLeft once per frame and changes the mounted window only at day edges. There is no per-card scroll state or text measurement. Cards have no idle backdrop filter or shadow. Each card does have sticky text and rounded overflow clipping. Only the two shared tracks declare will-change. The first diagnostic comparison is excluded: before capture left the saved theme dark for after measurement. The probe now restores Paper per phase and listens for layers before navigation.
Author
Owner

Matched Paper isolation, one locked perf VM session, 1440 wheel / 60 days:

Step rAF p95 ms Compositor p95 ms Task CPU s Raster wall ms Trace raster layer IDs
Matched Paper isolation, one locked perf VM session, 1440 wheel / 60 days: | Step | rAF p95 ms | Compositor p95 ms | Task CPU s | Raster wall ms | Trace raster layer IDs | | --- | ---: | ---: | ---: | ---: | ---: |
Author
Owner

Complete matched Paper isolation results (the preceding comment sent before the table was complete). One locked perf VM session, 1440 wheel / 60 days:

Step rAF p95 ms Compositor p95 ms Task CPU s Raster wall ms Trace raster layer IDs
before 116.7 132.6 2.328 1406.7 1375
after-glass 50.0 29.1 4.591 2452.8 1389
after-sticky 133.5 143.1 2.268 1568.1 154
after-contain 166.7 174.6 2.347 434.4 1393

Shared glass drives the frame delay. Sticky label removal cuts layer churn but does not solve the glass cost. Card containment cuts raster wall time by 69%, without solving the frame delay alone. A shared horizontal gesture marker now has a focused regression: 11 tests pass. Next: separate edge and floating glass, then combine the useful changes.

Complete matched Paper isolation results (the preceding comment sent before the table was complete). One locked perf VM session, 1440 wheel / 60 days: | Step | rAF p95 ms | Compositor p95 ms | Task CPU s | Raster wall ms | Trace raster layer IDs | | --- | ---: | ---: | ---: | ---: | ---: | | before | 116.7 | 132.6 | 2.328 | 1406.7 | 1375 | | after-glass | 50.0 | 29.1 | 4.591 | 2452.8 | 1389 | | after-sticky | 133.5 | 143.1 | 2.268 | 1568.1 | 154 | | after-contain | 166.7 | 174.6 | 2.347 | 434.4 | 1393 | Shared glass drives the frame delay. Sticky label removal cuts layer churn but does not solve the glass cost. Card containment cuts raster wall time by 69%, without solving the frame delay alone. A shared horizontal gesture marker now has a focused regression: 11 tests pass. Next: separate edge and floating glass, then combine the useful changes.
Author
Owner

Round 2 finished on job/weekscroll-1018, head ec251e0584c7254ac70116b3298dd312ad3a4172. No push, deployment or issue closure. The requested origin/dev merge is 0ad68e1008d077482a5d6ae5392ca3f25eaeceb5. Worktree is clean. This round does not meet the requested frame target.

Built: native horizontal gestures now use static main chrome material and non-sticky card labels, then restore the resting material at scrollend. Cards use layout/paint/style containment. Attachment-free Log titles omit their empty wrapper but retain its 4px gap. Hover lift/shadow is suppressed during horizontal travel without changing shared motion durations, focus or active drag. One root marker changes at gesture edges; it clears at settlement and unmount. Portal popovers retain their blur. No per-card scroll state, text measurement, extra will-change, packing redesign or JS fling was added.

Files: packages/ui/src/components/calendar/TimeGrid.svelte, packages/ui/src/components/calendar/GridColumn.svelte, packages/ui/src/tokens.css, apps/web/src/lib/calendar/TimeGrid.svelte.test.ts, bench/week-scroll-1018.mjs, docs/perf/week-scroll-1018.md, docs/perf/week-scroll-1018.json. Module and non-obvious function comments were re-read. Existing test expectations were retained.

Measurements: Chrome 153.0.8010.12 on the perf VM, CPU throttle off, /root/perf.lock held throughout each session. No builds there. The final matched pair uses immutable saved builds, the same server and real fixture. Initial locked load: 0.00, 0.03, 0.43; baseline sample phase 0.08, 0.05, 0.43; after phase 1.67, 0.75, 0.64. Earlier mixed-theme and mutable-build diagnostics are excluded. The benchmark now verifies theme and immutable phase digests.

Step, 1440 wheel / 60 days rAF p95 Compositor p95 Task CPU Raster wall
Plain card paint: matched before 150.1 ms See raw trace 2.766 s 1545.2 ms
Plain card paint experiment 183.3 ms See raw trace 2.626 s 1407.5 ms
Isolated steps: before 116.7 ms 132.6 ms 2.328 s 1406.7 ms
Shared glass off 50.0 ms 29.1 ms 4.591 s 2452.8 ms
Sticky labels off 133.5 ms 143.1 ms 2.268 s 1568.1 ms
Card containment 166.7 ms 174.6 ms 2.347 s 434.4 ms
Combined steps: before 83.4 ms 92.3 ms 1.956 s 1314.9 ms
Edge glass off 100.0 ms 79.2 ms 3.690 s 2470.6 ms
Overlay glass off 133.3 ms 137.2 ms 3.269 s 2059.3 ms
All glass + sticky off + containment 33.4 ms 31.1 ms 4.015 s 2311.9 ms
Edge glass + sticky off + containment 33.4 ms 37.0 ms 2.382 s 1636.3 ms
Frozen production: before (21df90808 UI) 100.1 ms 109.3 ms 1.960 s 1259.6 ms
Frozen production: after (f7bac8d7a UI) 33.3 ms 30.2 ms 2.866 s 1671.5 ms

Step 2 audit found no scroll-reactive card stores, text measurement or repeated lane packing. Stable date keys retain the day/zoom-derived packing. Step 3 shipped containment and the empty-wrapper removal; columns already used content-visibility:auto. Step 4 confirmed native overflow and native track timelines; no scroll rewrite was needed. Plain paint alone did not improve p95, so resting radii/material were retained.

Final 10-day wheel p95: desktop 133.4 → 16.8 ms; tablet 83.4 → 16.8 ms. Touch rAF p95: desktop 116.7 → 33.3 ms, tablet 50.0 → 33.3 ms. Touch compositor p95 remains 94.9/66.6 ms; samples include idle frames after release and different actual native distances. See raw samples before comparing them with wheel.

The baseline registry's round 1 60-day result was 200.0 → 150.1 ms, task CPU 3.024 → 2.281 s and raster 1135.5 → 1467.9 ms. The final round 2 matched pair gives a 66.7% rAF p95 reduction, but task CPU rises 46.2% and raster wall duration rises 32.7%. More delivered frames cost more total work. #1026 remains relevant. RSS after: 834.4 → 873.3 MiB; DOM nodes: 1319 → 1247; eleven columns remain mounted. Retained heap after the 650-day traversal stays 10.6–12.0 MB.

Known gaps / remaining cause: 16.7 ms is unmet; 33.3 ms also misses the ≤33 ms fallback by 0.3 ms. Compositor p95 is below 33 ms. Dense entering days still incur 169 layouts (334.7 ms total, 6.3 ms maximum), 544 style passes (336.7 ms total, 12.8 ms maximum), 2952 raster tasks (1671.5 ms summed wall duration, 7.2 ms maximum), and 297 commits (285.6 ms total, 9.9 ms maximum). The available after tree has 295 layers, 276 with content and nine sticky layers. Raster layer IDs over the full gesture are 431; IDs measure churn, not simultaneous layers. The baseline live tree was unavailable. These are the remaining measured dense-card costs; evidence does not isolate a single sole cause of the 33.3 ms tail. No observed long task occurred in the final wheel gesture. A file-event callback elsewhere in the trace is outside that measured interval.

UX gaps closed: empty title-wrapper removal keeps the original 4px gap; vertical scrolling keeps sticky labels; scrollend/snap/unmount remove the marker; hovered moving cards remain flat; preview popovers keep readable material. Production checks passed selection, Space preview, Copy link, native wheel/touch movement, exact URL settlement, track alignment, keyboard date navigation and reduced motion. Loading and input never wait for paint state.

UX gaps left: real macOS/Safari momentum and unsupported-timeline fallback need the combined merge-round checks. No new item-action gap was found in the focused walk.

Decisions: use one Calendar-owned root gesture attribute rather than a document-wide :has dependency; suspend main chrome backdrop sampling only while horizontal travel occurs; keep portal blur and vertical sticking; use a 48px/hour cold intrinsic estimate while explicit dimensions remain authoritative; retain existing native scrolling/packing; use the same available shared release server for both UI builds because shared-server/CURRENT was absent. No Rust behavior or API changed.

Visual evidence: 24 before/after production screenshots, Week and Day, 390/820/1440, Paper/Tokyo Night, macOS platform rendering. At 390 and 820 no pixel has a channel delta above 10; at 1440 each image has fewer than 100 such pixels within title glyphs. Cap-height alignment was inspected in the production captures; final visual review belongs to Claude. No review artifact is committed. Private fixture sessions are excluded from attachments.

Gate output verbatim (full logs are in the evidence archive):

cargo fmt --check: exit 0, no output. No Rust changes from this job, so per-crate clippy/test are not applicable.

$ node scripts/check-user-storage.mjs && node scripts/check-type-tokens.mjs && node scripts/check-motion-tokens.mjs && svelte-kit sync && svelte-check --tsconfig ./tsconfig.json
User browser caches use userStorage; only documented device/public-link exceptions remain.
Text sizes and UI shape values use shared role tokens.
UI transitions and animation options use shared motion tokens or documented exceptions.
Loading svelte-check in workspace: /home/kayg/Developer/calternal-wt/weekscroll-1018/apps/web
Getting Svelte diagnostics...

svelte-check found 0 errors and 0 warnings

 RUN  v5.0.1 /home/kayg/Developer/calternal-wt/weekscroll-1018/apps/web


 Test Files  2 passed (2)
      Tests  85 passed (85)
   Start at  22:25:20
   Duration  12.63s (transform 69%, tests 22%, import 5%, environment 3%, setup 1%)

  Transform  |component| transforming modules took 8.79s · 78% 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

 RUN  v5.0.1 /home/kayg/Developer/calternal-wt/weekscroll-1018/apps/web


 Test Files  1 passed (1)
      Tests  11 passed (11)
   Start at  22:37:18
   Duration  11.61s (transform 73%, tests 10%, environment 9%, import 6%, setup 2%)

  Transform  |component| transforming modules took 8.36s · 73% 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
TAP version 13
# Subtest: owner fixture has exact totals, dense overlap days, tags and real attachment links
ok 1 - owner fixture has exact totals, dense overlap days, tags and real attachment links
  ---
  duration_ms: 40.450258
  type: 'test'
  ...
1..1
# tests 1
# suites 0
# pass 1
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 164.036425
week-scroll-1018: saved production regression passed

Production build passed. Cleanup: cargo clean and web build output removal completed.

For the merge round (not run here under the latest verification policy):

  • In apps/web: bun run test --maxWorkers=2 — full web regression coverage.
  • In apps/web: bun run test:e2e:calendar and bun run test:e2e:weekstate-609 — real Calendar actions, retained view state and sticky labels after gestures.
  • From root: bash tests/adversarial/run-split.sh — combined API authz/XUser/robustness matrices.
  • On the locked macOS VM, run the same production Calendar fixture and native wheel/touch momentum; check Safari track alignment and material restoration. Also check the fallback on a browser without native scroll timelines.

Evidence attachments:

Round 2 finished on `job/weekscroll-1018`, head `ec251e0584c7254ac70116b3298dd312ad3a4172`. No push, deployment or issue closure. The requested origin/dev merge is `0ad68e1008d077482a5d6ae5392ca3f25eaeceb5`. Worktree is clean. This round does not meet the requested frame target. Built: native horizontal gestures now use static main chrome material and non-sticky card labels, then restore the resting material at scrollend. Cards use layout/paint/style containment. Attachment-free Log titles omit their empty wrapper but retain its 4px gap. Hover lift/shadow is suppressed during horizontal travel without changing shared motion durations, focus or active drag. One root marker changes at gesture edges; it clears at settlement and unmount. Portal popovers retain their blur. No per-card scroll state, text measurement, extra will-change, packing redesign or JS fling was added. Files: `packages/ui/src/components/calendar/TimeGrid.svelte`, `packages/ui/src/components/calendar/GridColumn.svelte`, `packages/ui/src/tokens.css`, `apps/web/src/lib/calendar/TimeGrid.svelte.test.ts`, `bench/week-scroll-1018.mjs`, `docs/perf/week-scroll-1018.md`, `docs/perf/week-scroll-1018.json`. Module and non-obvious function comments were re-read. Existing test expectations were retained. Measurements: Chrome 153.0.8010.12 on the perf VM, CPU throttle off, `/root/perf.lock` held throughout each session. No builds there. The final matched pair uses immutable saved builds, the same server and real fixture. Initial locked load: 0.00, 0.03, 0.43; baseline sample phase 0.08, 0.05, 0.43; after phase 1.67, 0.75, 0.64. Earlier mixed-theme and mutable-build diagnostics are excluded. The benchmark now verifies theme and immutable phase digests. | Step, 1440 wheel / 60 days | rAF p95 | Compositor p95 | Task CPU | Raster wall | | --- | --- | --- | --- | --- | | Plain card paint: matched before | 150.1 ms | See raw trace | 2.766 s | 1545.2 ms | | Plain card paint experiment | 183.3 ms | See raw trace | 2.626 s | 1407.5 ms | | Isolated steps: before | 116.7 ms | 132.6 ms | 2.328 s | 1406.7 ms | | Shared glass off | 50.0 ms | 29.1 ms | 4.591 s | 2452.8 ms | | Sticky labels off | 133.5 ms | 143.1 ms | 2.268 s | 1568.1 ms | | Card containment | 166.7 ms | 174.6 ms | 2.347 s | 434.4 ms | | Combined steps: before | 83.4 ms | 92.3 ms | 1.956 s | 1314.9 ms | | Edge glass off | 100.0 ms | 79.2 ms | 3.690 s | 2470.6 ms | | Overlay glass off | 133.3 ms | 137.2 ms | 3.269 s | 2059.3 ms | | All glass + sticky off + containment | 33.4 ms | 31.1 ms | 4.015 s | 2311.9 ms | | Edge glass + sticky off + containment | 33.4 ms | 37.0 ms | 2.382 s | 1636.3 ms | | Frozen production: before (21df90808 UI) | 100.1 ms | 109.3 ms | 1.960 s | 1259.6 ms | | Frozen production: after (f7bac8d7a UI) | 33.3 ms | 30.2 ms | 2.866 s | 1671.5 ms | Step 2 audit found no scroll-reactive card stores, text measurement or repeated lane packing. Stable date keys retain the day/zoom-derived packing. Step 3 shipped containment and the empty-wrapper removal; columns already used content-visibility:auto. Step 4 confirmed native overflow and native track timelines; no scroll rewrite was needed. Plain paint alone did not improve p95, so resting radii/material were retained. Final 10-day wheel p95: desktop 133.4 → 16.8 ms; tablet 83.4 → 16.8 ms. Touch rAF p95: desktop 116.7 → 33.3 ms, tablet 50.0 → 33.3 ms. Touch compositor p95 remains 94.9/66.6 ms; samples include idle frames after release and different actual native distances. See raw samples before comparing them with wheel. The baseline registry's round 1 60-day result was 200.0 → 150.1 ms, task CPU 3.024 → 2.281 s and raster 1135.5 → 1467.9 ms. The final round 2 matched pair gives a 66.7% rAF p95 reduction, but task CPU rises 46.2% and raster wall duration rises 32.7%. More delivered frames cost more total work. #1026 remains relevant. RSS after: 834.4 → 873.3 MiB; DOM nodes: 1319 → 1247; eleven columns remain mounted. Retained heap after the 650-day traversal stays 10.6–12.0 MB. Known gaps / remaining cause: 16.7 ms is unmet; 33.3 ms also misses the ≤33 ms fallback by 0.3 ms. Compositor p95 is below 33 ms. Dense entering days still incur 169 layouts (334.7 ms total, 6.3 ms maximum), 544 style passes (336.7 ms total, 12.8 ms maximum), 2952 raster tasks (1671.5 ms summed wall duration, 7.2 ms maximum), and 297 commits (285.6 ms total, 9.9 ms maximum). The available after tree has 295 layers, 276 with content and nine sticky layers. Raster layer IDs over the full gesture are 431; IDs measure churn, not simultaneous layers. The baseline live tree was unavailable. These are the remaining measured dense-card costs; evidence does not isolate a single sole cause of the 33.3 ms tail. No observed long task occurred in the final wheel gesture. A file-event callback elsewhere in the trace is outside that measured interval. UX gaps closed: empty title-wrapper removal keeps the original 4px gap; vertical scrolling keeps sticky labels; scrollend/snap/unmount remove the marker; hovered moving cards remain flat; preview popovers keep readable material. Production checks passed selection, Space preview, Copy link, native wheel/touch movement, exact URL settlement, track alignment, keyboard date navigation and reduced motion. Loading and input never wait for paint state. UX gaps left: real macOS/Safari momentum and unsupported-timeline fallback need the combined merge-round checks. No new item-action gap was found in the focused walk. Decisions: use one Calendar-owned root gesture attribute rather than a document-wide :has dependency; suspend main chrome backdrop sampling only while horizontal travel occurs; keep portal blur and vertical sticking; use a 48px/hour cold intrinsic estimate while explicit dimensions remain authoritative; retain existing native scrolling/packing; use the same available shared release server for both UI builds because shared-server/CURRENT was absent. No Rust behavior or API changed. Visual evidence: 24 before/after production screenshots, Week and Day, 390/820/1440, Paper/Tokyo Night, macOS platform rendering. At 390 and 820 no pixel has a channel delta above 10; at 1440 each image has fewer than 100 such pixels within title glyphs. Cap-height alignment was inspected in the production captures; final visual review belongs to Claude. No review artifact is committed. Private fixture sessions are excluded from attachments. Gate output verbatim (full logs are in the evidence archive): `cargo fmt --check`: exit 0, no output. No Rust changes from this job, so per-crate clippy/test are not applicable. ```text $ node scripts/check-user-storage.mjs && node scripts/check-type-tokens.mjs && node scripts/check-motion-tokens.mjs && svelte-kit sync && svelte-check --tsconfig ./tsconfig.json User browser caches use userStorage; only documented device/public-link exceptions remain. Text sizes and UI shape values use shared role tokens. UI transitions and animation options use shared motion tokens or documented exceptions. Loading svelte-check in workspace: /home/kayg/Developer/calternal-wt/weekscroll-1018/apps/web Getting Svelte diagnostics... svelte-check found 0 errors and 0 warnings ``` ```text RUN v5.0.1 /home/kayg/Developer/calternal-wt/weekscroll-1018/apps/web Test Files 2 passed (2) Tests 85 passed (85) Start at 22:25:20 Duration 12.63s (transform 69%, tests 22%, import 5%, environment 3%, setup 1%) Transform |component| transforming modules took 8.79s · 78% 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 ``` ```text RUN v5.0.1 /home/kayg/Developer/calternal-wt/weekscroll-1018/apps/web Test Files 1 passed (1) Tests 11 passed (11) Start at 22:37:18 Duration 11.61s (transform 73%, tests 10%, environment 9%, import 6%, setup 2%) Transform |component| transforming modules took 8.36s · 73% 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 ``` ```text TAP version 13 # Subtest: owner fixture has exact totals, dense overlap days, tags and real attachment links ok 1 - owner fixture has exact totals, dense overlap days, tags and real attachment links --- duration_ms: 40.450258 type: 'test' ... 1..1 # tests 1 # suites 0 # pass 1 # fail 0 # cancelled 0 # skipped 0 # todo 0 # duration_ms 164.036425 ``` ```text week-scroll-1018: saved production regression passed ``` Production build passed. Cleanup: cargo clean and web build output removal completed. For the merge round (not run here under the latest verification policy): - In apps/web: `bun run test --maxWorkers=2` — full web regression coverage. - In apps/web: `bun run test:e2e:calendar` and `bun run test:e2e:weekstate-609` — real Calendar actions, retained view state and sticky labels after gestures. - From root: `bash tests/adversarial/run-split.sh` — combined API authz/XUser/robustness matrices. - On the locked macOS VM, run the same production Calendar fixture and native wheel/touch momentum; check Safari track alignment and material restoration. Also check the fallback on a browser without native scroll timelines. Evidence attachments: - [round2-before-day-1440-paper.png](https://git.kayg.org/attachments/34167f91-8a45-4848-9164-83abc1a9475c) - [round2-before-day-1440-tokyo-night.png](https://git.kayg.org/attachments/e562979e-e53c-4bcd-9de9-6cff183aec54) - [round2-before-day-390-paper.png](https://git.kayg.org/attachments/0957be0c-04ab-4779-989f-06a2f389bf21) - [round2-before-day-390-tokyo-night.png](https://git.kayg.org/attachments/35034ee1-1061-4107-9287-10b796547723) - [round2-before-day-820-paper.png](https://git.kayg.org/attachments/7c0ae329-e04a-4803-96f3-b3b80878a30a) - [round2-before-day-820-tokyo-night.png](https://git.kayg.org/attachments/c29be1e2-5f9d-4300-b4c9-6993f8495533) - [round2-before-week-1440-paper.png](https://git.kayg.org/attachments/0a43d181-d712-42e8-8f2b-8247947e4d2f) - [round2-before-week-1440-tokyo-night.png](https://git.kayg.org/attachments/ebcbb7a9-e9c7-4e51-94ff-9c2a2f771df3) - [round2-before-week-390-paper.png](https://git.kayg.org/attachments/41847501-e009-4aba-b06b-d796ee713fa2) - [round2-before-week-390-tokyo-night.png](https://git.kayg.org/attachments/167036d5-e9cd-4112-8492-556a903ec40e) - [round2-before-week-820-paper.png](https://git.kayg.org/attachments/b939ebf8-d8f3-4b7a-b73e-8f35d9e08d96) - [round2-before-week-820-tokyo-night.png](https://git.kayg.org/attachments/93d58a44-8670-429f-aabb-973e3d03d9b6) - [round2-after-day-1440-paper.png](https://git.kayg.org/attachments/9de2bbcf-019c-4e4f-8745-fc60c335fcf4) - [round2-after-day-1440-tokyo-night.png](https://git.kayg.org/attachments/9e9b03d0-5810-4162-b417-cd7da7a3cfa6) - [round2-after-day-390-paper.png](https://git.kayg.org/attachments/c226b3a9-e81c-4b28-9ca6-9795f10f93c5) - [round2-after-day-390-tokyo-night.png](https://git.kayg.org/attachments/8564559d-ad08-4e09-8991-dfd06495bb32) - [round2-after-day-820-paper.png](https://git.kayg.org/attachments/40f3f072-b6dc-49ac-9e20-69c9e0f4a681) - [round2-after-day-820-tokyo-night.png](https://git.kayg.org/attachments/ca803a64-d2de-4013-8636-cec038864b25) - [round2-after-week-1440-paper.png](https://git.kayg.org/attachments/477e333e-3094-45bc-b658-29c19e33e5cf) - [round2-after-week-1440-tokyo-night.png](https://git.kayg.org/attachments/be110a94-0df7-46d6-8c47-8704703b96d1) - [round2-after-week-390-paper.png](https://git.kayg.org/attachments/685e3522-c01c-4a64-ae0c-5e3a851521aa) - [round2-after-week-390-tokyo-night.png](https://git.kayg.org/attachments/e37ad530-f977-4ef5-ae82-0f720174eb65) - [round2-after-week-820-paper.png](https://git.kayg.org/attachments/ff5340d9-5a9b-4a0e-8c71-2d6288c2e747) - [round2-after-week-820-tokyo-night.png](https://git.kayg.org/attachments/983cf675-78ae-499b-8dfc-0c9c381ecb1a) - [round2-weekscroll-evidence.zip](https://git.kayg.org/attachments/b1d61eba-aba0-4f0d-88ed-cec22b2639d1)
Author
Owner

Round 3 starts on job/weekscroll-1018 at ec251e0584. Profile a seven-day native pass on the same 650-day / 7200-Log fixture. Compare flat card clips and one column layer first; record style/layout, renderer CPU, raster wall, layer reasons and idle renderer CPU. No dependency or API changes planned.

Round 3 starts on job/weekscroll-1018 at ec251e0584c7254ac70116b3298dd312ad3a4172. Profile a seven-day native pass on the same 650-day / 7200-Log fixture. Compare flat card clips and one column layer first; record style/layout, renderer CPU, raster wall, layer reasons and idle renderer CPU. No dependency or API changes planned.
Author
Owner

Dense week isolation on the locked perf VM, same fixture and saved production builds: 100 Logs over the measured anchor week. Direct card geometry: renderer task CPU 2.143 → 2.100 s; raster wall 323.4 → 311.3 ms; rAF p95 stays 16.8 ms; compositor p95 18.4 → 17.8 ms. Column compositing with direct geometry: CPU 2.093 s, raster 300.9 ms, compositor p95 20.7 ms. Style counts stay near one per frame (337/337/335). Live LayerTree was unavailable in this session; no simultaneous layer-count claim. Next: move Log title clamp variables to the title only, remove inherited lane aliases, and compare the combined production change for the 60-day burst. Idle renderer task CPU is 0.96–1.78% over two seconds; add an idle trace to identify the remaining activity.

Dense week isolation on the locked perf VM, same fixture and saved production builds: 100 Logs over the measured anchor week. Direct card geometry: renderer task CPU 2.143 → 2.100 s; raster wall 323.4 → 311.3 ms; rAF p95 stays 16.8 ms; compositor p95 18.4 → 17.8 ms. Column compositing with direct geometry: CPU 2.093 s, raster 300.9 ms, compositor p95 20.7 ms. Style counts stay near one per frame (337/337/335). Live LayerTree was unavailable in this session; no simultaneous layer-count claim. Next: move Log title clamp variables to the title only, remove inherited lane aliases, and compare the combined production change for the 60-day burst. Idle renderer task CPU is 0.96–1.78% over two seconds; add an idle trace to identify the remaining activity.
Author
Owner

Matched locked-VM 60-day burst: current round-2 source → combined round-3 source with two-day mount batches. rAF p95 33.4 → 33.4 ms; compositor p95 31.8 → 31.1 ms; renderer task CPU 3.882 → 3.355 s (-13.6%); raster wall 2105.6 → 1171.0 ms (-44.4%); layouts 170 → 111; style passes 505 → 457. Both phases use the same server, fixture and immutable production bundles. The 16.7 ms target is still unmet. First column-only combination reduced raster but raised CPU (3.144 → 3.451 s), so batching is necessary. No existing test expectation was changed. New regression checks forward and reverse movement through a retained batch while visible dates continue to change. Decisions: mount eleven Week columns in two-day batches; retain at least two forward and one reverse buffer dates. Idle has zero layout and style passes, but 1.6% renderer task CPU remains; idle traces show the shared file-events callback, not a running scroll loop. Final full profile and Mac-platform production screenshots are running.

Matched locked-VM 60-day burst: current round-2 source → combined round-3 source with two-day mount batches. rAF p95 33.4 → 33.4 ms; compositor p95 31.8 → 31.1 ms; renderer task CPU 3.882 → 3.355 s (-13.6%); raster wall 2105.6 → 1171.0 ms (-44.4%); layouts 170 → 111; style passes 505 → 457. Both phases use the same server, fixture and immutable production bundles. The 16.7 ms target is still unmet. First column-only combination reduced raster but raised CPU (3.144 → 3.451 s), so batching is necessary. No existing test expectation was changed. New regression checks forward and reverse movement through a retained batch while visible dates continue to change. Decisions: mount eleven Week columns in two-day batches; retain at least two forward and one reverse buffer dates. Idle has zero layout and style passes, but 1.6% renderer task CPU remains; idle traces show the shared file-events callback, not a running scroll loop. Final full profile and Mac-platform production screenshots are running.
Author
Owner

Round 3 finished on job/weekscroll-1018, head 7de6492ed4d91da1dc35bdb6a29ea104c48eaeb9. The requested origin/dev merge is 3c0e8494c. No push, deployment or issue closure. The worktree is clean. The 16.7 ms frame target remains unmet.

Built: packed cards now use ordinary CSS geometry instead of inherited start, duration and lane variables. Log title limits live on the title only. Removed unused lane aliases. Moving columns request one transform layer; cards make no inline style writes during scroll. Mounted dates advance in two-day batches, while visible dates, the title and native position still follow each day. Eleven Week columns stay mounted, with at least two forward and one reverse buffer dates. Resting fills, radii, clips, sticky labels, shared motion and reduced motion stay in use. No additional per-card DOM reduction was made.

Files owned and changed: packages/ui/src/components/calendar/GridColumn.svelte, packages/ui/src/components/calendar/TimeGrid.svelte, apps/web/src/lib/calendar/TimeGrid.svelte.test.ts, bench/week-scroll-1018.mjs, docs/perf/week-scroll-1018.md, docs/perf/week-scroll-1018.json. Other changes came from the required origin/dev merge. Module and changed function comments were read again. No existing test expectation was changed.

Measurements use Chrome 153.0.8010.12 on the perf VM, CPU throttle off, with /root/perf.lock held for every session. No builds ran there. Each pair uses the same real 650-day / 7,200-Log fixture and immutable web bundles. Dense week mode uses 2025-02-16: 100 Logs over seven days. The final server is a private copy of an available shared release binary. Matched batch load before: 0.06, 0.62, 0.58; after starts at 0.25, 0.63, 0.59. Final full-profile starting load: 0.08, 0.47, 0.53.

Step rAF p95 Compositor p95 Renderer task CPU Raster wall
Dense week before 16.8 ms 18.4 ms 2.143 s 323.4 ms
Direct geometry 16.8 ms 17.8 ms 2.100 s 311.3 ms
Geometry and column layer 16.8 ms 20.7 ms 2.093 s 300.9 ms
60-day column pair: before 33.3 ms 31.5 ms 3.144 s 1694.9 ms
Geometry, title scope and column layer 33.3 ms 31.1 ms 3.451 s 1045.8 ms
60-day batch pair: before 33.4 ms 31.8 ms 3.882 s 2105.6 ms
Combined change with batches 33.4 ms 31.1 ms 3.355 s 1171.0 ms
Final full profile, separate session 33.3 ms 31.5 ms 2.611 s 861.1 ms

The matched batch pair cuts renderer task CPU by 13.6% and raster wall by 44.4%. Layout passes fall 170 → 111; style passes 505 → 457. Paint rises 167.1 → 199.3 ms. Column layers alone raised CPU, so batching is required. Raster durations overlap across threads and are wall durations, not CPU. The baseline registry still contains the round 1 pair: 200.0 → 150.1 ms rAF p95, 3.024 → 2.281 s task CPU and 1135.5 → 1467.9 ms raster wall. Use matched pairs for attribution; do not compare separate sessions as isolated code effects.

The final full profile passes the unchanged coarse 60-day regression. Desktop/tablet 10-day wheel p95: 16.8 ms. Touch rAF p95: 33.3 ms at both widths; touch compositor p95 remains 99.7/51.3 ms. No long task occurred in any of the five final gestures. Every native track alignment error is zero. Keyboard navigation restores June 2 with both motion preferences. Post-GC heap stays 10.2–12.0 MB across the 650-day traversal, with eleven columns.

Idle after settlement has zero layout/style passes in every final sample. Renderer task CPU remains 1.5–2.0%, so fully zero idle is not established. The idle trace shows the shared file-events callback: the column baseline's 60-day idle sample has 104 calls and 27.6 ms of callback time, with no running scroll rAF loop. Most live layer trees are unavailable; no simultaneous layer-count reduction is claimed. Raster layer IDs show churn, not a live count.

UX gaps closed: retained columns now survive the intervening day without re-mounting; the new test covers forward and reverse motion with exact reported dates. Geometry and title style scopes preserve resting appearance. The column-stage real fixture passed selection, Space preview and Copy link. Final native wheel/touch, keyboard, reduced motion, exact URL settlement and bounded traversal pass. Main chrome restores at settlement; no motion or loading behavior changed.

UX gaps left / known gaps: 16.7 ms is unmet; touch compositor delivery remains delayed; idle file-event work remains; card DOM still needs its sticky container and separate title/metadata lines. Native macOS momentum and Safari/fallback checks need the merge round. Full action, Undo, error/offline and accessibility suites were deferred under the verification policy.

Decisions: use ordinary percentage geometry with shared CSS tokens; scope Log title variables to the title; request one layer per moving column and release it at settlement; use two-day mount batches with the existing eleven-column bound and retained keyboard neighbors. Keep resting radii because the flat-radius diagnostic did not justify shipping it. Add no dependency and change no Rust/API behavior.

Visual evidence: 24 before/final production screenshots, Week and Day at 390/820/1440 in Paper and Tokyo Night with Mac platform emulation. All twelve pairs have zero pixels with a channel difference over 10; the largest difference is 5 in at most six pixels per image. Icon/text alignment was inspected in production captures. Final visual review belongs to the orchestrator. Screenshots and traces are attached, never committed.

Gate output verbatim:

cargo fmt --check: exit 0, no output. Per-crate clippy/test are not applicable: no Rust changes.

$ node scripts/check-user-storage.mjs && node scripts/check-type-tokens.mjs && node scripts/check-motion-tokens.mjs && svelte-kit sync && svelte-check --tsconfig ./tsconfig.json
User browser caches use userStorage; only documented device/public-link exceptions remain.
Text sizes and UI shape values use shared role tokens.
UI transitions and animation options use shared motion tokens or documented exceptions.
Loading svelte-check in workspace: /home/kayg/Developer/calternal-wt/weekscroll-1018/apps/web
Getting Svelte diagnostics...

svelte-check found 0 errors and 0 warnings

 RUN  v5.0.1 /home/kayg/Developer/calternal-wt/weekscroll-1018/apps/web


 Test Files  2 passed (2)
      Tests  41 passed (41)
   Start at  23:12:44
   Duration  12.63s (transform 82%, tests 6%, import 6%, environment 5%, setup 2%)

  Transform  |component| transforming modules took 9.48s · 76% 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

 RUN  v5.0.1 /home/kayg/Developer/calternal-wt/weekscroll-1018/apps/web


 Test Files  1 passed (1)
      Tests  13 passed (13)
   Start at  23:20:41
   Duration  7.93s (transform 68%, tests 13%, environment 11%, import 5%, setup 3%)

  Transform  |component| transforming modules took 5.26s · 68% 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
TAP version 13
# Subtest: owner fixture has exact totals, dense overlap days, tags and real attachment links
ok 1 - owner fixture has exact totals, dense overlap days, tags and real attachment links
  ---
  duration_ms: 27.331123
  type: 'test'
  ...
1..1
# tests 1
# suites 0
# pass 1
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 117.245503
week-scroll-1018: saved production regression passed

Production builds passed. Cleanup ran cargo clean and removed current web build output, private fixture/session, private server copy, saved round-3 builds and the dedicated remote browser profile.

     Removed 1 file, 356B total

For the merge round:

  • cd apps/web && bun run test --maxWorkers=2 — full web regressions.
  • cd apps/web && bun run test:e2e:calendar && bun run test:e2e:weekstate-609 — real Calendar actions, retained dates, settlement and sticky labels.
  • cd apps/web && bun run test:e2e:calendar-crossday && bun run test:e2e:calendar-task-overflow && bun run test:e2e:calendar-doc-stack — split identities, narrow overflow and attachment decks.
  • cd apps/web && bun run test:e2e:a11y && bun run test:e2e:deeplinks — focus, accessible state and stable links.
  • bash tests/adversarial/run-split.sh — combined API matrices. No endpoint-specific API probe was added in this UI job.
  • On the locked macOS VM, use the production fixture for native wheel/touch momentum and Safari timeline alignment. Check the fallback in a browser without native scroll timelines.

Evidence attachments:

Round 3 finished on `job/weekscroll-1018`, head `7de6492ed4d91da1dc35bdb6a29ea104c48eaeb9`. The requested origin/dev merge is `3c0e8494c`. No push, deployment or issue closure. The worktree is clean. The 16.7 ms frame target remains unmet. Built: packed cards now use ordinary CSS geometry instead of inherited start, duration and lane variables. Log title limits live on the title only. Removed unused lane aliases. Moving columns request one transform layer; cards make no inline style writes during scroll. Mounted dates advance in two-day batches, while visible dates, the title and native position still follow each day. Eleven Week columns stay mounted, with at least two forward and one reverse buffer dates. Resting fills, radii, clips, sticky labels, shared motion and reduced motion stay in use. No additional per-card DOM reduction was made. Files owned and changed: `packages/ui/src/components/calendar/GridColumn.svelte`, `packages/ui/src/components/calendar/TimeGrid.svelte`, `apps/web/src/lib/calendar/TimeGrid.svelte.test.ts`, `bench/week-scroll-1018.mjs`, `docs/perf/week-scroll-1018.md`, `docs/perf/week-scroll-1018.json`. Other changes came from the required origin/dev merge. Module and changed function comments were read again. No existing test expectation was changed. Measurements use Chrome 153.0.8010.12 on the perf VM, CPU throttle off, with `/root/perf.lock` held for every session. No builds ran there. Each pair uses the same real 650-day / 7,200-Log fixture and immutable web bundles. Dense week mode uses 2025-02-16: 100 Logs over seven days. The final server is a private copy of an available shared release binary. Matched batch load before: 0.06, 0.62, 0.58; after starts at 0.25, 0.63, 0.59. Final full-profile starting load: 0.08, 0.47, 0.53. | Step | rAF p95 | Compositor p95 | Renderer task CPU | Raster wall | | --- | --- | --- | --- | --- | | Dense week before | 16.8 ms | 18.4 ms | 2.143 s | 323.4 ms | | Direct geometry | 16.8 ms | 17.8 ms | 2.100 s | 311.3 ms | | Geometry and column layer | 16.8 ms | 20.7 ms | 2.093 s | 300.9 ms | | 60-day column pair: before | 33.3 ms | 31.5 ms | 3.144 s | 1694.9 ms | | Geometry, title scope and column layer | 33.3 ms | 31.1 ms | 3.451 s | 1045.8 ms | | 60-day batch pair: before | 33.4 ms | 31.8 ms | 3.882 s | 2105.6 ms | | Combined change with batches | 33.4 ms | 31.1 ms | 3.355 s | 1171.0 ms | | Final full profile, separate session | 33.3 ms | 31.5 ms | 2.611 s | 861.1 ms | The matched batch pair cuts renderer task CPU by 13.6% and raster wall by 44.4%. Layout passes fall 170 → 111; style passes 505 → 457. Paint rises 167.1 → 199.3 ms. Column layers alone raised CPU, so batching is required. Raster durations overlap across threads and are wall durations, not CPU. The baseline registry still contains the round 1 pair: 200.0 → 150.1 ms rAF p95, 3.024 → 2.281 s task CPU and 1135.5 → 1467.9 ms raster wall. Use matched pairs for attribution; do not compare separate sessions as isolated code effects. The final full profile passes the unchanged coarse 60-day regression. Desktop/tablet 10-day wheel p95: 16.8 ms. Touch rAF p95: 33.3 ms at both widths; touch compositor p95 remains 99.7/51.3 ms. No long task occurred in any of the five final gestures. Every native track alignment error is zero. Keyboard navigation restores June 2 with both motion preferences. Post-GC heap stays 10.2–12.0 MB across the 650-day traversal, with eleven columns. Idle after settlement has zero layout/style passes in every final sample. Renderer task CPU remains 1.5–2.0%, so fully zero idle is not established. The idle trace shows the shared file-events callback: the column baseline's 60-day idle sample has 104 calls and 27.6 ms of callback time, with no running scroll rAF loop. Most live layer trees are unavailable; no simultaneous layer-count reduction is claimed. Raster layer IDs show churn, not a live count. UX gaps closed: retained columns now survive the intervening day without re-mounting; the new test covers forward and reverse motion with exact reported dates. Geometry and title style scopes preserve resting appearance. The column-stage real fixture passed selection, Space preview and Copy link. Final native wheel/touch, keyboard, reduced motion, exact URL settlement and bounded traversal pass. Main chrome restores at settlement; no motion or loading behavior changed. UX gaps left / known gaps: 16.7 ms is unmet; touch compositor delivery remains delayed; idle file-event work remains; card DOM still needs its sticky container and separate title/metadata lines. Native macOS momentum and Safari/fallback checks need the merge round. Full action, Undo, error/offline and accessibility suites were deferred under the verification policy. Decisions: use ordinary percentage geometry with shared CSS tokens; scope Log title variables to the title; request one layer per moving column and release it at settlement; use two-day mount batches with the existing eleven-column bound and retained keyboard neighbors. Keep resting radii because the flat-radius diagnostic did not justify shipping it. Add no dependency and change no Rust/API behavior. Visual evidence: 24 before/final production screenshots, Week and Day at 390/820/1440 in Paper and Tokyo Night with Mac platform emulation. All twelve pairs have zero pixels with a channel difference over 10; the largest difference is 5 in at most six pixels per image. Icon/text alignment was inspected in production captures. Final visual review belongs to the orchestrator. Screenshots and traces are attached, never committed. Gate output verbatim: `cargo fmt --check`: exit 0, no output. Per-crate clippy/test are not applicable: no Rust changes. ```text $ node scripts/check-user-storage.mjs && node scripts/check-type-tokens.mjs && node scripts/check-motion-tokens.mjs && svelte-kit sync && svelte-check --tsconfig ./tsconfig.json User browser caches use userStorage; only documented device/public-link exceptions remain. Text sizes and UI shape values use shared role tokens. UI transitions and animation options use shared motion tokens or documented exceptions. Loading svelte-check in workspace: /home/kayg/Developer/calternal-wt/weekscroll-1018/apps/web Getting Svelte diagnostics... svelte-check found 0 errors and 0 warnings ``` ```text RUN v5.0.1 /home/kayg/Developer/calternal-wt/weekscroll-1018/apps/web Test Files 2 passed (2) Tests 41 passed (41) Start at 23:12:44 Duration 12.63s (transform 82%, tests 6%, import 6%, environment 5%, setup 2%) Transform |component| transforming modules took 9.48s · 76% 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 ``` ```text RUN v5.0.1 /home/kayg/Developer/calternal-wt/weekscroll-1018/apps/web Test Files 1 passed (1) Tests 13 passed (13) Start at 23:20:41 Duration 7.93s (transform 68%, tests 13%, environment 11%, import 5%, setup 3%) Transform |component| transforming modules took 5.26s · 68% 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 ``` ```text TAP version 13 # Subtest: owner fixture has exact totals, dense overlap days, tags and real attachment links ok 1 - owner fixture has exact totals, dense overlap days, tags and real attachment links --- duration_ms: 27.331123 type: 'test' ... 1..1 # tests 1 # suites 0 # pass 1 # fail 0 # cancelled 0 # skipped 0 # todo 0 # duration_ms 117.245503 ``` ```text week-scroll-1018: saved production regression passed ``` Production builds passed. Cleanup ran cargo clean and removed current web build output, private fixture/session, private server copy, saved round-3 builds and the dedicated remote browser profile. ```text Removed 1 file, 356B total ``` For the merge round: - `cd apps/web && bun run test --maxWorkers=2` — full web regressions. - `cd apps/web && bun run test:e2e:calendar && bun run test:e2e:weekstate-609` — real Calendar actions, retained dates, settlement and sticky labels. - `cd apps/web && bun run test:e2e:calendar-crossday && bun run test:e2e:calendar-task-overflow && bun run test:e2e:calendar-doc-stack` — split identities, narrow overflow and attachment decks. - `cd apps/web && bun run test:e2e:a11y && bun run test:e2e:deeplinks` — focus, accessible state and stable links. - `bash tests/adversarial/run-split.sh` — combined API matrices. No endpoint-specific API probe was added in this UI job. - On the locked macOS VM, use the production fixture for native wheel/touch momentum and Safari timeline alignment. Check the fallback in a browser without native scroll timelines. Evidence attachments: - [round3-before-day-1440-paper.png](https://git.kayg.org/attachments/5eea51f6-5ef0-40dd-b266-ee186bceef4c) - [round3-before-day-1440-tokyo-night.png](https://git.kayg.org/attachments/34577c5e-3a9f-47d9-a37f-3d226a0ab537) - [round3-before-day-390-paper.png](https://git.kayg.org/attachments/5b43c795-e4f2-43d5-bb67-f52e91ce2748) - [round3-before-day-390-tokyo-night.png](https://git.kayg.org/attachments/8a83c0f2-1c32-4841-928a-b8d8cb732acd) - [round3-before-day-820-paper.png](https://git.kayg.org/attachments/7458da36-9ec3-43ea-a06e-4f7d3f5a0d5c) - [round3-before-day-820-tokyo-night.png](https://git.kayg.org/attachments/7845d651-cf55-4945-bb2a-f106cf237672) - [round3-before-week-1440-paper.png](https://git.kayg.org/attachments/67050c9f-1c1c-4a4b-9ba8-ca04b11dc57b) - [round3-before-week-1440-tokyo-night.png](https://git.kayg.org/attachments/cb3a34ff-a3ba-43a7-841a-5bf62c445ddc) - [round3-before-week-390-paper.png](https://git.kayg.org/attachments/eaa5e7bd-6505-4666-bcd7-420c30119481) - [round3-before-week-390-tokyo-night.png](https://git.kayg.org/attachments/be91acd3-0032-4e50-8072-a8c43830a2cc) - [round3-before-week-820-paper.png](https://git.kayg.org/attachments/1ff0689a-92ed-4b91-9d8e-ceea03183b52) - [round3-before-week-820-tokyo-night.png](https://git.kayg.org/attachments/76b908aa-7044-4a05-b837-886dc9486f3b) - [round3-final-day-1440-paper.png](https://git.kayg.org/attachments/86fe54b1-554f-4b94-98e7-3f93d49b54d6) - [round3-final-day-1440-tokyo-night.png](https://git.kayg.org/attachments/0a6efc86-4ee9-4081-b922-0d6d34e2f419) - [round3-final-day-390-paper.png](https://git.kayg.org/attachments/e7c193ec-305f-4b12-aeb3-274a3ea5ce38) - [round3-final-day-390-tokyo-night.png](https://git.kayg.org/attachments/658d89fc-8405-4384-903d-3570122e0623) - [round3-final-day-820-paper.png](https://git.kayg.org/attachments/83a3fc9b-3699-453a-99e0-0170c8d14b2f) - [round3-final-day-820-tokyo-night.png](https://git.kayg.org/attachments/ce009fe3-004c-4640-9bc5-2d9ece642846) - [round3-final-week-1440-paper.png](https://git.kayg.org/attachments/5578055d-44fd-414d-93e3-73b0f267af02) - [round3-final-week-1440-tokyo-night.png](https://git.kayg.org/attachments/21abb8f4-c540-40f3-9155-f8f934e35a96) - [round3-final-week-390-paper.png](https://git.kayg.org/attachments/6dbb49fe-bd08-4f0b-b918-1de71739bd19) - [round3-final-week-390-tokyo-night.png](https://git.kayg.org/attachments/206b2962-0267-4923-a8a4-529581d9b4b6) - [round3-final-week-820-paper.png](https://git.kayg.org/attachments/cacc2c4a-a084-4e7e-b976-6d951accb218) - [round3-final-week-820-tokyo-night.png](https://git.kayg.org/attachments/ba20eaba-2304-45fd-84e6-88d4f52689f2) - [round3-weekscroll-evidence.zip](https://git.kayg.org/attachments/137e2963-0309-4f6e-9b84-515f821721e0)
Author
Owner

Round 4 starts on job/weekscroll-1018 at 7de6492ed4. First measure an empty horizontal scrolling page with the same perf VM Chrome and driver. Then trace frame delivery and post-scroll idle callbacks. No dependency changes planned.

Round 4 starts on job/weekscroll-1018 at 7de6492ed4d91da1dc35bdb6a29ea104c48eaeb9. First measure an empty horizontal scrolling page with the same perf VM Chrome and driver. Then trace frame delivery and post-scroll idle callbacks. No dependency changes planned.
Author
Owner

Empty-page baseline first (round 4): locked perf VM Chrome 153.0.8010.12, CPU throttle off, load 0.00 / 0.04 / 0.23. Same five-second native mouse scroll and 12,000 px travel. Untraced: 310 frames, median 16.7 ms, p95 16.8 ms, idle renderer CPU 0.0075%. Traced with the Week CPU-profile categories: 308 frames, median 16.7 ms, p95 16.7 ms, idle 0.0100%. The VM is not capped at 30 Hz. The round 3 60-day trace has 255 DrawFrame intervals near one vsync and 21 near two; the reported p95 is a missed-frame tail, not steady 30 fps. Continue with renderer/compositor work and the idle file-event stream.

Empty-page baseline first (round 4): locked perf VM Chrome 153.0.8010.12, CPU throttle off, load 0.00 / 0.04 / 0.23. Same five-second native mouse scroll and 12,000 px travel. Untraced: 310 frames, median 16.7 ms, p95 16.8 ms, idle renderer CPU 0.0075%. Traced with the Week CPU-profile categories: 308 frames, median 16.7 ms, p95 16.7 ms, idle 0.0100%. The VM is not capped at 30 Hz. The round 3 60-day trace has 255 DrawFrame intervals near one vsync and 21 near two; the reported p95 is a missed-frame tail, not steady 30 fps. Continue with renderer/compositor work and the idle file-event stream.
Author
Owner

Round 4 finished on job/weekscroll-1018, head 43d5cd557a184b23b20d1aa8aea56f632d3947e6. Base: 7de6492ed4d91da1dc35bdb6a29ea104c48eaeb9. git fetch origin && git merge origin/dev ran once and returned Already up to date. No push, deploy or issue closure. The worktree is clean. The strict 16.7 ms target remains unmet.

Empty-page baseline first

Previously posted before the app experiments: locked perf VM, Chrome 153.0.8010.12, CPU throttle off, load 0.00 / 0.04 / 0.23. A native five-second gesture moves 12,000 px on a plain scroller. Untraced rAF p95: 16.8 ms; traced rAF p95: 16.7 ms. Traced DrawFrame p95: 16.927 ms; all 301 intervals are near one vsync. Empty-page idle renderer CPU: 0.0075–0.0100%. The VM is not limited to 30 Hz.

The prior 60-day trace has a 16.7 ms median, 255 DrawFrame intervals near one vsync and 21 near two. Its 33.3 ms p95 is a missed-frame tail, not steady 30 fps. Main-thread window updates combine Svelte, style, layout and paint into 30–41 ms tasks. Layerize is the largest total stage (616.6 ms in the unchanged control); IntersectionObserver totals 18.8 ms. A separate 55.1 ms wall task has 5.6 ms thread CPU and a 52.6 ms Commit: compositor waiting, not 55 ms of JavaScript. The profile now distinguishes these cases and has regression tests for them.

Built

  • ModeHeader retains its connected Calendar scroller when date titles and PageChrome change. This preserves the horizontal fast path and phone collapse state. A removed route releases the node. The new test covers live titles and route replacement.
  • Timed cards use content-visibility: auto inside their fixed geometry. Off-screen contents skip work while buttons retain their names and native targets. Chrome documents this CSS method.
  • The profile has an empty-page control, vsync histogram, renderer-only stage/task costs, thread CPU versus wall time, server binary SHA-256, idle file-hint counts, a busy-window flag and active job summaries from the real API. Summaries omit payloads and User identities. The job-summary field was added after the full capture; that capture's job state was checked through the private fixture Index.
  • Retained the original baseline; added round 4 measurements and decisions beside it.

Files

packages/ui/src/components/ModeHeader.svelte
packages/ui/src/components/calendar/GridColumn.svelte
apps/web/src/lib/modeHeader.svelte.test.ts
bench/week-scroll-1018.mjs
bench/week-scroll-1018.test.mjs
docs/perf/baseline.json
docs/perf/week-scroll-1018.json
docs/perf/week-scroll-1018.md

Measurements

Every perf VM session held /root/perf.lock and recorded load. No build ran there. The final pair uses one branch-built server, the same Home and 650-day / 7,200-Log fixture, and immutable saved web builds. Application before: 7de6492ed; after: 53bf81496. Shared-server CURRENT was absent, so the branch server was built once. Its Rust source is unchanged. Before load: 0.01 / 0.16 / 0.20; after: 1.38 / 0.83 / 0.47.

Final pair rAF p95 before → after DrawFrame p95 before → after
1440 wheel, 10 days 16.8 → 16.8 ms 18.7 → 18.1 ms
1440 touch 33.3 → 16.8 ms 83.6 → 75.8 ms
820 wheel, 10 days 16.8 → 16.8 ms 17.2 → 18.3 ms
820 touch 33.3 → 33.2 ms 60.3 → 55.1 ms
1440 wheel, 60 days 33.4 → 16.8 ms 31.2 → 27.6 ms

60-day renderer task CPU: 3.370 → 2.881 s. Raster wall duration: 1271.0 → 573.0 ms. The after run has 286 one-vsync intervals, 7 two-vsync intervals and 5 longer intervals. No >50 ms long task was observed in that after burst. Both full phases also contain live background hints, so this pair is not a quiet-only code attribution.

The isolated card-visibility pair is cleaner: task CPU 2.401 → 2.288 s (-4.7%), raster wall 678.6 → 466.9 ms (-31.2%), DrawFrame p95 28.6 → 24.7 ms. Removing card paint containment, all card containment or column visibility skipping increased task CPU and kept compositor p95 around 30 ms. Those experiments were not shipped. Raster wall durations can overlap; they are not CPU totals.

The baseline registry still retains round 1 (200.0 → 150.1 ms rAF p95, task CPU 3.024 → 2.281 s, raster wall 1135.5 → 1467.9 ms). The new round 4 entry points to its own matched pair. Do not attribute differences across sessions to one code change.

Idle finding

The unchanged-UI control has 0.025% and 0.039% renderer CPU with no file hints. A fresh fixture on that compatible prebuilt server has 0.033% and 0.044%. The branch-built server reproduces 19–37 file hints per two-second post-scroll window, with 0.36–1.84% CPU and zero layout/style passes. A no-hint final window has 0.043% CPU.

The hints name Daily notes. The retained fixture has an active notes.daily-log-projection-rebuild (#724), plus migration/adoption notifications. These samples include background work; they are not quiet idle. No always-running client scroll or animation loop was found. Quiet CPU is already near zero. The benchmark now retains the missing context instead of reporting all settled-grid windows as equivalent idle. Live edits and background work are not suppressed.

Gates (verbatim)

cargo fmt --check: exit 0, no output. Rust code and API contracts did not change; per-crate Rust clippy/test are not applicable.

cd apps/web && bun run check:

$ node scripts/check-user-storage.mjs && node scripts/check-type-tokens.mjs && node scripts/check-motion-tokens.mjs && svelte-kit sync && svelte-check --tsconfig ./tsconfig.json
User browser caches use userStorage; only documented device/public-link exceptions remain.
Text sizes and UI shape values use shared role tokens.
UI transitions and animation options use shared motion tokens or documented exceptions.
Loading svelte-check in workspace: /home/kayg/Developer/calternal-wt/weekscroll-1018/apps/web
Getting Svelte diagnostics...

svelte-check found 0 errors and 0 warnings

cd apps/web && bunx vitest run src/lib/calendar/TimeGrid.svelte.test.ts src/lib/calendar/grid.test.ts src/lib/modeHeader.svelte.test.ts --maxWorkers=2:

 Test Files  3 passed (3)
      Tests  45 passed (45)

node --test bench/week-scroll-1018.test.mjs:

# tests 3
# suites 0
# pass 3
# fail 0
# cancelled 0
# skipped 0
# todo 0

The real production profile used --compare --assert and passed:

week-scroll-1018: production fixture, native wheel/touch, 60-day scroll and bounded two-year traversal captured

Production web build passed. The unchanged coarse 60-day regression passed. No existing assertion or timing bound changed. Comments in every touched source file were read again. Cleanup:

     Removed 7238 files, 4.6GiB total

Web build output, saved bundles and private fixture/session data were removed. Screenshots and traces remain as review artifacts and are attached, not committed.

UX gaps closed

  • Live date titles no longer discard phone header collapse state or the known vertical offset.
  • Off-screen card contents skip rendering work without changing the timed hit box.
  • Native wheel/touch travel, zero track-alignment error, keyboard date navigation, reduced motion, selection, Space preview and Copy link pass on the real fixture. Popover glass remains active during horizontal travel.
  • Post-GC heap stays 10.5–11.9 MB through the two-year traversal, with eleven columns.
  • Before/final Week and Day evidence covers 390, 820 and 1440, Paper and Tokyo Night, with macOS emulation. No icon/text geometry was changed. Claude retains visual review.

UX gaps left / known gaps

  • Strict p95 ≤16.7 ms is not met. rAF p95 reaches the empty-page floor, but compositor p95 is still 27.6 ms for the 60-day run. Touch delivery remains delayed.
  • Background projection/adoption work still consumes CPU and sends live hints. This is not claimed as a fixed server workload.
  • A newer prebuilt server did not become ready within five minutes; no sample from that attempt is used. A fresh-fixture confirmation on the branch-built server indexed all Logs but timed out applying Paper before timing; it is excluded. Logs are attached. No rerun loop followed either failure.
  • Safari, real macOS momentum, screen-reader behavior of off-screen card contents and full Undo/error/offline suites need the merge round.

Decisions

  • Retain a scroller while its DOM node is connected. PageChrome identity is not route identity: the visible date changes it during one gesture.
  • Apply card visibility skipping inside the existing fixed timed boxes. Keep containment, rounding, sticky labels, shared motion durations and native scrolling.
  • Keep the strict target and existing regression thresholds. Record the empty-page floor and interval distribution instead of changing an assertion to pass.
  • Preserve busy post-scroll samples, but tag file activity and record the server binary and job context. Do not cancel real work to obtain a low CPU figure.
  • Add no dependency. Existing locked packages were used.

For the merge round

  • cd apps/web && bun run test --maxWorkers=2: full web regressions.
  • cd apps/web && bun run test:e2e:calendar && bun run test:e2e:weekstate-609: native settlement, URL restoration, resizing, primary actions and keyboard behavior.
  • cd apps/web && bun run test:e2e:calendar-crossday && bun run test:e2e:calendar-task-overflow && bun run test:e2e:calendar-doc-stack: retained columns, narrow actions and attachment decks.
  • cd apps/web && bun run test:e2e:a11y && bun run test:e2e:deeplinks: names, states, focus and stable links; include off-screen cards.
  • tests/adversarial/run-split.sh: the combined server's adversarial matrices. This job adds no API endpoint.
  • CALTERNAL_E2E_ASSET_OVERRIDE=1 CALTERNAL_SERVER_BIN=<combined-server> bun bench/week-scroll-1018.mjs --compare --assert --out artifacts/weekscroll-1018/merge-round: the profile and unchanged coarse budget. Hold perf.lock on the perf VM and record active jobs.
  • On the locked Mac VM, check Safari card focus/sticky labels, timeline fallback and real fling delivery.

Evidence

Round 4 finished on `job/weekscroll-1018`, head `43d5cd557a184b23b20d1aa8aea56f632d3947e6`. Base: `7de6492ed4d91da1dc35bdb6a29ea104c48eaeb9`. `git fetch origin && git merge origin/dev` ran once and returned `Already up to date.` No push, deploy or issue closure. The worktree is clean. The strict 16.7 ms target remains unmet. ### Empty-page baseline first Previously posted before the app experiments: locked perf VM, Chrome 153.0.8010.12, CPU throttle off, load 0.00 / 0.04 / 0.23. A native five-second gesture moves 12,000 px on a plain scroller. Untraced rAF p95: 16.8 ms; traced rAF p95: 16.7 ms. Traced DrawFrame p95: 16.927 ms; all 301 intervals are near one vsync. Empty-page idle renderer CPU: 0.0075–0.0100%. The VM is not limited to 30 Hz. The prior 60-day trace has a 16.7 ms median, 255 DrawFrame intervals near one vsync and 21 near two. Its 33.3 ms p95 is a missed-frame tail, not steady 30 fps. Main-thread window updates combine Svelte, style, layout and paint into 30–41 ms tasks. Layerize is the largest total stage (616.6 ms in the unchanged control); IntersectionObserver totals 18.8 ms. A separate 55.1 ms wall task has 5.6 ms thread CPU and a 52.6 ms Commit: compositor waiting, not 55 ms of JavaScript. The profile now distinguishes these cases and has regression tests for them. ### Built - ModeHeader retains its connected Calendar scroller when date titles and PageChrome change. This preserves the horizontal fast path and phone collapse state. A removed route releases the node. The new test covers live titles and route replacement. - Timed cards use `content-visibility: auto` inside their fixed geometry. Off-screen contents skip work while buttons retain their names and native targets. [Chrome documents this CSS method](https://web.dev/articles/content-visibility). - The profile has an empty-page control, vsync histogram, renderer-only stage/task costs, thread CPU versus wall time, server binary SHA-256, idle file-hint counts, a busy-window flag and active job summaries from the real API. Summaries omit payloads and User identities. The job-summary field was added after the full capture; that capture's job state was checked through the private fixture Index. - Retained the original baseline; added round 4 measurements and decisions beside it. ### Files ```text packages/ui/src/components/ModeHeader.svelte packages/ui/src/components/calendar/GridColumn.svelte apps/web/src/lib/modeHeader.svelte.test.ts bench/week-scroll-1018.mjs bench/week-scroll-1018.test.mjs docs/perf/baseline.json docs/perf/week-scroll-1018.json docs/perf/week-scroll-1018.md ``` ### Measurements Every perf VM session held `/root/perf.lock` and recorded load. No build ran there. The final pair uses one branch-built server, the same Home and 650-day / 7,200-Log fixture, and immutable saved web builds. Application before: `7de6492ed`; after: `53bf81496`. Shared-server CURRENT was absent, so the branch server was built once. Its Rust source is unchanged. Before load: 0.01 / 0.16 / 0.20; after: 1.38 / 0.83 / 0.47. | Final pair | rAF p95 before → after | DrawFrame p95 before → after | | --- | --- | --- | | 1440 wheel, 10 days | 16.8 → 16.8 ms | 18.7 → 18.1 ms | | 1440 touch | 33.3 → 16.8 ms | 83.6 → 75.8 ms | | 820 wheel, 10 days | 16.8 → 16.8 ms | 17.2 → 18.3 ms | | 820 touch | 33.3 → 33.2 ms | 60.3 → 55.1 ms | | 1440 wheel, 60 days | 33.4 → 16.8 ms | 31.2 → 27.6 ms | 60-day renderer task CPU: 3.370 → 2.881 s. Raster wall duration: 1271.0 → 573.0 ms. The after run has 286 one-vsync intervals, 7 two-vsync intervals and 5 longer intervals. No >50 ms long task was observed in that after burst. Both full phases also contain live background hints, so this pair is not a quiet-only code attribution. The isolated card-visibility pair is cleaner: task CPU 2.401 → 2.288 s (-4.7%), raster wall 678.6 → 466.9 ms (-31.2%), DrawFrame p95 28.6 → 24.7 ms. Removing card paint containment, all card containment or column visibility skipping increased task CPU and kept compositor p95 around 30 ms. Those experiments were not shipped. Raster wall durations can overlap; they are not CPU totals. The baseline registry still retains round 1 (200.0 → 150.1 ms rAF p95, task CPU 3.024 → 2.281 s, raster wall 1135.5 → 1467.9 ms). The new round 4 entry points to its own matched pair. Do not attribute differences across sessions to one code change. ### Idle finding The unchanged-UI control has 0.025% and 0.039% renderer CPU with no file hints. A fresh fixture on that compatible prebuilt server has 0.033% and 0.044%. The branch-built server reproduces 19–37 file hints per two-second post-scroll window, with 0.36–1.84% CPU and zero layout/style passes. A no-hint final window has 0.043% CPU. The hints name Daily notes. The retained fixture has an active `notes.daily-log-projection-rebuild` (#724), plus migration/adoption notifications. These samples include background work; they are not quiet idle. No always-running client scroll or animation loop was found. Quiet CPU is already near zero. The benchmark now retains the missing context instead of reporting all settled-grid windows as equivalent idle. Live edits and background work are not suppressed. ### Gates (verbatim) `cargo fmt --check`: exit 0, no output. Rust code and API contracts did not change; per-crate Rust clippy/test are not applicable. `cd apps/web && bun run check`: ```text $ node scripts/check-user-storage.mjs && node scripts/check-type-tokens.mjs && node scripts/check-motion-tokens.mjs && svelte-kit sync && svelte-check --tsconfig ./tsconfig.json User browser caches use userStorage; only documented device/public-link exceptions remain. Text sizes and UI shape values use shared role tokens. UI transitions and animation options use shared motion tokens or documented exceptions. Loading svelte-check in workspace: /home/kayg/Developer/calternal-wt/weekscroll-1018/apps/web Getting Svelte diagnostics... svelte-check found 0 errors and 0 warnings ``` `cd apps/web && bunx vitest run src/lib/calendar/TimeGrid.svelte.test.ts src/lib/calendar/grid.test.ts src/lib/modeHeader.svelte.test.ts --maxWorkers=2`: ```text Test Files 3 passed (3) Tests 45 passed (45) ``` `node --test bench/week-scroll-1018.test.mjs`: ```text # tests 3 # suites 0 # pass 3 # fail 0 # cancelled 0 # skipped 0 # todo 0 ``` The real production profile used `--compare --assert` and passed: ```text week-scroll-1018: production fixture, native wheel/touch, 60-day scroll and bounded two-year traversal captured ``` Production web build passed. The unchanged coarse 60-day regression passed. No existing assertion or timing bound changed. Comments in every touched source file were read again. Cleanup: ```text Removed 7238 files, 4.6GiB total ``` Web build output, saved bundles and private fixture/session data were removed. Screenshots and traces remain as review artifacts and are attached, not committed. ### UX gaps closed - Live date titles no longer discard phone header collapse state or the known vertical offset. - Off-screen card contents skip rendering work without changing the timed hit box. - Native wheel/touch travel, zero track-alignment error, keyboard date navigation, reduced motion, selection, Space preview and Copy link pass on the real fixture. Popover glass remains active during horizontal travel. - Post-GC heap stays 10.5–11.9 MB through the two-year traversal, with eleven columns. - Before/final Week and Day evidence covers 390, 820 and 1440, Paper and Tokyo Night, with macOS emulation. No icon/text geometry was changed. Claude retains visual review. ### UX gaps left / known gaps - Strict p95 ≤16.7 ms is not met. rAF p95 reaches the empty-page floor, but compositor p95 is still 27.6 ms for the 60-day run. Touch delivery remains delayed. - Background projection/adoption work still consumes CPU and sends live hints. This is not claimed as a fixed server workload. - A newer prebuilt server did not become ready within five minutes; no sample from that attempt is used. A fresh-fixture confirmation on the branch-built server indexed all Logs but timed out applying Paper before timing; it is excluded. Logs are attached. No rerun loop followed either failure. - Safari, real macOS momentum, screen-reader behavior of off-screen card contents and full Undo/error/offline suites need the merge round. ### Decisions - Retain a scroller while its DOM node is connected. PageChrome identity is not route identity: the visible date changes it during one gesture. - Apply card visibility skipping inside the existing fixed timed boxes. Keep containment, rounding, sticky labels, shared motion durations and native scrolling. - Keep the strict target and existing regression thresholds. Record the empty-page floor and interval distribution instead of changing an assertion to pass. - Preserve busy post-scroll samples, but tag file activity and record the server binary and job context. Do not cancel real work to obtain a low CPU figure. - Add no dependency. Existing locked packages were used. ### For the merge round - `cd apps/web && bun run test --maxWorkers=2`: full web regressions. - `cd apps/web && bun run test:e2e:calendar && bun run test:e2e:weekstate-609`: native settlement, URL restoration, resizing, primary actions and keyboard behavior. - `cd apps/web && bun run test:e2e:calendar-crossday && bun run test:e2e:calendar-task-overflow && bun run test:e2e:calendar-doc-stack`: retained columns, narrow actions and attachment decks. - `cd apps/web && bun run test:e2e:a11y && bun run test:e2e:deeplinks`: names, states, focus and stable links; include off-screen cards. - `tests/adversarial/run-split.sh`: the combined server's adversarial matrices. This job adds no API endpoint. - `CALTERNAL_E2E_ASSET_OVERRIDE=1 CALTERNAL_SERVER_BIN=<combined-server> bun bench/week-scroll-1018.mjs --compare --assert --out artifacts/weekscroll-1018/merge-round`: the profile and unchanged coarse budget. Hold perf.lock on the perf VM and record active jobs. - On the locked Mac VM, check Safari card focus/sticky labels, timeline fallback and real fling delivery. ### Evidence - [round4-before-day-1440-paper.png](https://git.kayg.org/attachments/73cc6568-9d54-4953-a048-50a422c0d68f) - [round4-before-day-1440-tokyo-night.png](https://git.kayg.org/attachments/f753449d-c9ca-47f7-9bc7-5fd1b0d6266e) - [round4-before-day-390-paper.png](https://git.kayg.org/attachments/e3fba78b-6900-4b38-bf08-7d917a822bb9) - [round4-before-day-390-tokyo-night.png](https://git.kayg.org/attachments/81aef847-3e95-4937-b7e7-702ec7f78c72) - [round4-before-day-820-paper.png](https://git.kayg.org/attachments/6e58c753-585e-46ac-8099-6a5136ca2b61) - [round4-before-day-820-tokyo-night.png](https://git.kayg.org/attachments/9d7b8c3b-fa4e-475d-b6fb-26e4f30ed0a0) - [round4-before-week-1440-paper.png](https://git.kayg.org/attachments/acf516e4-a2fe-40f5-a4aa-3dd5cd276000) - [round4-before-week-1440-tokyo-night.png](https://git.kayg.org/attachments/79eb3417-143c-489d-bed6-2977c2b9cb85) - [round4-before-week-390-paper.png](https://git.kayg.org/attachments/7fdd46ce-0c93-44be-861e-2e5ce5e0d88a) - [round4-before-week-390-tokyo-night.png](https://git.kayg.org/attachments/78446e17-71cf-48a6-8a7f-c1d7a9a0bb02) - [round4-before-week-820-paper.png](https://git.kayg.org/attachments/7b59db85-09e1-416a-a224-ae44e22fadad) - [round4-before-week-820-tokyo-night.png](https://git.kayg.org/attachments/c969ba19-b1dd-4f03-bf56-49943caba8ce) - [round4-final-day-1440-paper.png](https://git.kayg.org/attachments/479ce58f-98ee-42e0-87f5-2f60e5e19a3a) - [round4-final-day-1440-tokyo-night.png](https://git.kayg.org/attachments/75fc753f-a21f-46fe-afdb-ced276a8779e) - [round4-final-day-390-paper.png](https://git.kayg.org/attachments/ec89fac8-f1ce-479f-9756-76b72bbe73d1) - [round4-final-day-390-tokyo-night.png](https://git.kayg.org/attachments/61888e3c-b581-4291-b4bc-d6b2059ddf98) - [round4-final-day-820-paper.png](https://git.kayg.org/attachments/9bc2d0a0-8282-49dc-a236-bb442ac02f82) - [round4-final-day-820-tokyo-night.png](https://git.kayg.org/attachments/7a9b9323-fd66-4c57-a4b1-bb994261a7d5) - [round4-final-week-1440-paper.png](https://git.kayg.org/attachments/00771785-39d9-411a-b677-e784b70a5ae7) - [round4-final-week-1440-tokyo-night.png](https://git.kayg.org/attachments/e9ebc398-afe4-4233-bc08-aa74615a66f1) - [round4-final-week-390-paper.png](https://git.kayg.org/attachments/29b634bd-6545-4bdb-ac40-d87fd9e9f5b3) - [round4-final-week-390-tokyo-night.png](https://git.kayg.org/attachments/9cd812a2-b9dd-462b-9e26-3ae121a0892a) - [round4-final-week-820-paper.png](https://git.kayg.org/attachments/79951a01-227b-4da0-b7de-2bc0c841fce6) - [round4-final-week-820-tokyo-night.png](https://git.kayg.org/attachments/8caaa7d1-16fe-4ece-be1c-ab17c35b1c12) - [round4-weekscroll-evidence.zip](https://git.kayg.org/attachments/1808cbb9-7e3e-4b40-92b2-d102dfcf5b8a)
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#1018
No description provided.