Web: stupid fast boot, list and typing (#327) #508

Closed
kayg wants to merge 12 commits from issue/327-web-fast into dev
Owner

This consolidates the web-speed work for issue #327 and replaces PRs #360, #394, #402, #407, and #454.

Changes

  • Added the browser performance harness and budgets for Homes with 10,000 and 100,000 notes.
  • Added the notes index and windowed list rows. The first note is served over plain HTTP, and fill pages are parsed in a worker and indexed in short, backpressured slices.
  • Kept editor updates incremental so typing does not copy the full note text on every key. The preview updates in place.
  • Spread remaining startup work out after the first note appears.

Measurements

Chromium at 4x CPU; four interleaved rounds on current dev 312bc892 and this branch 85eadf8. Values are linear-interpolated p50/p95. Boot and post-boot browse metrics have four samples; typing has 672 samples; CLS has eight. Cold TBT starts at first contentful paint; cold blocked time starts at navigation. The longest-task row is the maximum during the post-boot 50-note browse pass.

metric Home unit current dev p50/p95 this branch p50/p95
Cold time to first note 10k ms 3640.4/4656.4 2319.4/3005.1
Cold TBT 10k ms 2072.9/2846.1 506.5/882.7
Cold blocked from navigation 10k ms 2932.5/4125.1 1463.0/2236.0
Warm TBT 10k ms 1779.5/2354.8 235.2/353.8
Long-note typing 10k ms 152.6/326.9 154.2/304.0
Nested-list typing 10k ms 280.6/1006.3 250.5/646.3
Layout shift (CLS) 10k score 0.0/0.0 0.0/0.0
Post-boot longest task 10k ms 296.0/361.6 352.0/420.4
Cold time to first note 100k ms 4037.3/4965.5 2694.1/2755.5
Cold TBT 100k ms 22616.2/24484.6 598.4/761.9
Cold blocked from navigation 100k ms 23610.5/25815.7 1888.0/2083.1
Warm TBT 100k ms 21666.5/23123.3 416.9/548.9
Long-note typing 100k ms 155.0/337.6 155.3/297.2
Nested-list typing 100k ms 263.5/839.0 279.6/782.5
Layout shift (CLS) 100k score 0.0/0.0 0.0/0.0
Post-boot longest task 100k ms 565.0/773.4 455.5/523.7

Boot blocking fell substantially at both sizes. Long-note typing p50 stayed nearly unchanged; nested-list p95 improved at both sizes, while 100k nested-list p50 rose by 16 ms. The post-boot browse task improved at 100k and rose at 10k.

The background fill check passed four repeats at each size. Each run processed two complete 2,000-note pages with no size mismatches, using 500 indexing slices. The largest slice was 8.9 ms at 10k and 12.3 ms at 100k. All eight runs recorded zero fill-overlap tasks, zero fill tasks over 50 ms, and zero after-boot tasks over 50 ms.

Checks

  • svelte-check found 0 errors and 12 warnings in 7 files
  • Test Files 17 passed (17); Tests 130 passed (130)
  • Chromium 1440: 10 failed, 258 skipped, 46 passed (6.2m). All failures match the clean dev baseline.
  • WebKit 1440: 13 failed, 260 skipped, 41 passed (17.9m). Nine failures match the clean dev baseline. The other four failed only in the full run under host load; all four passed when rerun separately on both clean dev and this branch.
  • Chromium 390: 8 failed, 16 skipped, 290 passed (15.9m). All failures match the clean dev baseline.
This consolidates the web-speed work for issue #327 and replaces PRs #360, #394, #402, #407, and #454. ## Changes - Added the browser performance harness and budgets for Homes with 10,000 and 100,000 notes. - Added the notes index and windowed list rows. The first note is served over plain HTTP, and fill pages are parsed in a worker and indexed in short, backpressured slices. - Kept editor updates incremental so typing does not copy the full note text on every key. The preview updates in place. - Spread remaining startup work out after the first note appears. ## Measurements Chromium at 4x CPU; four interleaved rounds on current dev `312bc892` and this branch `85eadf8`. Values are linear-interpolated p50/p95. Boot and post-boot browse metrics have four samples; typing has 672 samples; CLS has eight. Cold TBT starts at first contentful paint; cold blocked time starts at navigation. The longest-task row is the maximum during the post-boot 50-note browse pass. | metric | Home | unit | current dev p50/p95 | this branch p50/p95 | |---|---:|---|---:|---:| | Cold time to first note | 10k | ms | 3640.4/4656.4 | 2319.4/3005.1 | | Cold TBT | 10k | ms | 2072.9/2846.1 | 506.5/882.7 | | Cold blocked from navigation | 10k | ms | 2932.5/4125.1 | 1463.0/2236.0 | | Warm TBT | 10k | ms | 1779.5/2354.8 | 235.2/353.8 | | Long-note typing | 10k | ms | 152.6/326.9 | 154.2/304.0 | | Nested-list typing | 10k | ms | 280.6/1006.3 | 250.5/646.3 | | Layout shift (CLS) | 10k | score | 0.0/0.0 | 0.0/0.0 | | Post-boot longest task | 10k | ms | 296.0/361.6 | 352.0/420.4 | | Cold time to first note | 100k | ms | 4037.3/4965.5 | 2694.1/2755.5 | | Cold TBT | 100k | ms | 22616.2/24484.6 | 598.4/761.9 | | Cold blocked from navigation | 100k | ms | 23610.5/25815.7 | 1888.0/2083.1 | | Warm TBT | 100k | ms | 21666.5/23123.3 | 416.9/548.9 | | Long-note typing | 100k | ms | 155.0/337.6 | 155.3/297.2 | | Nested-list typing | 100k | ms | 263.5/839.0 | 279.6/782.5 | | Layout shift (CLS) | 100k | score | 0.0/0.0 | 0.0/0.0 | | Post-boot longest task | 100k | ms | 565.0/773.4 | 455.5/523.7 | Boot blocking fell substantially at both sizes. Long-note typing p50 stayed nearly unchanged; nested-list p95 improved at both sizes, while 100k nested-list p50 rose by 16 ms. The post-boot browse task improved at 100k and rose at 10k. The background fill check passed four repeats at each size. Each run processed two complete 2,000-note pages with no size mismatches, using 500 indexing slices. The largest slice was 8.9 ms at 10k and 12.3 ms at 100k. All eight runs recorded zero fill-overlap tasks, zero fill tasks over 50 ms, and zero after-boot tasks over 50 ms. ## Checks - `svelte-check found 0 errors and 12 warnings in 7 files` - `Test Files 17 passed (17)`; `Tests 130 passed (130)` - Chromium 1440: `10 failed`, `258 skipped`, `46 passed` (6.2m). All failures match the clean dev baseline. - WebKit 1440: `13 failed`, `260 skipped`, `41 passed` (17.9m). Nine failures match the clean dev baseline. The other four failed only in the full run under host load; all four passed when rerun separately on both clean dev and this branch. - Chromium 390: `8 failed`, `16 skipped`, `290 passed` (15.9m). All failures match the clean dev baseline.
kayg added 12 commits 2026-10-16 17:34:51 +00:00
perf/web.sh measures the built app as production serves it on 10k and 100k
fixture Homes, Chromium (CPU 4x) and WebKit: bundle sizes, boot (TBT as
web.dev defines it, every long task, first paint, time to interactive),
keystroke to paint, the blaze test (#271), scrolling, memory, layout shift
and main-thread CPU. web.* budgets in perf/budgets.json; CI gates the
bundle sizes. docs/perf/web.md.

Replaces #360.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018Yyy8fQGxPLkLa8v8NXz7T
- frontmatterEnd walks lines without copying and remembers per document.
- The note metadata keeps `base` under its own key, written only when it
  changed (older records still read).
- A preview whose text matches the live document swaps its binding in
  place (a compartment) instead of building and parsing a new state.
- Clouds worked out in slices (lib/slices.ts), date labels morph only once
  tapped, the offline merge code loads only when a merge runs.

Replaces #402 and part of #454.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018Yyy8fQGxPLkLa8v8NXz7T
- lib/notes-index.ts: notes newest first by binary search, tag counts,
  file to id, the Journal's order; views are told once per batch.
- groups() slices ordered lists by binary search; NoteList works out its
  visible rows from group sizes (lib/list-window.ts). Nothing walks every
  note on the main thread.
- The background fill (#422, pages of 2000) is fetched and parsed in a
  worker (lib/notes-fill.worker.ts) and handed over 250 notes at a time;
  without a worker, pages of 500 the plain way.
- The first note's text comes over plain HTTP (notes.peek) when nothing is
  remembered, instead of waiting for its room; peeks come 12 at a time.
- Typing: properties re-read only when an edit reaches them, the bar's
  block list replaced only when it held something.
- Theme colour once per frame; the Settings bar builds at the next idle.

Replaces #394, #407 and the rest of #454.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018Yyy8fQGxPLkLa8v8NXz7T
Fill pages are fetched by a worker now, whose requests the page doesn't
always see: the app marks html[data-listed] when the whole list is in, and
the harness waits for it (builds without the fill worker: request silence).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018Yyy8fQGxPLkLa8v8NXz7T
Perf: slice notes fill work on the page
Some checks failed
CI / server (pull_request) Successful in 21s
CI / rust (pull_request) Successful in 1m41s
CI / web (pull_request) Failing after 48m9s
85eadf8201
Author
Owner

Superseded by PR #515: #515. The replacement is rebased onto current dev and includes the issue #327 work with the issue #448 links fix.

Superseded by PR #515: https://git.kayg.org/kayg/calternal/pulls/515. The replacement is rebased onto current dev and includes the issue #327 work with the issue #448 links fix.
kayg closed this pull request 2026-10-16 23:10:37 +00:00
Some checks failed
CI / server (pull_request) Successful in 21s
CI / rust (pull_request) Successful in 1m41s
CI / web (pull_request) Failing after 48m9s

Pull request closed

Sign in to join this conversation.
No reviewers
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!508
No description provided.