Notes: 5,000-block Note opens in about 7 s, typing p95 171 ms, heap doubles in 5 minutes #1349

Closed
opened 2026-10-07 10:31:00 +00:00 by kayg · 50 comments
Owner

From bash-notes round 2 (#1216), local DEBUG server, host load 27-38 (provisional; confirm on the perf VM with a release build):
5,000-block Note (499,898 bytes): open 6,910 ms; scroll frame p95 16.8 ms; keydown-to-paint p50 76.9 ms / p95 171.5 ms; heap 27.7 MB before and 56.9 MB after five minutes of typing; 60/60 typing bursts saved, the last after 34.3 s.
Budgets (DESIGN §59): open from cache <= 100 ms, first usable view with 10,000 items <= 1.5 s, action input to visible state <= 150 ms, and the editor should keep typing at frame rate. Heap doubling during 5 minutes of typing needs a leak check (undo history bound, collab update log, decorations).
Steps: measure on the perf VM (release build, bench/hdd-emu.sh), profile open and typing, fix the top causes (likely: full-document parse/render on open instead of incremental or virtualised rendering; per-keystroke work proportional to document size; unbounded history), regression budget test.

From bash-notes round 2 (#1216), local DEBUG server, host load 27-38 (provisional; confirm on the perf VM with a release build): 5,000-block Note (499,898 bytes): open 6,910 ms; scroll frame p95 16.8 ms; keydown-to-paint p50 76.9 ms / p95 171.5 ms; heap 27.7 MB before and 56.9 MB after five minutes of typing; 60/60 typing bursts saved, the last after 34.3 s. Budgets (DESIGN §59): open from cache <= 100 ms, first usable view with 10,000 items <= 1.5 s, action input to visible state <= 150 ms, and the editor should keep typing at frame rate. Heap doubling during 5 minutes of typing needs a leak check (undo history bound, collab update log, decorations). Steps: measure on the perf VM (release build, bench/hdd-emu.sh), profile open and typing, fix the top causes (likely: full-document parse/render on open instead of incremental or virtualised rendering; per-keystroke work proportional to document size; unbounded history), regression budget test.
Author
Owner

Starting #1349 on branch job/bignote-1349, based on 0419170fe456b58614befcb12d9c9d255118f1c0 (origin/dev).

Starting #1349 on branch `job/bignote-1349`, based on `0419170fe456b58614befcb12d9c9d255118f1c0` (origin/dev).
Author
Owner

Corrected local diagnostic before any production changes: on the release server binary for baseline 0419170fe, a 5,000-block Note took 6.36 s to become editable and 7.86 s to render all paragraphs. Four keydown-to-next-frame samples per position measured p95 328 ms at the start, 566 ms in the middle, and 883 ms at the end; the separate 23-sample middle typing trace measured p95 344 ms. This fails the 1.5 s open and 50 ms input budgets. The host load average was 28.11 / 39.60 / 38.72. This is diagnostic evidence only, not the requested full baseline: the run was local, the perf VM was occupied, and the HDD emulator is unmounted ( is unavailable). I am validating persistence and will post the full 5k/20k table and traces before changing production code.

Corrected local diagnostic before any production changes: on the release server binary for baseline 0419170fe, a 5,000-block Note took 6.36 s to become editable and 7.86 s to render all paragraphs. Four keydown-to-next-frame samples per position measured p95 328 ms at the start, 566 ms in the middle, and 883 ms at the end; the separate 23-sample middle typing trace measured p95 344 ms. This fails the 1.5 s open and 50 ms input budgets. The host load average was 28.11 / 39.60 / 38.72. This is diagnostic evidence only, not the requested full baseline: the run was local, the perf VM was occupied, and the HDD emulator is unmounted ( is unavailable). I am validating persistence and will post the full 5k/20k table and traces before changing production code.
Author
Owner

Perf VM smoke profile with the production build and release server, backed by the mounted HDD emulator: load average 1.91 / 1.99 / 1.51 before and 5.55 / 3.17 / 1.98 after. The 5,000-block Note reached editable view in 2.85 s and fully rendered in 2.97 s. With two diagnostic samples per position, keydown-to-paint p95 was 132 ms at start, 54 ms middle, and 70 ms end; the 24-sample middle typing trace p95 was 143 ms; scroll frame p95 was 167 ms. The 5-second typing smoke inserted 30 keys after 30 positioning/trace keys; all 60 were present in the Note API. The final save marker reached the API in 56.8 s. This is not the full baseline: the five-minute typing run and 20,000-block Note remain to be measured. No production files have changed.

Perf VM smoke profile with the production build and release server, backed by the mounted HDD emulator: load average 1.91 / 1.99 / 1.51 before and 5.55 / 3.17 / 1.98 after. The 5,000-block Note reached editable view in 2.85 s and fully rendered in 2.97 s. With two diagnostic samples per position, keydown-to-paint p95 was 132 ms at start, 54 ms middle, and 70 ms end; the 24-sample middle typing trace p95 was 143 ms; scroll frame p95 was 167 ms. The 5-second typing smoke inserted 30 keys after 30 positioning/trace keys; all 60 were present in the Note API. The final save marker reached the API in 56.8 s. This is not the full baseline: the five-minute typing run and 20,000-block Note remain to be measured. No production files have changed.
Author
Owner

Trace and source finding before production changes: the 5,000-block perf-VM typing trace sampled ProseMirror nodesBetween and forChild work. The shared editor has three matching full-document paths: BlockAnchorOwners walks every descendant after each document-changing transaction; BlockIdAnchorDecoration rebuilds hidden block-ID ranges from every descendant during decoration, keydown, copy, and cut handling; EmptyBlockHints checks every top-level child whenever ProseMirror asks for decorations. These paths do linear work per edit or key even when a Note has no block IDs. The full 5k/20k baseline is still running under the perf-run lock. I will post the complete measurements before editing production code.

Trace and source finding before production changes: the 5,000-block perf-VM typing trace sampled ProseMirror nodesBetween and forChild work. The shared editor has three matching full-document paths: BlockAnchorOwners walks every descendant after each document-changing transaction; BlockIdAnchorDecoration rebuilds hidden block-ID ranges from every descendant during decoration, keydown, copy, and cut handling; EmptyBlockHints checks every top-level child whenever ProseMirror asks for decorations. These paths do linear work per edit or key even when a Note has no block IDs. The full 5k/20k baseline is still running under the perf-run lock. I will post the complete measurements before editing production code.
Author
Owner

Full perf-VM 5,000-block baseline at 0419170fe: usable view 2.706 s; fully rendered 2.789 s; keydown-to-paint p95 82 ms / 109 ms / 129 ms (start / middle / end); scroll frame p95 166.6 ms. After five minutes, renderer heap was 47.9 MB at start and 35.7 MB at end (-25.4%); browser-tree RSS stayed around 850-865 MB, while server RSS rose from 997 MB at 30 s to 1,278 MB at 300 s. The 5-minute run entered 1,842 sustained keys, for 1,962 total expected z characters including the 120 positioning/trace keys. At the 60-second save deadline, the live editor had all 1,962 and the final marker, but the Note API returned 1,716 z characters and no marker. This proves the save was not visible within 60 seconds; it does not yet prove permanent keystroke loss. I am extending the save probe to distinguish a slow save from missing updates. The 20,000-block profile and full baseline table are pending; no production code has changed.

Full perf-VM 5,000-block baseline at 0419170fe: usable view 2.706 s; fully rendered 2.789 s; keydown-to-paint p95 82 ms / 109 ms / 129 ms (start / middle / end); scroll frame p95 166.6 ms. After five minutes, renderer heap was 47.9 MB at start and 35.7 MB at end (-25.4%); browser-tree RSS stayed around 850-865 MB, while server RSS rose from 997 MB at 30 s to 1,278 MB at 300 s. The 5-minute run entered 1,842 sustained keys, for 1,962 total expected z characters including the 120 positioning/trace keys. At the 60-second save deadline, the live editor had all 1,962 and the final marker, but the Note API returned 1,716 z characters and no marker. This proves the save was not visible within 60 seconds; it does not yet prove permanent keystroke loss. I am extending the save probe to distinguish a slow save from missing updates. The 20,000-block profile and full baseline table are pending; no production code has changed.
Author
Owner

The initial 5,000-block run was a single-open pilot, so I did not treat it as the §59 baseline. I updated bench/bignote-1349.mjs to report five first-open samples for distinct Notes and five same-Note warm reopen samples, with first-usable paint and full-render p50/p95/max. A local production-build smoke passed this flow and persisted all 147 expected z keys plus the save marker after 43.9 s. The local host load was 11.43/19.63/25.92, so these timings are harness evidence only, not the perf baseline. No editor implementation changes have started; the corrected perf VM baseline is still pending.

The initial 5,000-block run was a single-open pilot, so I did not treat it as the §59 baseline. I updated `bench/bignote-1349.mjs` to report five first-open samples for distinct Notes and five same-Note warm reopen samples, with first-usable paint and full-render p50/p95/max. A local production-build smoke passed this flow and persisted all 147 expected `z` keys plus the save marker after 43.9 s. The local host load was 11.43/19.63/25.92, so these timings are harness evidence only, not the perf baseline. No editor implementation changes have started; the corrected perf VM baseline is still pending.
Author
Owner

The corrected perf VM run has completed the five cold and five warm 5,000-block opens and the start/middle/end typing samples. Cold first-usable paint is 1,652 ms p50 / 2,984.9 ms p95; warm reopen is 1,094.7 / 1,409.3 ms. Keydown-to-paint p95 is 97.5 ms at the start, 108.6 ms in the middle, and 98.7 ms at the end. The typing CPU profile samples forChild, nodesBetween and ProseMirror child lookup repeatedly; extensions.ts has full-document scans in BlockAnchorOwners, BlockIdAnchorDecoration, and EmptyBlockHints. The five-minute run and 20,000-block profile are still running, so this is interim evidence; no editor code has changed.

The corrected perf VM run has completed the five cold and five warm 5,000-block opens and the start/middle/end typing samples. Cold first-usable paint is 1,652 ms p50 / 2,984.9 ms p95; warm reopen is 1,094.7 / 1,409.3 ms. Keydown-to-paint p95 is 97.5 ms at the start, 108.6 ms in the middle, and 98.7 ms at the end. The typing CPU profile samples `forChild`, `nodesBetween` and ProseMirror child lookup repeatedly; `extensions.ts` has full-document scans in BlockAnchorOwners, BlockIdAnchorDecoration, and EmptyBlockHints. The five-minute run and 20,000-block profile are still running, so this is interim evidence; no editor code has changed.
Author
Owner

The perf VM baseline completed the 5,000-block profile: after five minutes and 1,934 sustained key presses, the live Note and Note API both contained all 2,054 expected z keys, and the marker reached the API in 81.8 s. Renderer heap growth was 2.8%. The 20,000-block profile failed before typing: after clicking the first 20,000-block Note, .editor-surface[data-editor-ready="true"] did not become visible within 120 s. The profile recorded the timeout and released the perf lock. I have not changed editor code; I am isolating the 20,000-block open to determine whether this is a slow open or a surfaced error.

The perf VM baseline completed the 5,000-block profile: after five minutes and 1,934 sustained key presses, the live Note and Note API both contained all 2,054 expected `z` keys, and the marker reached the API in 81.8 s. Renderer heap growth was 2.8%. The 20,000-block profile failed before typing: after clicking the first 20,000-block Note, `.editor-surface[data-editor-ready="true"]` did not become visible within 120 s. The profile recorded the timeout and released the perf lock. I have not changed editor code; I am isolating the 20,000-block open to determine whether this is a slow open or a surfaced error.
Author
Owner

The isolated 20,000-block profile has completed its open, typing and scroll samples. First-usable paint is 4,577.8 ms p50 / 4,779.6 ms p95 for cold content opens and 2,782.8 / 4,180.9 ms for warm reopens. Keydown-to-paint p95 is 191.6 ms at the start, 227.2 ms in the middle, and 270.0 ms at the end; scroll-frame p95 is 316.6 ms. Renderer heap is 26.3% lower at the five-minute endpoint than at start. The trace samples forChild for 866.8 ms across the typing capture, with repeated ProseMirror traversal calls. The final API save check is still pending; no editor code has changed.

The isolated 20,000-block profile has completed its open, typing and scroll samples. First-usable paint is 4,577.8 ms p50 / 4,779.6 ms p95 for cold content opens and 2,782.8 / 4,180.9 ms for warm reopens. Keydown-to-paint p95 is 191.6 ms at the start, 227.2 ms in the middle, and 270.0 ms at the end; scroll-frame p95 is 316.6 ms. Renderer heap is 26.3% lower at the five-minute endpoint than at start. The trace samples `forChild` for 866.8 ms across the typing capture, with repeated ProseMirror traversal calls. The final API save check is still pending; no editor code has changed.
Author
Owner

Baseline before editor changes

Measured with the release server, production web build, Chromium at 1440×900, and bench/hdd-emu.sh (8 ms read/write delay, 200 IOPS). Each size ran in its own fresh server/browser session under perf-run to avoid cross-size cache and memory contamination. Five first opens of distinct Notes and five same-Note warm reopens were recorded. Typing samples use 32 keys at each document position. Load average at lock-held command start was 1.06/3.99/4.14 for 5,000 blocks and 1.82/3.60/4.46 for 20,000 blocks.

Open and interaction latency (ms; p50 / p95 / max)

Blocks Open path First usable paint Fully rendered
5,000 Cold Note 1,652 / 2,984.9 / 2,984.9 1,653.5 / 2,986.6 / 2,986.6
5,000 Warm reopen 1,094.7 / 1,409.3 / 1,409.3 1,096 / 1,410.8 / 1,410.8
20,000 Cold Note 4,577.8 / 4,779.6 / 4,779.6 4,581 / 4,782.1 / 4,782.1
20,000 Warm reopen 2,782.8 / 4,180.9 / 4,180.9 2,784.8 / 4,183.5 / 4,183.5
Blocks Typing position Keydown to paint (p50 / p95 / max)
5,000 Start 28 / 97.5 / 103.4
5,000 Middle 43.1 / 108.6 / 128.7
5,000 End 36.6 / 98.7 / 101.6
20,000 Start 153 / 191.6 / 218
20,000 Middle 177 / 227.2 / 387.9
20,000 End 200.1 / 270 / 278.7

Scroll-frame p50/p95/max was 66.7/150/183.4 ms at 5,000 blocks (101 frames) and 116.7/316.6/366.6 ms at 20,000 blocks (98 frames).

Five-minute typing memory and save

The browser heap column is renderer JS heap; RSS columns are process-tree totals, all in MiB at 30-second intervals.

Elapsed 5k heap / browser RSS / server RSS 20k heap / browser RSS / server RSS
30 s 44.6 / 909.9 / 1,054.0 86.4 / 1,658.1 / 2,160.1
60 s 43.2 / 896.6 / 1,104.4 94.9 / 1,668.9 / 2,234.0
90 s 52.1 / 903.1 / 1,113.5 88.9 / 1,669.1 / 2,255.5
120 s 44.4 / 901.5 / 1,137.1 62.7 / 1,652.0 / 2,281.0
150 s 50.3 / 898.0 / 1,165.6 66.4 / 1,636.6 / 2,303.5
180 s 27.7 / 895.4 / 1,192.2 73.9 / 1,637.9 / 2,307.9
210 s 25.2 / 902.8 / 1,215.3 65.8 / 1,639.0 / 2,378.9
240 s 46.2 / 900.2 / 1,230.0 74.4 / 1,640.0 / 2,376.6
270 s 51.6 / 899.8 / 1,234.4 53.9 / 1,643.4 / 2,386.6
300 s 29.8 / 905.2 / 1,247.4 51.8 / 1,639.0 / 2,399.2
Blocks Sustained keys Heap change Save marker latency Persisted keys
5,000 1,934 +2.8% (29.0 → 29.8 MiB) 81.8 s 2,054 / 2,054; complete
20,000 716 −26.3% (70.3 → 51.8 MiB) 107.2 s 836 / 836; complete

The browser process-tree peak was 905.2 MiB at 5,000 blocks and 1,718.7 MiB at 20,000 blocks. Server RSS at the final sample was 1,247.4 MiB and 2,399.2 MiB respectively.

Trace finding

The typing traces repeatedly sample ProseMirror forChild, nodesBetween, child lookup and findIndex. Source review found full-document work on edits/redraws in BlockAnchorOwners, BlockIdAnchorDecoration, and EmptyBlockHints in packages/editor/src/extensions.ts. These are the first targets for the fix. No production editor code has changed yet.

Artifacts on the perf VM:

  • 5k result: /root/calternal-bignote-1349/artifacts/bignote-1349/before-sampled.json
  • 5k open trace: /root/calternal-bignote-1349/artifacts/bignote-1349/before-sampled-open-5000.chrome-trace.json
  • 5k typing trace: /root/calternal-bignote-1349/artifacts/bignote-1349/before-sampled-typing-2500-24.chrome-trace.json
  • 20k result: /root/calternal-bignote-1349/artifacts/bignote-1349/before-20000.json
  • 20k open trace: /root/calternal-bignote-1349/artifacts/bignote-1349/before-20000-open-20000.chrome-trace.json
  • 20k typing trace: /root/calternal-bignote-1349/artifacts/bignote-1349/before-20000-typing-10000-24.chrome-trace.json
## Baseline before editor changes Measured with the release server, production web build, Chromium at 1440×900, and `bench/hdd-emu.sh` (8 ms read/write delay, 200 IOPS). Each size ran in its own fresh server/browser session under `perf-run` to avoid cross-size cache and memory contamination. Five first opens of distinct Notes and five same-Note warm reopens were recorded. Typing samples use 32 keys at each document position. Load average at lock-held command start was 1.06/3.99/4.14 for 5,000 blocks and 1.82/3.60/4.46 for 20,000 blocks. ### Open and interaction latency (ms; p50 / p95 / max) | Blocks | Open path | First usable paint | Fully rendered | | ---: | --- | ---: | ---: | | 5,000 | Cold Note | 1,652 / 2,984.9 / 2,984.9 | 1,653.5 / 2,986.6 / 2,986.6 | | 5,000 | Warm reopen | 1,094.7 / 1,409.3 / 1,409.3 | 1,096 / 1,410.8 / 1,410.8 | | 20,000 | Cold Note | 4,577.8 / 4,779.6 / 4,779.6 | 4,581 / 4,782.1 / 4,782.1 | | 20,000 | Warm reopen | 2,782.8 / 4,180.9 / 4,180.9 | 2,784.8 / 4,183.5 / 4,183.5 | | Blocks | Typing position | Keydown to paint (p50 / p95 / max) | | ---: | --- | ---: | | 5,000 | Start | 28 / 97.5 / 103.4 | | 5,000 | Middle | 43.1 / 108.6 / 128.7 | | 5,000 | End | 36.6 / 98.7 / 101.6 | | 20,000 | Start | 153 / 191.6 / 218 | | 20,000 | Middle | 177 / 227.2 / 387.9 | | 20,000 | End | 200.1 / 270 / 278.7 | Scroll-frame p50/p95/max was 66.7/150/183.4 ms at 5,000 blocks (101 frames) and 116.7/316.6/366.6 ms at 20,000 blocks (98 frames). ### Five-minute typing memory and save The browser heap column is renderer JS heap; RSS columns are process-tree totals, all in MiB at 30-second intervals. | Elapsed | 5k heap / browser RSS / server RSS | 20k heap / browser RSS / server RSS | | ---: | ---: | ---: | | 30 s | 44.6 / 909.9 / 1,054.0 | 86.4 / 1,658.1 / 2,160.1 | | 60 s | 43.2 / 896.6 / 1,104.4 | 94.9 / 1,668.9 / 2,234.0 | | 90 s | 52.1 / 903.1 / 1,113.5 | 88.9 / 1,669.1 / 2,255.5 | | 120 s | 44.4 / 901.5 / 1,137.1 | 62.7 / 1,652.0 / 2,281.0 | | 150 s | 50.3 / 898.0 / 1,165.6 | 66.4 / 1,636.6 / 2,303.5 | | 180 s | 27.7 / 895.4 / 1,192.2 | 73.9 / 1,637.9 / 2,307.9 | | 210 s | 25.2 / 902.8 / 1,215.3 | 65.8 / 1,639.0 / 2,378.9 | | 240 s | 46.2 / 900.2 / 1,230.0 | 74.4 / 1,640.0 / 2,376.6 | | 270 s | 51.6 / 899.8 / 1,234.4 | 53.9 / 1,643.4 / 2,386.6 | | 300 s | 29.8 / 905.2 / 1,247.4 | 51.8 / 1,639.0 / 2,399.2 | | Blocks | Sustained keys | Heap change | Save marker latency | Persisted keys | | ---: | ---: | ---: | ---: | --- | | 5,000 | 1,934 | +2.8% (29.0 → 29.8 MiB) | 81.8 s | 2,054 / 2,054; complete | | 20,000 | 716 | −26.3% (70.3 → 51.8 MiB) | 107.2 s | 836 / 836; complete | The browser process-tree peak was 905.2 MiB at 5,000 blocks and 1,718.7 MiB at 20,000 blocks. Server RSS at the final sample was 1,247.4 MiB and 2,399.2 MiB respectively. ### Trace finding The typing traces repeatedly sample ProseMirror `forChild`, `nodesBetween`, child lookup and `findIndex`. Source review found full-document work on edits/redraws in `BlockAnchorOwners`, `BlockIdAnchorDecoration`, and `EmptyBlockHints` in `packages/editor/src/extensions.ts`. These are the first targets for the fix. No production editor code has changed yet. Artifacts on the perf VM: - 5k result: `/root/calternal-bignote-1349/artifacts/bignote-1349/before-sampled.json` - 5k open trace: `/root/calternal-bignote-1349/artifacts/bignote-1349/before-sampled-open-5000.chrome-trace.json` - 5k typing trace: `/root/calternal-bignote-1349/artifacts/bignote-1349/before-sampled-typing-2500-24.chrome-trace.json` - 20k result: `/root/calternal-bignote-1349/artifacts/bignote-1349/before-20000.json` - 20k open trace: `/root/calternal-bignote-1349/artifacts/bignote-1349/before-20000-open-20000.chrome-trace.json` - 20k typing trace: `/root/calternal-bignote-1349/artifacts/bignote-1349/before-20000-typing-10000-24.chrome-trace.json`
Author
Owner

Full web test gate update after merging origin/dev: Vitest has reported failures in three unrelated UI suites: src/lib/calendar/TimeGrid.svelte.test.ts (1/16, “opens the shared anchored surface with every all-day event and task in a 1-day view”), src/routes/settings/connected-accounts/ConnectedAccountsSection.svelte.test.ts (4/11), and src/routes/settings/apps/CalendarFeedsGroup.svelte.test.ts (1/4, “freezes edits and retries the complete submitted body after assertion”). The full bun run test process is still running; I will report its final exit and summary when it finishes. These files are outside #1349’s editor ownership, so I have not changed their assertions or implementation.

Full web test gate update after merging origin/dev: Vitest has reported failures in three unrelated UI suites: `src/lib/calendar/TimeGrid.svelte.test.ts` (1/16, “opens the shared anchored surface with every all-day event and task in a 1-day view”), `src/routes/settings/connected-accounts/ConnectedAccountsSection.svelte.test.ts` (4/11), and `src/routes/settings/apps/CalendarFeedsGroup.svelte.test.ts` (1/4, “freezes edits and retries the complete submitted body after assertion”). The full `bun run test` process is still running; I will report its final exit and summary when it finishes. These files are outside #1349’s editor ownership, so I have not changed their assertions or implementation.
Author
Owner

Further failures in the same still-running bun run test: src/routes/settings/account/PasskeysGroup.svelte.test.ts (2/2, both OIDC-only first-passkey flows) and src/routes/settings/account/AppPasswordsGroup.svelte.test.ts (1/3, “grants Calendar, Notes and Mail through the ordinary device choice”). Together with the three suites reported above, all five failing files are outside #1349’s editor ownership. I am preserving their existing code and assertions; the final Vitest aggregate is pending.

Further failures in the same still-running `bun run test`: `src/routes/settings/account/PasskeysGroup.svelte.test.ts` (2/2, both OIDC-only first-passkey flows) and `src/routes/settings/account/AppPasswordsGroup.svelte.test.ts` (1/3, “grants Calendar, Notes and Mail through the ordinary device choice”). Together with the three suites reported above, all five failing files are outside #1349’s editor ownership. I am preserving their existing code and assertions; the final Vitest aggregate is pending.
Author
Owner

Full bun run test gate completed after the origin/dev merge. Exact Vitest aggregate:

Test Files  5 failed | 288 passed (293)
     Tests  9 failed | 2094 passed (2103)
   Start at  23:17:14
  Duration  1415.06s (transform 30%, environment 26%, import 21%, tests 17%, setup 6%)

The failing files are src/lib/calendar/TimeGrid.svelte.test.ts, src/routes/settings/account/ConnectedAccountsSection.svelte.test.ts, src/routes/settings/apps/CalendarFeedsGroup.svelte.test.ts, src/routes/settings/account/PasskeysGroup.svelte.test.ts, and src/routes/settings/account/AppPasswordsGroup.svelte.test.ts. Eight reported failures are Vitest's 5000ms timeout; one Passkeys case asserts the missing “Single sign-on” label. I did not alter these unrelated tests or their expectations. The command exited with error: script "test" exited with code 1.

Full `bun run test` gate completed after the origin/dev merge. Exact Vitest aggregate: ```text Test Files 5 failed | 288 passed (293) Tests 9 failed | 2094 passed (2103) Start at 23:17:14 Duration 1415.06s (transform 30%, environment 26%, import 21%, tests 17%, setup 6%) ``` The failing files are `src/lib/calendar/TimeGrid.svelte.test.ts`, `src/routes/settings/account/ConnectedAccountsSection.svelte.test.ts`, `src/routes/settings/apps/CalendarFeedsGroup.svelte.test.ts`, `src/routes/settings/account/PasskeysGroup.svelte.test.ts`, and `src/routes/settings/account/AppPasswordsGroup.svelte.test.ts`. Eight reported failures are Vitest's 5000ms timeout; one Passkeys case asserts the missing “Single sign-on” label. I did not alter these unrelated tests or their expectations. The command exited with `error: script "test" exited with code 1`.
Author
Owner

After-profile interim finding from the first 5,000-block Note (after.json, while 20,000-block run is pending): cold open p95 is 3,103.1 ms; keydown-to-paint p95 is 46.2 ms at start, 91.6 ms in the middle, and 112.5 ms at the end; scroll frame p95 is 150 ms. The open trace has Layout events of 170.9 ms (10,101 dirty of 10,379 objects) and 126.1 ms (10,112 dirty of 10,485 objects). The rendered Note has 5,001 paragraphs and about 12,900 DOM nodes. This shows full-document layout remains a measured cost after the transaction-local decoration fix. At 300 seconds, sustained typing had entered 1,990 keys, heap growth was 7.9%, and the 5k save completed in 87.45 seconds with all input keys persisted. I will include the complete 5k/20k after table after the locked run finishes.

After-profile interim finding from the first 5,000-block Note (`after.json`, while 20,000-block run is pending): cold open p95 is 3,103.1 ms; keydown-to-paint p95 is 46.2 ms at start, 91.6 ms in the middle, and 112.5 ms at the end; scroll frame p95 is 150 ms. The open trace has Layout events of 170.9 ms (10,101 dirty of 10,379 objects) and 126.1 ms (10,112 dirty of 10,485 objects). The rendered Note has 5,001 paragraphs and about 12,900 DOM nodes. This shows full-document layout remains a measured cost after the transaction-local decoration fix. At 300 seconds, sustained typing had entered 1,990 keys, heap growth was 7.9%, and the 5k save completed in 87.45 seconds with all input keys persisted. I will include the complete 5k/20k after table after the locked run finishes.
Author
Owner

The first after-profile attempt completed the 5,000-block phase: 1,990 sustained keys; 7.9% heap growth; save 87,454.4 ms; no_lost_keystrokes=true. The 20,000-block Note opened, but the benchmark then failed while resolving the last paragraph: Playwright locator('.cal-prose > p').nth(19999).scrollIntoViewIfNeeded() timed out after 30 seconds while waiting for the 20,000th sibling. This is a profile-harness limitation, not a Note/editor error. I changed bench/bignote-1349.mjs to resolve the paragraph in page context and use the same real pointer double-click, committed as 9cf38a4cd; I will rerun the after-profile under perf-run to capture 20k typing and save metrics.

The first after-profile attempt completed the 5,000-block phase: 1,990 sustained keys; 7.9% heap growth; save 87,454.4 ms; `no_lost_keystrokes=true`. The 20,000-block Note opened, but the benchmark then failed while resolving the last paragraph: Playwright `locator('.cal-prose > p').nth(19999).scrollIntoViewIfNeeded()` timed out after 30 seconds while waiting for the 20,000th sibling. This is a profile-harness limitation, not a Note/editor error. I changed `bench/bignote-1349.mjs` to resolve the paragraph in page context and use the same real pointer double-click, committed as `9cf38a4cd`; I will rerun the after-profile under `perf-run` to capture 20k typing and save metrics.
Author
Owner

The 5k typing p95 still missed budget, and source review found another per-transaction full-document path: NoteCardsLayer.sectionBlocks() walked every prose.children element after each document edit before measuring each Card. I replaced that walk with start/end positions from the Note Card decoration set. The layer now resolves only Card endpoints from EditorView.nodeDOM; the plugin maps the boundary metadata through text edits. Added a unit test for the mapped positions. Commit: 23d464f42.

Focused verification:

svelte-check found 0 errors and 0 warnings
Test Files  1 passed (1)
     Tests  4 passed (4)
The 5k typing p95 still missed budget, and source review found another per-transaction full-document path: `NoteCardsLayer.sectionBlocks()` walked every `prose.children` element after each document edit before measuring each Card. I replaced that walk with start/end positions from the Note Card decoration set. The layer now resolves only Card endpoints from `EditorView.nodeDOM`; the plugin maps the boundary metadata through text edits. Added a unit test for the mapped positions. Commit: `23d464f42`. Focused verification: ```text svelte-check found 0 errors and 0 warnings Test Files 1 passed (1) Tests 4 passed (4) ```
Author
Owner

The final bun run check reached the source guard and found that NoteCardsLayer.svelte's exact existing performance exception pins no longer match after the section-boundary edit (layout.observer-purpose, plus repeated-read and loop-site fingerprints). The live scan confirms the same bounded ResizeObserver and measured Card-boundary reads; the #663 ledger entries are scoped to those exact sites. I am refreshing only their live symbol/hash identities, keeping the existing rules, limits, owner, reason, expiry, and ratchet counts unchanged, then rerunning the check.

The final `bun run check` reached the source guard and found that `NoteCardsLayer.svelte`'s exact existing performance exception pins no longer match after the section-boundary edit (`layout.observer-purpose`, plus repeated-read and loop-site fingerprints). The live scan confirms the same bounded ResizeObserver and measured Card-boundary reads; the `#663` ledger entries are scoped to those exact sites. I am refreshing only their live symbol/hash identities, keeping the existing rules, limits, owner, reason, expiry, and ratchet counts unchanged, then rerunning the check.
Author
Owner

Final bun run check passes after refreshing the exact live pins for #663. The output is perf-lint: PASS; 0 violations; 22543 scoped exceptions and svelte-check found 0 errors and 4 warnings in 2 files; the warnings are unused CSS selectors in the merged-branch Mail and budget screens, outside this issue. I am now running the requested full bun run test gate.

Final `bun run check` passes after refreshing the exact live pins for #663. The output is `perf-lint: PASS; 0 violations; 22543 scoped exceptions` and `svelte-check found 0 errors and 4 warnings in 2 files`; the warnings are unused CSS selectors in the merged-branch Mail and budget screens, outside this issue. I am now running the requested full `bun run test` gate.
Author
Owner

The 5,000-block sustained-typing phase completed its five-minute sampling window. Across the first and last 30-second samples, browser heap was 56,383,892 → 58,874,112 bytes (+4.4%); browser process-tree RSS was 1,007,898,624 → 1,003,036,672 bytes (-0.5%); server RSS was 861,462,528 → 1,108,418,560 bytes (+28.7%). The input probe recorded 2,106 z keys. The benchmark is still checking persisted save contents and running the 20,000-block profile. Perf VM load was 0.85 / 1.64 / 1.64 at lock acquisition and 7.17 / 5.80 / 3.63 near the end of the typing window.

The 5,000-block sustained-typing phase completed its five-minute sampling window. Across the first and last 30-second samples, browser heap was 56,383,892 → 58,874,112 bytes (+4.4%); browser process-tree RSS was 1,007,898,624 → 1,003,036,672 bytes (-0.5%); server RSS was 861,462,528 → 1,108,418,560 bytes (+28.7%). The input probe recorded 2,106 `z` keys. The benchmark is still checking persisted save contents and running the 20,000-block profile. Perf VM load was 0.85 / 1.64 / 1.64 at lock acquisition and 7.17 / 5.80 / 3.63 near the end of the typing window.
Author
Owner

Correction to my previous interim heap note: the benchmark's five-minute budget measurement starts immediately before typing, after its warm-up actions. It recorded 42,188,500 → 58,874,112 bytes (+39.6%), so the 20% heap budget is not met. The full 5,000-block result also misses the budgets: cold/warm first-usable p95 3,083.1 / 1,774.3 ms (1,500 ms limit); keydown-to-paint p95 start/middle/end 77.2 / 81.0 / 88.8 ms (50 ms limit). Scroll-frame p95 was 200 ms. Save completed in 10,516.1 ms and all 2,226 typed keys persisted.

The 20,000-block open p95 was 4,717.5 ms cold and 2,628.9 ms warm. Its 32-key position samples were 150.7 / 184.1 / 205.4 ms p95. The typed trace's top application work is ProseMirror traversal (map, forChild, descAt, nodesBetween); the open trace also shows 161.6 ms in getBoundingClientRect at 20k. The perf VM load rose to about 7 during this run. I am finishing the 20k save check, then will target the measured ProseMirror and Card-layout work.

Correction to my previous interim heap note: the benchmark's five-minute budget measurement starts immediately before typing, after its warm-up actions. It recorded 42,188,500 → 58,874,112 bytes (+39.6%), so the 20% heap budget is not met. The full 5,000-block result also misses the budgets: cold/warm first-usable p95 3,083.1 / 1,774.3 ms (1,500 ms limit); keydown-to-paint p95 start/middle/end 77.2 / 81.0 / 88.8 ms (50 ms limit). Scroll-frame p95 was 200 ms. Save completed in 10,516.1 ms and all 2,226 typed keys persisted. The 20,000-block open p95 was 4,717.5 ms cold and 2,628.9 ms warm. Its 32-key position samples were 150.7 / 184.1 / 205.4 ms p95. The typed trace's top application work is ProseMirror traversal (`map`, `forChild`, `descAt`, `nodesBetween`); the open trace also shows 161.6 ms in `getBoundingClientRect` at 20k. The perf VM load rose to about 7 during this run. I am finishing the 20k save check, then will target the measured ProseMirror and Card-layout work.
Author
Owner

The first after profile was diagnostic and failed the requested 5k budgets. It ran the production build from deb719bc6 on perf-test-69-63; load rose to about 7 during the 20k phase.

Measured evidence:

Size Open usable p95, cold Keydown paint p95, start / middle / end Scroll frame p95 Heap change in 5 min Save
5,000 3,083 ms 77 / 81 / 89 ms 200 ms +39.6% 10.5 s; 2,226/2,226 keys persisted
20,000 4,718 ms 151 / 184 / 205 ms 483 ms +11.3% 18.5 s; 1,033/1,033 keys persisted

Chrome typing profiles showed repeated ProseMirror DecorationSet.forChild scans and decoration mapping. The 20k open trace also showed 20,001 paragraphs mounted in the DOM and repeated Card endpoint layout reads. The Note API returned 525,516 bytes in about 222 ms in the 5k open trace, so the profile points to editor/render work after the request rather than request latency alone.

The editor fix now binary-searches sparse top-level decoration children and measures Card geometry only after a structural change or a real prose resize. Focused tests pass (12/12). The enforced profile still needs to be rerun on this fix; no budget pass is claimed.

The first after profile was diagnostic and failed the requested 5k budgets. It ran the production build from `deb719bc6` on perf-test-69-63; load rose to about 7 during the 20k phase. Measured evidence: | Size | Open usable p95, cold | Keydown paint p95, start / middle / end | Scroll frame p95 | Heap change in 5 min | Save | |---|---:|---:|---:|---:|---| | 5,000 | 3,083 ms | 77 / 81 / 89 ms | 200 ms | +39.6% | 10.5 s; 2,226/2,226 keys persisted | | 20,000 | 4,718 ms | 151 / 184 / 205 ms | 483 ms | +11.3% | 18.5 s; 1,033/1,033 keys persisted | Chrome typing profiles showed repeated ProseMirror `DecorationSet.forChild` scans and decoration mapping. The 20k open trace also showed 20,001 paragraphs mounted in the DOM and repeated Card endpoint layout reads. The Note API returned 525,516 bytes in about 222 ms in the 5k open trace, so the profile points to editor/render work after the request rather than request latency alone. The editor fix now binary-searches sparse top-level decoration children and measures Card geometry only after a structural change or a real prose resize. Focused tests pass (12/12). The enforced profile still needs to be rerun on this fix; no budget pass is claimed.
Author
Owner

Final report

Branch: job/bignote-1349
Head: 26fdacdb3bf106407ad4fd1afefa1af62d27bc2d

Built

  • Moved large Note decoration work into the shared editor core. It updates decorations from transaction ranges and indexes sparse Node decorations so child lookups do not scan every Note Card decoration.
  • Cached Note Card section boundaries and limited layout measurement to structure or resize changes.
  • Deferred offscreen block layout with content-visibility: auto.
  • Added the #1349 profile with 5k/20k Notes, open and typing traces, keydown-to-paint p50/p95, scroll frames, 30-second heap/RSS samples over five minutes, save checks, and budget assertions.

Before and measured checkpoint

The final profile was not rerun after the last commit (26fdacdb3). The “checkpoint” column is the prior measured profile at cf711ec56; it must not be read as a measurement of HEAD.

Metric Baseline Checkpoint at cf711ec56
5k cold / warm open p95 2,984.9 / 1,409.3 ms 2,779 / 1,433 ms
20k cold / warm open p95 4,779.6 / 4,180.9 ms 5,350.1 / 3,207.2 ms
5k typing p95, start / middle / end 97.5 / 108.6 / 98.7 ms 83.6 / 86.5 / 118.2 ms
20k typing p95, start / middle / end 191.6 / 227.2 / 270 ms 171.6 / 176.3 / 182.5 ms
Scroll frame p95, 5k / 20k 150 / 316.6 ms 166.6 / 533.3 ms
Five-minute heap growth, 5k / 20k +2.8% / −26.3% +19.7% / +13.6%
Save latency, 5k / 20k 81.8 / 107.2 s 16.4 / 5.3 s

The checkpoint still missed the 5k open and typing budgets. Its trace showed ProseMirror scanning root-local Node decorations in forChild for each child. The final commit fixes that sparse lookup path, but there is no post-fix timing evidence yet. The previous enforced profile exited with the 5k open-budget assertion; the final profile command is listed below.

Gates

cd apps/web && bun run build — PASS:

✓ built in 2m 30s
✓ built in 505ms
✓ built in 5m 24s
Compressed 914 static variants; saved 21496317 bytes.

cd apps/web && bun run check — PASS:

perf-lint: PASS; 0 violations; 22543 scoped exceptions
svelte-check found 0 errors and 4 warnings in 2 files

cd apps/web && bun run test — FAIL at the design-rule check because the moving origin/dev ref advanced after this worktree's one required merge:

New design-rule violations:
- packages/ui/src/components/TagPill.svelte:78: new hand-rolled button: tag-action touch-hit aria-haspopup={haspopup} aria-pressed={haspopup ? undefined : active} aria-label={(leaf || leafOnly) ? `#${tag}
error: script "test" exited with code 1

The full suite passed when run against this worktree's merge baseline with CALTERNAL_DESIGN_RULE_BASE=ef0aa12b12e0047cf9a779827cc0ed32261b934e:

design rules: no new shared primitive overrides or hand-rolled buttons (ef0aa12b12e0047cf9a779827cc0ed32261b934e baseline)
 Test Files  293 passed (293)
      Tests  2103 passed (2103)
   Duration  658.76s (transform 30%, environment 24%, import 20%, tests 20%, setup 5%)

Focused editor test: 1 file and 2 tests passed. No Rust files changed, so Rust crate gates were not run. cargo clean completed: Removed 1 file, 356B total. The web build output was removed. The worktree is clean.

UX gaps left

The requested final profile for HEAD and the 390/820/1440 Mac-platform light/dark screenshots were not completed or attached. At closeout the perf VM lock was held by another job and the local browser slot was occupied; the job had passed the four-hour cap. Visual review therefore remains outstanding. No UI control or interaction behavior changed.

Decisions not covered by DESIGN

  • The sparse decoration index reads ProseMirror's private local and children arrays. It uses a runtime type sentinel to distinguish inline decorations and falls back to the source set when inline-local decorations are present.
  • The offscreen layout estimate uses the shared line-height token as 2lh.

Files

  • packages/editor/src/extensions.ts
  • packages/editor/src/{blockAnchorOwners,documentDecorationPlugins,indexedDecorationSet,noteCardsDecoration,transactionRanges}.ts and their tests
  • packages/editor/src/components/NoteCardsLayer.svelte
  • apps/web/src/lib/notes/noteProse.css
  • bench/bignote-1349.mjs
  • contracts/perf/exceptions.json

Remaining work

After the perf VM is available, run the staged final profile and attach the result and traces:

netbird ssh --no-browser root@10.69.69.63 'perf-run calternal bignote-1349 45 -- bash /root/calternal-bignote-1349/target/tmp/run-after-followup.sh'

On the merge-round branch, rerun cd apps/web && bun run test against the integrated origin/dev tip to verify the default design-rule baseline and full web suite.

## Final report **Branch:** `job/bignote-1349` **Head:** `26fdacdb3bf106407ad4fd1afefa1af62d27bc2d` ### Built - Moved large Note decoration work into the shared editor core. It updates decorations from transaction ranges and indexes sparse Node decorations so child lookups do not scan every Note Card decoration. - Cached Note Card section boundaries and limited layout measurement to structure or resize changes. - Deferred offscreen block layout with `content-visibility: auto`. - Added the #1349 profile with 5k/20k Notes, open and typing traces, keydown-to-paint p50/p95, scroll frames, 30-second heap/RSS samples over five minutes, save checks, and budget assertions. ### Before and measured checkpoint The final profile was not rerun after the last commit (`26fdacdb3`). The “checkpoint” column is the prior measured profile at `cf711ec56`; it must not be read as a measurement of HEAD. | Metric | Baseline | Checkpoint at cf711ec56 | | --- | ---: | ---: | | 5k cold / warm open p95 | 2,984.9 / 1,409.3 ms | 2,779 / 1,433 ms | | 20k cold / warm open p95 | 4,779.6 / 4,180.9 ms | 5,350.1 / 3,207.2 ms | | 5k typing p95, start / middle / end | 97.5 / 108.6 / 98.7 ms | 83.6 / 86.5 / 118.2 ms | | 20k typing p95, start / middle / end | 191.6 / 227.2 / 270 ms | 171.6 / 176.3 / 182.5 ms | | Scroll frame p95, 5k / 20k | 150 / 316.6 ms | 166.6 / 533.3 ms | | Five-minute heap growth, 5k / 20k | +2.8% / −26.3% | +19.7% / +13.6% | | Save latency, 5k / 20k | 81.8 / 107.2 s | 16.4 / 5.3 s | The checkpoint still missed the 5k open and typing budgets. Its trace showed ProseMirror scanning root-local Node decorations in `forChild` for each child. The final commit fixes that sparse lookup path, but there is no post-fix timing evidence yet. The previous enforced profile exited with the 5k open-budget assertion; the final profile command is listed below. ### Gates `cd apps/web && bun run build` — PASS: ``` ✓ built in 2m 30s ✓ built in 505ms ✓ built in 5m 24s Compressed 914 static variants; saved 21496317 bytes. ``` `cd apps/web && bun run check` — PASS: ``` perf-lint: PASS; 0 violations; 22543 scoped exceptions svelte-check found 0 errors and 4 warnings in 2 files ``` `cd apps/web && bun run test` — FAIL at the design-rule check because the moving `origin/dev` ref advanced after this worktree's one required merge: ``` New design-rule violations: - packages/ui/src/components/TagPill.svelte:78: new hand-rolled button: tag-action touch-hit aria-haspopup={haspopup} aria-pressed={haspopup ? undefined : active} aria-label={(leaf || leafOnly) ? `#${tag} error: script "test" exited with code 1 ``` The full suite passed when run against this worktree's merge baseline with `CALTERNAL_DESIGN_RULE_BASE=ef0aa12b12e0047cf9a779827cc0ed32261b934e`: ``` design rules: no new shared primitive overrides or hand-rolled buttons (ef0aa12b12e0047cf9a779827cc0ed32261b934e baseline) Test Files 293 passed (293) Tests 2103 passed (2103) Duration 658.76s (transform 30%, environment 24%, import 20%, tests 20%, setup 5%) ``` Focused editor test: 1 file and 2 tests passed. No Rust files changed, so Rust crate gates were not run. `cargo clean` completed: `Removed 1 file, 356B total`. The web build output was removed. The worktree is clean. ### UX gaps left The requested final profile for HEAD and the 390/820/1440 Mac-platform light/dark screenshots were not completed or attached. At closeout the perf VM lock was held by another job and the local browser slot was occupied; the job had passed the four-hour cap. Visual review therefore remains outstanding. No UI control or interaction behavior changed. ### Decisions not covered by DESIGN - The sparse decoration index reads ProseMirror's private `local` and `children` arrays. It uses a runtime type sentinel to distinguish inline decorations and falls back to the source set when inline-local decorations are present. - The offscreen layout estimate uses the shared line-height token as `2lh`. ### Files - `packages/editor/src/extensions.ts` - `packages/editor/src/{blockAnchorOwners,documentDecorationPlugins,indexedDecorationSet,noteCardsDecoration,transactionRanges}.ts` and their tests - `packages/editor/src/components/NoteCardsLayer.svelte` - `apps/web/src/lib/notes/noteProse.css` - `bench/bignote-1349.mjs` - `contracts/perf/exceptions.json` ### Remaining work After the perf VM is available, run the staged final profile and attach the result and traces: ``` netbird ssh --no-browser root@10.69.69.63 'perf-run calternal bignote-1349 45 -- bash /root/calternal-bignote-1349/target/tmp/run-after-followup.sh' ``` On the merge-round branch, rerun `cd apps/web && bun run test` against the integrated `origin/dev` tip to verify the default design-rule baseline and full web suite.
Author
Owner

Starting continuation on job/bignote-1349 at 26fdacdb3b; branch merge base is ef0aa12b12. I will measure this HEAD on the perf VM before code changes, then continue the listed risk checks and screenshots.

Starting continuation on job/bignote-1349 at 26fdacdb3bf106407ad4fd1afefa1af62d27bc2d; branch merge base is ef0aa12b12e0047cf9a779827cc0ed32261b934e. I will measure this HEAD on the perf VM before code changes, then continue the listed risk checks and screenshots.
Author
Owner

Measurement setup finding: HEAD run 1 exited before sampling because the copied release server could not load libsherpa-onnx-c-api.so. perf-run released the lock. I am copying the complete matching shared-server runtime directory, then will restart the interleaved perf run. No timing data was produced by this attempt.

Measurement setup finding: HEAD run 1 exited before sampling because the copied release server could not load libsherpa-onnx-c-api.so. perf-run released the lock. I am copying the complete matching shared-server runtime directory, then will restart the interleaved perf run. No timing data was produced by this attempt.
Author
Owner

HEAD run 1 finding: after five minutes of typing in the 5k Note, the benchmark had not observed the SAVE13495000 marker in the Notes API after about 60 seconds. The profile is still within its 180-second save deadline; I will report whether the marker becomes durable or times out.

HEAD run 1 finding: after five minutes of typing in the 5k Note, the benchmark had not observed the SAVE13495000 marker in the Notes API after about 60 seconds. The profile is still within its 180-second save deadline; I will report whether the marker becomes durable or times out.
Author
Owner

Correction to the interim save note: the completed 5k profile now records save_complete=true, save_latency_ms=2904.1, and no_lost_keystrokes=true. The quiet console did not mean the save was still pending; the earlier note was premature. I will use the saved profile data as the record.

Correction to the interim save note: the completed 5k profile now records save_complete=true, save_latency_ms=2904.1, and no_lost_keystrokes=true. The quiet console did not mean the save was still pending; the earlier note was premature. I will use the saved profile data as the record.
Author
Owner

HEAD run 1, 5k Note result: fully painted p95 2408.6 ms (the profile target is 1500 ms); typing p95 is 115.8 ms at start, 131.4 ms in the middle, and 158.6 ms at the end (profile threshold 50 ms); scroll-frame p95 is 366.6 ms. Chrome traces are saved. Load average was 0.52/2.36/2.93 before and 5.88/4.76/3.84 after, so this is one provisional sample; the interleaved origin/dev matrix will provide comparison.

HEAD run 1, 5k Note result: fully painted p95 2408.6 ms (the profile target is 1500 ms); typing p95 is 115.8 ms at start, 131.4 ms in the middle, and 158.6 ms at the end (profile threshold 50 ms); scroll-frame p95 is 366.6 ms. Chrome traces are saved. Load average was 0.52/2.36/2.93 before and 5.88/4.76/3.84 after, so this is one provisional sample; the interleaved origin/dev matrix will provide comparison.
Author
Owner

HEAD run 1 completed on perf-test-69-63. For 20k: cold fully painted p95 5525.1 ms, warm fully painted p95 5254.4 ms; typing p95 294.1/285.2/266.3 ms (start/middle/end); scroll-frame p95 866.6 ms; heap change -11.9%; mean browser-tree RSS 1397 MiB and server RSS 1277 MiB; save latency 3666.2 ms with no lost keys. At 5k, heap change was +11.5%, mean browser-tree RSS 917 MiB and server RSS 1022 MiB, save latency 2904.1 ms with no lost keys. Load average was 0.52/2.36/2.93 before and 3.98/3.85/3.69 after. HEAD run 1 records five cold and five warm opens per size; the bench exited 1 after recording because 5k open p95 exceeded its 1500 ms threshold. I am starting the d395b6e25 baseline as B1.

HEAD run 1 completed on perf-test-69-63. For 20k: cold fully painted p95 5525.1 ms, warm fully painted p95 5254.4 ms; typing p95 294.1/285.2/266.3 ms (start/middle/end); scroll-frame p95 866.6 ms; heap change -11.9%; mean browser-tree RSS 1397 MiB and server RSS 1277 MiB; save latency 3666.2 ms with no lost keys. At 5k, heap change was +11.5%, mean browser-tree RSS 917 MiB and server RSS 1022 MiB, save latency 2904.1 ms with no lost keys. Load average was 0.52/2.36/2.93 before and 3.98/3.85/3.69 after. HEAD run 1 records five cold and five warm opens per size; the bench exited 1 after recording because 5k open p95 exceeded its 1500 ms threshold. I am starting the d395b6e25 baseline as B1.
Author
Owner

Baseline run 1 on d395b6e25 completed. 5k: cold fully painted p95 2800.1 ms, warm p95 1876.2 ms, typing p95 154.4/155.9/121.7 ms, scroll-frame p95 233.3 ms, heap change -2.1%, mean browser-tree/server RSS 925/1046 MiB, save 3551.6 ms with no lost keys. 20k: cold fully painted p95 7862.8 ms, warm p95 5811.7 ms, typing p95 342.2/468.1/759.6 ms, scroll-frame p95 516.6 ms, heap change -18.7%, mean browser-tree/server RSS 1347/1345 MiB, save 2636.4 ms with no lost keys. Load average was 2.62/3.54/3.59 before and 3.89/4.10/4.10 after. Compared with HEAD run 1, the 20k opens and typing samples improve, while the 5k budget still misses and scroll-frame p95 was higher on HEAD; repeated interleaved runs will confirm.

Baseline run 1 on d395b6e25 completed. 5k: cold fully painted p95 2800.1 ms, warm p95 1876.2 ms, typing p95 154.4/155.9/121.7 ms, scroll-frame p95 233.3 ms, heap change -2.1%, mean browser-tree/server RSS 925/1046 MiB, save 3551.6 ms with no lost keys. 20k: cold fully painted p95 7862.8 ms, warm p95 5811.7 ms, typing p95 342.2/468.1/759.6 ms, scroll-frame p95 516.6 ms, heap change -18.7%, mean browser-tree/server RSS 1347/1345 MiB, save 2636.4 ms with no lost keys. Load average was 2.62/3.54/3.59 before and 3.89/4.10/4.10 after. Compared with HEAD run 1, the 20k opens and typing samples improve, while the 5k budget still misses and scroll-frame p95 was higher on HEAD; repeated interleaved runs will confirm.
Author
Owner

#1349 measurement update — paired run 3 (A3 HEAD 26fdacdb3, B3 baseline d395b6e25)

B3 completed on perf-test-69-63. Typing windows were 60 seconds. A3 host load was 2.40/3.24/3.66 before and 3.66/3.66/3.76 after (peak sampled 5.12/3.86/3.83); B3 was 3.38/3.60/3.72 before and 4.06/3.80/3.77 after.

Blocks Build Cold open p95 Warm open p95 Typing p95 start / middle / end Scroll frame p95 Heap growth Mean browser / server RSS Save Keys kept
5k HEAD 3440 ms 1959 ms 95 / 140 / 130 ms 317 ms +35.1% 966 / 874 MiB 2512 ms yes
5k baseline 2166 ms 1396 ms 89 / 105 / 105 ms 183 ms -29.8% 891 / 864 MiB 3196 ms yes
20k HEAD 5360 ms 4845 ms 248 / 301 / 266 ms 817 ms -4.1% 1455 / 1168 MiB 9243 ms yes
20k baseline 5670 ms 5390 ms 301 / 333 / 328 ms 333 ms +21.1% 1376 / 1196 MiB 3217 ms yes

The 5k HEAD open and typing p95 values exceed their 1500 ms and 50 ms budgets. The 1-minute heap samples are noisy and are not directly comparable with the 5-minute first pair. The VM load differed between A3 and B3, so this pair is directional; paired runs 4 and 5 remain.

#1349 measurement update — paired run 3 (A3 HEAD `26fdacdb3`, B3 baseline `d395b6e25`) B3 completed on perf-test-69-63. Typing windows were 60 seconds. A3 host load was 2.40/3.24/3.66 before and 3.66/3.66/3.76 after (peak sampled 5.12/3.86/3.83); B3 was 3.38/3.60/3.72 before and 4.06/3.80/3.77 after. | Blocks | Build | Cold open p95 | Warm open p95 | Typing p95 start / middle / end | Scroll frame p95 | Heap growth | Mean browser / server RSS | Save | Keys kept | |---:|---|---:|---:|---:|---:|---:|---:|---:|---| | 5k | HEAD | 3440 ms | 1959 ms | 95 / 140 / 130 ms | 317 ms | +35.1% | 966 / 874 MiB | 2512 ms | yes | | 5k | baseline | 2166 ms | 1396 ms | 89 / 105 / 105 ms | 183 ms | -29.8% | 891 / 864 MiB | 3196 ms | yes | | 20k | HEAD | 5360 ms | 4845 ms | 248 / 301 / 266 ms | 817 ms | -4.1% | 1455 / 1168 MiB | 9243 ms | yes | | 20k | baseline | 5670 ms | 5390 ms | 301 / 333 / 328 ms | 333 ms | +21.1% | 1376 / 1196 MiB | 3217 ms | yes | The 5k HEAD open and typing p95 values exceed their 1500 ms and 50 ms budgets. The 1-minute heap samples are noisy and are not directly comparable with the 5-minute first pair. The VM load differed between A3 and B3, so this pair is directional; paired runs 4 and 5 remain.
Author
Owner

#1349 finding: the TagPill design-rule failure is branch-only.

Evidence: node apps/web/scripts/design-rules.test.mjs on job/bignote-1349 fails at packages/ui/src/components/TagPill.svelte:78 with a new hand-rolled button. The same command in a detached worktree at origin/dev (d395b6e25) passes: design rules: no new shared primitive overrides or hand-rolled buttons (origin/dev baseline). This branch has a stale TagPill implementation compared with origin/dev. I will resolve it with the required origin/dev merge and will run bun run test on origin/dev and on the merged branch before reporting.

#1349 finding: the TagPill design-rule failure is branch-only. Evidence: `node apps/web/scripts/design-rules.test.mjs` on `job/bignote-1349` fails at `packages/ui/src/components/TagPill.svelte:78` with a new hand-rolled button. The same command in a detached worktree at `origin/dev` (`d395b6e25`) passes: `design rules: no new shared primitive overrides or hand-rolled buttons (origin/dev baseline)`. This branch has a stale TagPill implementation compared with origin/dev. I will resolve it with the required origin/dev merge and will run `bun run test` on origin/dev and on the merged branch before reporting.
Author
Owner

#1349 measurement update — A4 HEAD 26fdacdb3 on perf-test-69-63

A4 typing windows were 60 seconds. Load average was 1.49/3.11/3.53 before and 3.72/3.76/3.75 after.

Blocks Cold open p50 / p95 Warm open p50 / p95 Typing p95 start / middle / end Scroll frame p95 Heap growth Mean browser / server RSS Save Keys kept
5k 1461 / 2176 ms 1117 / 1524 ms 64 / 140 / 99 ms 233 ms +22.8% 900 / 868 MiB 2696 ms yes
20k 4202 / 5485 ms 3073 / 3349 ms 166 / 219 / 136 ms 633 ms +5.6% 1455 / 1201 MiB 5025 ms yes

The 5k cold and warm open p95 values exceed 1500 ms. All three 5k typing p95 values exceed 50 ms. The one-minute heap result is not directly comparable to the first five-minute sample.

#1349 measurement update — A4 HEAD `26fdacdb3` on perf-test-69-63 A4 typing windows were 60 seconds. Load average was 1.49/3.11/3.53 before and 3.72/3.76/3.75 after. | Blocks | Cold open p50 / p95 | Warm open p50 / p95 | Typing p95 start / middle / end | Scroll frame p95 | Heap growth | Mean browser / server RSS | Save | Keys kept | |---:|---:|---:|---:|---:|---:|---:|---:|---| | 5k | 1461 / 2176 ms | 1117 / 1524 ms | 64 / 140 / 99 ms | 233 ms | +22.8% | 900 / 868 MiB | 2696 ms | yes | | 20k | 4202 / 5485 ms | 3073 / 3349 ms | 166 / 219 / 136 ms | 633 ms | +5.6% | 1455 / 1201 MiB | 5025 ms | yes | The 5k cold and warm open p95 values exceed 1500 ms. All three 5k typing p95 values exceed 50 ms. The one-minute heap result is not directly comparable to the first five-minute sample.
Author
Owner

#1349 measurement update — paired run 4 (A4 HEAD 26fdacdb3, B4 baseline d395b6e25)

B4 typing windows were 60 seconds. A4 load average was 1.49/3.11/3.53 before and 3.72/3.76/3.75 after; B4 was 2.66/3.52/3.67 before and 3.90/4.02/3.87 after.

Blocks Build Cold open p50 / p95 Warm open p50 / p95 Typing p95 start / middle / end Scroll frame p95 Heap growth Mean browser / server RSS Save Keys kept
5k HEAD 1461 / 2176 ms 1117 / 1524 ms 64 / 140 / 99 ms 233 ms +22.8% 900 / 868 MiB 2696 ms yes
5k baseline 1632 / 2078 ms 1496 / 1516 ms 93 / 141 / 140 ms 300 ms -22.2% 923 / 887 MiB 2925 ms yes
20k HEAD 4202 / 5485 ms 3073 / 3349 ms 166 / 219 / 136 ms 633 ms +5.6% 1455 / 1201 MiB 5025 ms yes
20k baseline 3756 / 4639 ms 3112 / 3511 ms 236 / 231 / 238 ms 333 ms +24.0% 1533 / 1258 MiB 3379 ms yes

Both builds miss the 5k cold-open and typing p95 budgets. The 20k baseline cold-open is faster than HEAD in this pair; 5k opens are close. Heap changes are from 60-second windows and remain noisy.

#1349 measurement update — paired run 4 (A4 HEAD `26fdacdb3`, B4 baseline `d395b6e25`) B4 typing windows were 60 seconds. A4 load average was 1.49/3.11/3.53 before and 3.72/3.76/3.75 after; B4 was 2.66/3.52/3.67 before and 3.90/4.02/3.87 after. | Blocks | Build | Cold open p50 / p95 | Warm open p50 / p95 | Typing p95 start / middle / end | Scroll frame p95 | Heap growth | Mean browser / server RSS | Save | Keys kept | |---:|---|---:|---:|---:|---:|---:|---:|---:|---| | 5k | HEAD | 1461 / 2176 ms | 1117 / 1524 ms | 64 / 140 / 99 ms | 233 ms | +22.8% | 900 / 868 MiB | 2696 ms | yes | | 5k | baseline | 1632 / 2078 ms | 1496 / 1516 ms | 93 / 141 / 140 ms | 300 ms | -22.2% | 923 / 887 MiB | 2925 ms | yes | | 20k | HEAD | 4202 / 5485 ms | 3073 / 3349 ms | 166 / 219 / 136 ms | 633 ms | +5.6% | 1455 / 1201 MiB | 5025 ms | yes | | 20k | baseline | 3756 / 4639 ms | 3112 / 3511 ms | 236 / 231 / 238 ms | 333 ms | +24.0% | 1533 / 1258 MiB | 3379 ms | yes | Both builds miss the 5k cold-open and typing p95 budgets. The 20k baseline cold-open is faster than HEAD in this pair; 5k opens are close. Heap changes are from 60-second windows and remain noisy.
Author
Owner

#1349 TagPill check follow-up

The full origin/dev web suite passed in the detached d395b6e25 worktree, with Vitest capped at two workers: bun run test -- --maxWorkers=2; output reported Test Files 297 passed (297) and Tests 2116 passed (2116). Its design-rule stage passed. The branch-only TagPill.svelte:78 failure is therefore due to the stale component on this job branch, not origin/dev. I will run the full web suite again after the required merge.

#1349 TagPill check follow-up The full origin/dev web suite passed in the detached d395b6e25 worktree, with Vitest capped at two workers: `bun run test -- --maxWorkers=2`; output reported `Test Files 297 passed (297)` and `Tests 2116 passed (2116)`. Its design-rule stage passed. The branch-only `TagPill.svelte:78` failure is therefore due to the stale component on this job branch, not origin/dev. I will run the full web suite again after the required merge.
Author
Owner

#1349 measurement update — A5 HEAD 26fdacdb3 on perf-test-69-63

Typing windows were 60 seconds. Load average was 0.49/0.68/1.35 before and 3.96/2.87/2.17 after.

Blocks Cold open p50 / p95 Warm open p50 / p95 Typing p95 start / middle / end Scroll frame p95 Heap growth Mean browser / server RSS Save Keys kept
5k 1373 / 1911 ms 1231 / 1836 ms 55 / 93 / 134 ms 217 ms -4.5% 880 / 831 MiB 2271 ms yes
20k 3146 / 3805 ms 2990 / 3116 ms 129 / 182 / 169 ms 650 ms -8.7% 1547 / 1250 MiB 3824 ms yes

The 5k open p95 and all three 5k typing p95 values exceed their 1500 ms and 50 ms budgets. This completed HEAD run 5; baseline run 5 remains.

#1349 measurement update — A5 HEAD `26fdacdb3` on perf-test-69-63 Typing windows were 60 seconds. Load average was 0.49/0.68/1.35 before and 3.96/2.87/2.17 after. | Blocks | Cold open p50 / p95 | Warm open p50 / p95 | Typing p95 start / middle / end | Scroll frame p95 | Heap growth | Mean browser / server RSS | Save | Keys kept | |---:|---:|---:|---:|---:|---:|---:|---:|---| | 5k | 1373 / 1911 ms | 1231 / 1836 ms | 55 / 93 / 134 ms | 217 ms | -4.5% | 880 / 831 MiB | 2271 ms | yes | | 20k | 3146 / 3805 ms | 2990 / 3116 ms | 129 / 182 / 169 ms | 650 ms | -8.7% | 1547 / 1250 MiB | 3824 ms | yes | The 5k open p95 and all three 5k typing p95 values exceed their 1500 ms and 50 ms budgets. This completed HEAD run 5; baseline run 5 remains.
Author
Owner

#1349 measurement update — B5 baseline d395b6e25 on perf-test-69-63

B5 typing windows were 60 seconds. Load average was 2.67/2.66/2.11 before and 3.38/3.39/2.66 after.

Blocks Cold open p50 / p95 Warm open p50 / p95 Typing p95 start / middle / end Scroll frame p95 Heap growth Mean browser / server RSS Save Keys kept
5k 1643 / 2256 ms 1631 / 1660 ms 75 / 186 / 111 ms 200 ms +18.5% 1095 / 876 MiB 3171 ms yes
20k 3349 / 4400 ms 3795 / 4626 ms 315 / 323 / 455 ms 433 ms +47.9% 1486 / 1158 MiB 3289 ms yes

This completes the fifth paired HEAD/baseline run. The 5k HEAD cold-open and typing budgets remain unmet; all five runs preserved input.

#1349 measurement update — B5 baseline `d395b6e25` on perf-test-69-63 B5 typing windows were 60 seconds. Load average was 2.67/2.66/2.11 before and 3.38/3.39/2.66 after. | Blocks | Cold open p50 / p95 | Warm open p50 / p95 | Typing p95 start / middle / end | Scroll frame p95 | Heap growth | Mean browser / server RSS | Save | Keys kept | |---:|---:|---:|---:|---:|---:|---:|---:|---| | 5k | 1643 / 2256 ms | 1631 / 1660 ms | 75 / 186 / 111 ms | 200 ms | +18.5% | 1095 / 876 MiB | 3171 ms | yes | | 20k | 3349 / 4400 ms | 3795 / 4626 ms | 315 / 323 / 455 ms | 433 ms | +47.9% | 1486 / 1158 MiB | 3289 ms | yes | This completes the fifth paired HEAD/baseline run. The 5k HEAD cold-open and typing budgets remain unmet; all five runs preserved input.
Author
Owner

Implemented and committed 6f0ba220a (Guard indexed decoration storage assumptions). The runtime guard accepts only the pinned array/triple shape and returns unsupported sets unchanged for ProseMirror's native lookup. The test asserts the private shape resolved by @tiptap/pm 3.31.4 (prosemirror-view 1.42.5), then renders both the indexed set and an unsupported array-like storage fallback with EditorView and compares the resulting HTML. Focused test output: Test Files 1 passed (1); Tests 3 passed (3).

Implemented and committed `6f0ba220a` (`Guard indexed decoration storage assumptions`). The runtime guard accepts only the pinned array/triple shape and returns unsupported sets unchanged for ProseMirror's native lookup. The test asserts the private shape resolved by `@tiptap/pm` 3.31.4 (`prosemirror-view` 1.42.5), then renders both the indexed set and an unsupported array-like storage fallback with `EditorView` and compares the resulting HTML. Focused test output: `Test Files 1 passed (1)`; `Tests 3 passed (3)`.
Author
Owner

Sourcemapped HEAD profile (26fdacdb3, original pre-fix) completed on perf-test-69-63. For the 5,000-block Note, cold fully-rendered open was p50/p95 1690/3272.5 ms; warm was 1367/1543 ms. Keydown-to-paint p95 was 81.2/199.4/151.8 ms at start/middle/end; scroll-frame p95 was 333.2 ms. For 20,000 blocks, cold/warm open p95 was 4480.9/3847.3 ms, typing p95 200.3/206.9/196.1 ms, scroll-frame p95 799.9 ms. One-minute memory samples grew 3.6% and 27.7%; all input keys saved. Load average was 0.29/1.75/2.14 before and 3.72/3.25/2.73 after.

Chrome traces mapped repeated 14–178 ms AppToaster dock updates while 5k/20k prose children mounted. I excluded .cal-prose subtree mutations from that dock observer and added an AppToaster regression test. The editor test now also pins the ProseMirror storage arrays/triples and asserts native fallback HTML matches indexed HTML. These changes are committed in 772920b6b and 6f0ba220a plus follow-up type/perf-pin commits. Re-measurement on perf-test-69-63 is pending the active infraternal perf lock; no result is inferred from the old profile.

Sourcemapped HEAD profile (`26fdacdb3`, original pre-fix) completed on perf-test-69-63. For the 5,000-block Note, cold fully-rendered open was p50/p95 1690/3272.5 ms; warm was 1367/1543 ms. Keydown-to-paint p95 was 81.2/199.4/151.8 ms at start/middle/end; scroll-frame p95 was 333.2 ms. For 20,000 blocks, cold/warm open p95 was 4480.9/3847.3 ms, typing p95 200.3/206.9/196.1 ms, scroll-frame p95 799.9 ms. One-minute memory samples grew 3.6% and 27.7%; all input keys saved. Load average was 0.29/1.75/2.14 before and 3.72/3.25/2.73 after. Chrome traces mapped repeated 14–178 ms AppToaster dock updates while 5k/20k prose children mounted. I excluded `.cal-prose` subtree mutations from that dock observer and added an AppToaster regression test. The editor test now also pins the ProseMirror storage arrays/triples and asserts native fallback HTML matches indexed HTML. These changes are committed in `772920b6b` and `6f0ba220a` plus follow-up type/perf-pin commits. Re-measurement on perf-test-69-63 is pending the active infraternal perf lock; no result is inferred from the old profile.
Author
Owner

Final report — #1349

Head: bad252232 (job/bignote-1349).

Built

  • Guarded the indexed ProseMirror decoration lookup against private storage shape changes, with native fallback parity coverage.
  • Skipped toast dock observation for Note prose mutations and refreshed exact performance pins.
  • Kept deferred Note blocks visible in print and removed the editor outline through the shared data-focus-ring="none" token; the caret remains the text focus indicator.
  • Added a production risk probe for deep links, find-in-page, caret/selection, print and scrolling.

Files: packages/editor/src/indexedDecorationSet.ts, packages/editor/src/indexedDecorationSet.test.ts, apps/web/src/lib/components/AppToaster.svelte, apps/web/src/lib/components/AppToaster.svelte.test.ts, contracts/perf/exceptions.json, contracts/perf/adoption-1058.json, apps/web/src/lib/notes/NoteEditorSurface.svelte, apps/web/src/lib/notes/noteProse.css, apps/web/e2e/bignote-1349-risk.mjs.

Performance

One post-fix perf VM run used one cold and one warm open per size, 24 key-paint samples per position, and 60 seconds of sustained typing per size. This sample count is smaller than the interleaved baseline run, so treat it as directional.

Blocks Cold open p95 Warm open p95 Typing p95 start / middle / end Scroll frame p95 Heap growth Lost keys
5,000 2,378.8 ms 382 ms 110.3 / 129.4 / 170.4 ms 349.9 ms 33.4% 0
20,000 5,293 ms 604.3 ms 193.9 / 190.5 / 179.3 ms 583.4 ms -15.7% 0

The 5k open and typing budgets remain missed. Both sizes saved all typed keys; save latency was 1,672.7 ms at 5k and 1,699.1 ms at 20k. The source-mapped profile and the initial five-pair HEAD/baseline table are in the earlier comments.

Verification

  • apps/web: bun run check exited 0. Output: perf-lint: PASS; 0 violations; 22544 scoped exceptions; svelte-check found 0 errors and 4 warnings in 2 files.
  • packages/editor: bun run check — svelte-check found 0 errors and 0 warnings.
  • packages/editor: bun run test — Test Files 26 passed (26); Tests 460 passed (460).
  • Focused tests: indexed decoration fallback 3 passed; AppToaster prose mutation 4 passed.
  • The 18 Mac-emulated production captures (390/820/1440 × light/dark × top/middle/typed) and the shortcut-find capture are attached below.
  • The risk-only browser run passed the deep-link, find, caret, selection, and focus-ring assertions, then was interrupted during PDF generation at the job time cap. Print PDF completion and scrollTop drift measurement remain unverified.
  • The full apps/web test suite was deferred under the shared verification policy. For the merge round: cd apps/web && bun run test --maxWorkers=2 must prove the complete web test suite passes.
  • The TagPill design-rule failure was reproduced as absent on origin/dev (d395b6e25); the post-merge branch check passes.

UX gaps

Closed: Note focus uses the caret without an outline after pointer typing; all requested width/theme/state captures are clean and show loaded Note content.

Left: no separate immediate-after-click capture was produced; the typed captures show the editor after pointer activation and typing. Print generation and measured scroll drift remain open as described above.

Decisions

  • Print media resets content-visibility and intrinsic sizing so every block uses its measured height.
  • The editable prose surface uses the shared no-ring token because its caret is the focus indicator.
  • The find-in-page probe uses Chromium window.find with wraparound because ⌘F is the browser's native find action, not the app Search palette.

Captures

390 light: top · middle · typed

390 dark: top · middle · typed

820 light: top · middle · typed

820 dark: top · middle · typed

1440 light: top · middle · typed

1440 dark: top · middle · typed

Shortcut find: 1440 light

## Final report — #1349 Head: `bad252232` (`job/bignote-1349`). ### Built - Guarded the indexed ProseMirror decoration lookup against private storage shape changes, with native fallback parity coverage. - Skipped toast dock observation for Note prose mutations and refreshed exact performance pins. - Kept deferred Note blocks visible in print and removed the editor outline through the shared `data-focus-ring="none"` token; the caret remains the text focus indicator. - Added a production risk probe for deep links, find-in-page, caret/selection, print and scrolling. Files: `packages/editor/src/indexedDecorationSet.ts`, `packages/editor/src/indexedDecorationSet.test.ts`, `apps/web/src/lib/components/AppToaster.svelte`, `apps/web/src/lib/components/AppToaster.svelte.test.ts`, `contracts/perf/exceptions.json`, `contracts/perf/adoption-1058.json`, `apps/web/src/lib/notes/NoteEditorSurface.svelte`, `apps/web/src/lib/notes/noteProse.css`, `apps/web/e2e/bignote-1349-risk.mjs`. ### Performance One post-fix perf VM run used one cold and one warm open per size, 24 key-paint samples per position, and 60 seconds of sustained typing per size. This sample count is smaller than the interleaved baseline run, so treat it as directional. | Blocks | Cold open p95 | Warm open p95 | Typing p95 start / middle / end | Scroll frame p95 | Heap growth | Lost keys | | --- | ---: | ---: | --- | ---: | ---: | --- | | 5,000 | 2,378.8 ms | 382 ms | 110.3 / 129.4 / 170.4 ms | 349.9 ms | 33.4% | 0 | | 20,000 | 5,293 ms | 604.3 ms | 193.9 / 190.5 / 179.3 ms | 583.4 ms | -15.7% | 0 | The 5k open and typing budgets remain missed. Both sizes saved all typed keys; save latency was 1,672.7 ms at 5k and 1,699.1 ms at 20k. The source-mapped profile and the initial five-pair HEAD/baseline table are in the earlier comments. ### Verification - `apps/web`: `bun run check` exited 0. Output: `perf-lint: PASS; 0 violations; 22544 scoped exceptions`; `svelte-check found 0 errors and 4 warnings in 2 files`. - `packages/editor`: `bun run check` — `svelte-check found 0 errors and 0 warnings`. - `packages/editor`: `bun run test` — `Test Files 26 passed (26)`; `Tests 460 passed (460)`. - Focused tests: indexed decoration fallback `3 passed`; AppToaster prose mutation `4 passed`. - The 18 Mac-emulated production captures (390/820/1440 × light/dark × top/middle/typed) and the shortcut-find capture are attached below. - The risk-only browser run passed the deep-link, find, caret, selection, and focus-ring assertions, then was interrupted during PDF generation at the job time cap. Print PDF completion and scrollTop drift measurement remain unverified. - The full `apps/web` test suite was deferred under the shared verification policy. For the merge round: `cd apps/web && bun run test --maxWorkers=2` must prove the complete web test suite passes. - The TagPill design-rule failure was reproduced as absent on `origin/dev` (`d395b6e25`); the post-merge branch check passes. ### UX gaps Closed: Note focus uses the caret without an outline after pointer typing; all requested width/theme/state captures are clean and show loaded Note content. Left: no separate immediate-after-click capture was produced; the typed captures show the editor after pointer activation and typing. Print generation and measured scroll drift remain open as described above. ### Decisions - Print media resets `content-visibility` and intrinsic sizing so every block uses its measured height. - The editable prose surface uses the shared no-ring token because its caret is the focus indicator. - The find-in-page probe uses Chromium `window.find` with wraparound because `⌘F` is the browser's native find action, not the app Search palette. ### Captures **390 light:** [top](https://git.kayg.org/attachments/b9b4fd3a-98e0-497f-86e2-01b7e806a82a) · [middle](https://git.kayg.org/attachments/c90ffc7f-72cb-4ceb-ae19-b234190c265b) · [typed](https://git.kayg.org/attachments/6a4b77dd-e2df-4538-a6b7-fd3ebcf5bd84) **390 dark:** [top](https://git.kayg.org/attachments/3caae50f-c5f0-4bc1-943d-fde94eaaf4bb) · [middle](https://git.kayg.org/attachments/234f701d-6c2a-4e64-86a0-f20472cf06bd) · [typed](https://git.kayg.org/attachments/b23f7537-902d-4ea5-b34e-a2ab244fef60) **820 light:** [top](https://git.kayg.org/attachments/5e85ebbb-7bb7-49a1-b5de-6daa071ebcc3) · [middle](https://git.kayg.org/attachments/d0e7f4be-242b-4f3d-aef1-903ad48d8daa) · [typed](https://git.kayg.org/attachments/38f4b528-26e9-4b95-9f06-8d2984bec04f) **820 dark:** [top](https://git.kayg.org/attachments/4b3301a6-70c9-4235-abf7-504ada35073d) · [middle](https://git.kayg.org/attachments/6b46be4c-cb8d-4645-a5c6-52de5f707be9) · [typed](https://git.kayg.org/attachments/70deaacf-286b-4abc-8350-83d7d1486979) **1440 light:** [top](https://git.kayg.org/attachments/3db88edb-8837-4973-b4ee-de5cb3a254de) · [middle](https://git.kayg.org/attachments/c5b3ef56-5510-49d9-a57b-8099e6015dc7) · [typed](https://git.kayg.org/attachments/98cef558-bd0a-486e-9580-15f72646f069) **1440 dark:** [top](https://git.kayg.org/attachments/de62d9f9-17fb-48f7-a824-18b378259578) · [middle](https://git.kayg.org/attachments/5c18aea0-7ed1-420d-a0a6-aeb3eb7f985a) · [typed](https://git.kayg.org/attachments/810c7232-6258-4beb-89c1-2bc1aff9081b) **Shortcut find:** [1440 light](https://git.kayg.org/attachments/30075615-60c8-411a-9ff3-fbe6900e8873)
Author
Owner

bignote3 started on job/bignote-1349, base/head bad252232f. No code changes before the controlled interleaved d395b6e25/bad252232 A/B (five pairs, 5k and 20k). Perf VM currently held by slowsel2-ab-retry; preparing isolated builds while waiting for perf-run. Then trace-led typing/scroll fixes and print/drift checks.

bignote3 started on job/bignote-1349, base/head bad252232fe61481836542fdbe4b9061f4330829. No code changes before the controlled interleaved d395b6e25/bad252232 A/B (five pairs, 5k and 20k). Perf VM currently held by slowsel2-ab-retry; preparing isolated builds while waiting for perf-run. Then trace-led typing/scroll fixes and print/drift checks.
Author
Owner

Controlled A/B is in progress under perf-run calternal bignote3-initial (five alternating-order pairs, 5k/20k, two distinct cold fixture Notes and a true warm switch-away/reopen per size). No tracked code has changed. A source-mapped headed Mac trace and the first locked VM 5k typing trace both identify two full-Note walks in inlineLinks (decoration rebuild and standalone preview collection), repeated anchor parsing, and posAtIndex prefix summation in Note Card dirty-range calculation. The 5k VM scroll trace has 2,491.5 ms of style recalculation and 1,242.7 ms of layout during the 50-wheel profile; Floating UI dimension reads have 2,945.8 ms sampled self time including forced rendering. The local existing risk probe reached its 600 s timeout without a PDF. Full paired table follows after all five pairs; production edits remain deferred until then.

Controlled A/B is in progress under perf-run calternal bignote3-initial (five alternating-order pairs, 5k/20k, two distinct cold fixture Notes and a true warm switch-away/reopen per size). No tracked code has changed. A source-mapped headed Mac trace and the first locked VM 5k typing trace both identify two full-Note walks in inlineLinks (decoration rebuild and standalone preview collection), repeated anchor parsing, and posAtIndex prefix summation in Note Card dirty-range calculation. The 5k VM scroll trace has 2,491.5 ms of style recalculation and 1,242.7 ms of layout during the 50-wheel profile; Floating UI dimension reads have 2,945.8 ms sampled self time including forced rendering. The local existing risk probe reached its 600 s timeout without a PDF. Full paired table follows after all five pairs; production edits remain deferred until then.
Author
Owner

New risk evidence, before any tracked edits: the original production risk probe timed out after 600 s without a PDF. A narrow print diagnostic that installs print block flow before changing media and hides fixed/decorative shell chrome completed a 1,542,883-byte PDF in 7.4 s. PDF.js reads 251 pages and confirms Block 5000 on the last page. These are temporary browser overrides, not a shipped fix; the production Card/shell fix and full risk rerun follow the initial five-pair A/B. A later caret probe ended at Block 2502 after 40 ArrowDown presses; its click coordinate is computed immediately after entering a deferred block, so the starting caret must be verified after layout settles without weakening the existing assertion.

New risk evidence, before any tracked edits: the original production risk probe timed out after 600 s without a PDF. A narrow print diagnostic that installs print block flow before changing media and hides fixed/decorative shell chrome completed a 1,542,883-byte PDF in 7.4 s. PDF.js reads 251 pages and confirms Block 5000 on the last page. These are temporary browser overrides, not a shipped fix; the production Card/shell fix and full risk rerun follow the initial five-pair A/B. A later caret probe ended at Block 2502 after 40 ArrowDown presses; its click coordinate is computed immediately after entering a deferred block, so the starting caret must be verified after layout settles without weakening the existing assertion.
Author
Owner

bignote3 controlled A/B completed before tracked changes. Branch remains clean at bad252232.

Compared exact production web builds d395b6e25 (dev) and bad252232 (head), same release server SHA256 9187026d117f4da1c62ba2e00581683cca9516c4804b58e9bab5885969d4f5bf, same browser/data/harness. Five interleaved pairs: dev/head, head/dev, dev/head, head/dev, dev/head. Each trial has fresh server/browser and both 5k/20k Notes. perf VM lock: perf-run calternal bignote3-initial 30; actual run 16:42:01–17:26:35 UTC. Load averages at trial start were 4.13–5.98 (1 min); no quiet-host filtering. Milliseconds except heap. Scroll frame samples include the same Chrome tracing overhead on both revisions.

Blocks Revision Cold open p50 / p95 Warm open p50 / p95 Top typing p50 / p95 Middle typing p50 / p95 End typing p50 / p95 Scroll-frame p95 Heap before / after (MiB)
5000 dev 3247.1 / 4869.1 1894.3 / 2431.9 55.5 / 125.2 67.1 / 165.3 81.9 / 214.4 266.7 31.1 / 39.4
5000 head 3406.3 / 4350.1 2019.4 / 2764 29.6 / 103.5 52.6 / 152.9 42.6 / 123.8 383.4 39.8 / 38.0
20000 dev 6803.2 / 8824.2 5388.9 / 5617.8 286.1 / 311.2 293 / 370.8 321.6 / 401.7 533.4 57.6 / 77.8
20000 head 6107.6 / 6943.1 5386 / 6300.9 146.4 / 255.5 168.9 / 261.2 193 / 290.7 933.3 73.8 / 67.4
Open percentiles pool all content-confirmed opens (10 cold / 5 warm per revision and size). Typing and scroll entries are medians of the five trial percentiles (20 untraced keys per position per trial). Heap is sampled before/after the same one-second final typing burst; this does not establish five-minute retention. The 20-key middle traces are separate from the typing samples. No slow trials are excluded.

The branch improves typing percentiles at both sizes and cold-open p95, but it does NOT consistently improve opening: warm-open p95 is worse at both sizes, and 5k cold-open p50 is worse. Scroll p95 is worse at both sizes. The 5k typing budget of 50 ms is missed at all positions.

20 middle keys at 5k, VM trace: sampled link decoration/preview work 171.6 ms (8.6/key); Card range work 99.1 ms (5.0/key); Yjs update/encode 80.6 ms (4.0/key); other decoration work 52.8 ms (2.6/key). Timeline Layout 159.5 ms (8.0/key), UpdateLayoutTree 26.9 ms (1.3/key). NoteView/save debounce sampled 2.0 ms total (0.1/key). NoteCardsLayer and toast dock have no sampled stack; Svelte effects are below reliable sample resolution. Sampled CPU and timeline categories overlap and must not be summed.

Scroll trace: UpdateLayoutTree 2,491.5 ms and Layout 1,242.7 ms; Floating UI getCssDimensions has 2,945.8 ms sampled self time including forced rendering. The synthetic stationary-pointer mousemove dispatch on each scroll frame repeatedly positions the drag handle.

Next fixes: remove prefix rescans in transaction-local ranges; rebuild links only in changed blocks; settle passive hover once scrolling stops; production print normal flow. Keep the guarded ProseMirror index and fallback test. No tracked code has changed yet.

bignote3 controlled A/B completed before tracked changes. Branch remains clean at bad252232. Compared exact production web builds d395b6e25 (dev) and bad252232 (head), same release server SHA256 9187026d117f4da1c62ba2e00581683cca9516c4804b58e9bab5885969d4f5bf, same browser/data/harness. Five interleaved pairs: dev/head, head/dev, dev/head, head/dev, dev/head. Each trial has fresh server/browser and both 5k/20k Notes. perf VM lock: perf-run calternal bignote3-initial 30; actual run 16:42:01–17:26:35 UTC. Load averages at trial start were 4.13–5.98 (1 min); no quiet-host filtering. Milliseconds except heap. Scroll frame samples include the same Chrome tracing overhead on both revisions. | Blocks | Revision | Cold open p50 / p95 | Warm open p50 / p95 | Top typing p50 / p95 | Middle typing p50 / p95 | End typing p50 / p95 | Scroll-frame p95 | Heap before / after (MiB) | | ---: | --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | | 5000 | dev | 3247.1 / 4869.1 | 1894.3 / 2431.9 | 55.5 / 125.2 | 67.1 / 165.3 | 81.9 / 214.4 | 266.7 | 31.1 / 39.4 | | 5000 | head | 3406.3 / 4350.1 | 2019.4 / 2764 | 29.6 / 103.5 | 52.6 / 152.9 | 42.6 / 123.8 | 383.4 | 39.8 / 38.0 | | 20000 | dev | 6803.2 / 8824.2 | 5388.9 / 5617.8 | 286.1 / 311.2 | 293 / 370.8 | 321.6 / 401.7 | 533.4 | 57.6 / 77.8 | | 20000 | head | 6107.6 / 6943.1 | 5386 / 6300.9 | 146.4 / 255.5 | 168.9 / 261.2 | 193 / 290.7 | 933.3 | 73.8 / 67.4 | Open percentiles pool all content-confirmed opens (10 cold / 5 warm per revision and size). Typing and scroll entries are medians of the five trial percentiles (20 untraced keys per position per trial). Heap is sampled before/after the same one-second final typing burst; this does not establish five-minute retention. The 20-key middle traces are separate from the typing samples. No slow trials are excluded. The branch improves typing percentiles at both sizes and cold-open p95, but it does NOT consistently improve opening: warm-open p95 is worse at both sizes, and 5k cold-open p50 is worse. Scroll p95 is worse at both sizes. The 5k typing budget of 50 ms is missed at all positions. 20 middle keys at 5k, VM trace: sampled link decoration/preview work 171.6 ms (8.6/key); Card range work 99.1 ms (5.0/key); Yjs update/encode 80.6 ms (4.0/key); other decoration work 52.8 ms (2.6/key). Timeline Layout 159.5 ms (8.0/key), UpdateLayoutTree 26.9 ms (1.3/key). NoteView/save debounce sampled 2.0 ms total (0.1/key). NoteCardsLayer and toast dock have no sampled stack; Svelte effects are below reliable sample resolution. Sampled CPU and timeline categories overlap and must not be summed. Scroll trace: UpdateLayoutTree 2,491.5 ms and Layout 1,242.7 ms; Floating UI getCssDimensions has 2,945.8 ms sampled self time including forced rendering. The synthetic stationary-pointer mousemove dispatch on each scroll frame repeatedly positions the drag handle. Next fixes: remove prefix rescans in transaction-local ranges; rebuild links only in changed blocks; settle passive hover once scrolling stops; production print normal flow. Keep the guarded ProseMirror index and fallback test. No tracked code has changed yet.
Author
Owner

bignote3 findings and commits:

  • e05f0588b removes repeated sibling-prefix scans from Card/local range lookup. Editor check: svelte-check found 0 errors and 0 warnings; focused range/Card/index tests: Test Files 3 passed (3), Tests 13 passed (13). Guarded private-field index and fallback remain intact.
  • 8e63bbb41 updates link decorations in changed blocks and derives preview requests from sparse widgets. 70b7367b7 synchronizes routed link DOM locally with WeakMap ownership. Focused link tests: Test Files 1 passed (1), Tests 17 passed (17), including 5k no-root-walk, duplicate ordinals and stable-link restoration.
  • 9a283c5ed settles stationary-pointer hover after scroll. Focused drag-handle tests: Test Files 1 passed (1), Tests 11 passed (11). Twenty scrolling events cause zero synthetic mouse moves during travel, then one settled refresh. Real pointer input stays immediate; keyboard focus/grab state stays visible.
  • 84d0c9890 maps Canvas widgets for plain-prose edits. Focused Canvas tests: Test Files 1 passed (1), Tests 5 passed (5). Actual embed edits retain the full sixteen-preview admission rule.
  • 3c6a330a7 adds shared Card printFlow and Note/shell normal flow. Shared Card/Canvas tests: Test Files 2 passed (2), Tests 15 passed (15). Production risk probe retained the original caret assertion and passed it after waiting for deferred pointer layout. The tightened fresh-before-print drift assertion also passed.

The PDF completeness assertion caught a real remaining print defect: a 122-page, 16 MB PDF repeated Blocks 1–17 and omitted Block 5000. Evidence: PDF text extraction from pages 120–122. The shell has fixed html/body positioning in calternal-app.css; the diagnostic override reset position too. The production fix now resets shell positioning for print and is rebuilding. I will rerun the same completeness assertion; a nonempty PDF is not sufficient.

8a358d08d retains raw CPU profiles and scroll traces in the existing benchmark, using twenty middle trace keys. Initial A/B table remains unchanged.

bignote3 findings and commits: - e05f0588b removes repeated sibling-prefix scans from Card/local range lookup. Editor check: `svelte-check found 0 errors and 0 warnings`; focused range/Card/index tests: `Test Files 3 passed (3)`, `Tests 13 passed (13)`. Guarded private-field index and fallback remain intact. - 8e63bbb41 updates link decorations in changed blocks and derives preview requests from sparse widgets. 70b7367b7 synchronizes routed link DOM locally with WeakMap ownership. Focused link tests: `Test Files 1 passed (1)`, `Tests 17 passed (17)`, including 5k no-root-walk, duplicate ordinals and stable-link restoration. - 9a283c5ed settles stationary-pointer hover after scroll. Focused drag-handle tests: `Test Files 1 passed (1)`, `Tests 11 passed (11)`. Twenty scrolling events cause zero synthetic mouse moves during travel, then one settled refresh. Real pointer input stays immediate; keyboard focus/grab state stays visible. - 84d0c9890 maps Canvas widgets for plain-prose edits. Focused Canvas tests: `Test Files 1 passed (1)`, `Tests 5 passed (5)`. Actual embed edits retain the full sixteen-preview admission rule. - 3c6a330a7 adds shared Card printFlow and Note/shell normal flow. Shared Card/Canvas tests: `Test Files 2 passed (2)`, `Tests 15 passed (15)`. Production risk probe retained the original caret assertion and passed it after waiting for deferred pointer layout. The tightened fresh-before-print drift assertion also passed. The PDF completeness assertion caught a real remaining print defect: a 122-page, 16 MB PDF repeated Blocks 1–17 and omitted Block 5000. Evidence: PDF text extraction from pages 120–122. The shell has fixed html/body positioning in calternal-app.css; the diagnostic override reset position too. The production fix now resets shell positioning for print and is rebuilding. I will rerun the same completeness assertion; a nonempty PDF is not sufficient. 8a358d08d retains raw CPU profiles and scroll traces in the existing benchmark, using twenty middle trace keys. Initial A/B table remains unchanged.
Author
Owner

bignote3 progress: the guarded ProseMirror decoration index and fallback test are retained. The first five-pair post-fix comparison is nearing completion; its production snapshot is frozen at eead8044a.

The new 20-key middle-of-5k trace attributes 2.202 ms total (0.110 ms/key) to link decorations/previews, compared with 171.636 ms total (8.582 ms/key) before the changes. Other sampled costs remain: Card decorations 85.633 ms (4.282 ms/key), other decorations 52.754 ms (2.638 ms/key), Yjs update/encode 94.896 ms (4.745 ms/key), Svelte effects 7.912 ms (0.396 ms/key), and NoteView/save 0.888 ms (0.044 ms/key). No NoteCardsLayer or toast-dock stack was sampled; this does not establish zero cost. Native Layout totals 150.661 ms (7.533 ms/key), style-tree update 31.671 ms (1.584 ms/key), and native intersection computation 305.300 ms (15.265 ms/key). These native totals overlap JS/event work and must not be added as independent latency. The native (program) samples are not source-attributed.

The fling trace still samples 2573.78 ms in Floating UI getCssDimensions, plus native intersection computation 3529.929 ms, Layout 1372.298 ms and style-tree update 2187.596 ms. The debounce alone did not remove the largest geometry cost. A follow-up slice suppresses same-coordinate passive mouse events during settling and uses Floating UI's existing fixed-position strategy for the viewport virtual reference. Physical pointer motion, dragging, and focused/grabbed keyboard handles remain immediate. Unit tests cover these contracts. No dependency was added.

Print now completes: 251 pages, final page contains Block 5000. The prior broken capture repeated the first 17 blocks over 122 pages; the fixed-position shell prevented pagination. Fresh deferred-block scrolling records 0 px scrollTop drift, and the stable Block 4000 link scrolls to its actual viewport position (204471 px). The current final screenshot set covers 390/820/1440 px in light and dark with macOS platform emulation. Native macOS measurements are queued behind the other tenant's lock.

Typing is still above 50 ms p95 in the first post-fix samples. This is not yet a budget-complete result. I will finish the controlled comparison and repeat it for the final scroll-positioning slice within this job's time limit.

bignote3 progress: the guarded ProseMirror decoration index and fallback test are retained. The first five-pair post-fix comparison is nearing completion; its production snapshot is frozen at eead8044a. The new 20-key middle-of-5k trace attributes 2.202 ms total (0.110 ms/key) to link decorations/previews, compared with 171.636 ms total (8.582 ms/key) before the changes. Other sampled costs remain: Card decorations 85.633 ms (4.282 ms/key), other decorations 52.754 ms (2.638 ms/key), Yjs update/encode 94.896 ms (4.745 ms/key), Svelte effects 7.912 ms (0.396 ms/key), and NoteView/save 0.888 ms (0.044 ms/key). No NoteCardsLayer or toast-dock stack was sampled; this does not establish zero cost. Native Layout totals 150.661 ms (7.533 ms/key), style-tree update 31.671 ms (1.584 ms/key), and native intersection computation 305.300 ms (15.265 ms/key). These native totals overlap JS/event work and must not be added as independent latency. The native `(program)` samples are not source-attributed. The fling trace still samples 2573.78 ms in Floating UI getCssDimensions, plus native intersection computation 3529.929 ms, Layout 1372.298 ms and style-tree update 2187.596 ms. The debounce alone did not remove the largest geometry cost. A follow-up slice suppresses same-coordinate passive mouse events during settling and uses Floating UI's existing fixed-position strategy for the viewport virtual reference. Physical pointer motion, dragging, and focused/grabbed keyboard handles remain immediate. Unit tests cover these contracts. No dependency was added. Print now completes: 251 pages, final page contains Block 5000. The prior broken capture repeated the first 17 blocks over 122 pages; the fixed-position shell prevented pagination. Fresh deferred-block scrolling records 0 px scrollTop drift, and the stable Block 4000 link scrolls to its actual viewport position (204471 px). The current final screenshot set covers 390/820/1440 px in light and dark with macOS platform emulation. Native macOS measurements are queued behind the other tenant's lock. Typing is still above 50 ms p95 in the first post-fix samples. This is not yet a budget-complete result. I will finish the controlled comparison and repeat it for the final scroll-positioning slice within this job's time limit.
Author
Owner

Five-pair post-fix comparison completed, d395b6e25 versus eead8044a (before the final handle positioning slice). This branch is not consistently better than dev on typing and open. It misses the 5k typing budget.

Blocks Revision Cold open p50 / p95 Warm open p50 / p95 Top typing p50 / p95 Middle typing p50 / p95 End typing p50 / p95 Scroll-frame p95 Heap before / after (MiB)
5000 dev 2746.4 / 4031.4 2097.3 / 2296.2 52.6 / 91.7 58.2 / 146.5 74.8 / 184.4 266.7 26.9 / 46.7
5000 head 3444.4 / 4274.7 1811.7 / 2342.6 27.9 / 83 53.1 / 149.6 44.2 / 121.5 300 39.8 / 30.6
20000 dev 6492.9 / 7627.9 5201.4 / 5262.6 245.1 / 310.3 297.8 / 386 337.4 / 407.5 549.9 62.7 / 57.0
20000 head 6247.3 / 9096.7 4871.3 / 7165.1 127.2 / 228.4 141.7 / 229.5 150.3 / 209.5 866.6 70.1 / 78.0
Open percentiles pool all content-confirmed opens (10 cold / 5 warm per revision and size). Typing and scroll entries are medians of the five trial percentiles (20 untraced keys per position per trial). Heap is sampled before/after the same one-second final typing burst; this does not establish five-minute retention. The 20-key middle traces are separate from the typing samples. No slow trials are excluded.

The 5k middle typing p95 is 149.6 ms versus dev 146.5 ms. Open p95 is worse in all four cold/warm × size cases. Scroll p95 is worse at both sizes. Top/end typing improves, and 20k typing improves, but these changes do not establish an acceptable overall result.

Measurement qualification: both the initial table and this table used the same pointer-targeting setup, but did not assert the caret block after deferred layout. Treat their top/middle/end labels as intended positions, not verified caret positions. Open measurements remain content-confirmed. The final comparison now waits for deferred geometry and asserts the actual Block number before every typing phase. Its source-attributed 20-key middle trace will have the same assertion.

The final handle slice is 443864508. A separate native-layout diagnostic is running under perf-run before the verified five-pair final comparison. All raw trials, including slow trials, are retained.

Five-pair post-fix comparison completed, d395b6e25 versus eead8044a (before the final handle positioning slice). **This branch is not consistently better than dev on typing and open.** It misses the 5k typing budget. | Blocks | Revision | Cold open p50 / p95 | Warm open p50 / p95 | Top typing p50 / p95 | Middle typing p50 / p95 | End typing p50 / p95 | Scroll-frame p95 | Heap before / after (MiB) | | ---: | --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | | 5000 | dev | 2746.4 / 4031.4 | 2097.3 / 2296.2 | 52.6 / 91.7 | 58.2 / 146.5 | 74.8 / 184.4 | 266.7 | 26.9 / 46.7 | | 5000 | head | 3444.4 / 4274.7 | 1811.7 / 2342.6 | 27.9 / 83 | 53.1 / 149.6 | 44.2 / 121.5 | 300 | 39.8 / 30.6 | | 20000 | dev | 6492.9 / 7627.9 | 5201.4 / 5262.6 | 245.1 / 310.3 | 297.8 / 386 | 337.4 / 407.5 | 549.9 | 62.7 / 57.0 | | 20000 | head | 6247.3 / 9096.7 | 4871.3 / 7165.1 | 127.2 / 228.4 | 141.7 / 229.5 | 150.3 / 209.5 | 866.6 | 70.1 / 78.0 | Open percentiles pool all content-confirmed opens (10 cold / 5 warm per revision and size). Typing and scroll entries are medians of the five trial percentiles (20 untraced keys per position per trial). Heap is sampled before/after the same one-second final typing burst; this does not establish five-minute retention. The 20-key middle traces are separate from the typing samples. No slow trials are excluded. The 5k middle typing p95 is 149.6 ms versus dev 146.5 ms. Open p95 is worse in all four cold/warm × size cases. Scroll p95 is worse at both sizes. Top/end typing improves, and 20k typing improves, but these changes do not establish an acceptable overall result. Measurement qualification: both the initial table and this table used the same pointer-targeting setup, but did not assert the caret block after deferred layout. Treat their top/middle/end labels as intended positions, not verified caret positions. Open measurements remain content-confirmed. The final comparison now waits for deferred geometry and asserts the actual Block number before every typing phase. Its source-attributed 20-key middle trace will have the same assertion. The final handle slice is 443864508. A separate native-layout diagnostic is running under perf-run before the verified five-pair final comparison. All raw trials, including slow trials, are retained.
Author
Owner

Corrected measurement finding (bignote3, source 923307029): the two completed pairs below assert the actual caret Block and actual wheel travel. This branch is not consistently better than dev on typing and open. The 5k middle typing p95 is 235.7 ms versus dev 158.7 ms; the 50 ms target is not met. These are TWO pairs, not the requested five. All trials, including the slow second head trial, are retained.

Blocks Revision Cold open p50 / p95 Warm open p50 / p95 Top typing p50 / p95 Middle typing p50 / p95 End typing p50 / p95 Scroll-frame p95 Heap before / after (MiB)
5000 dev 2717.3 / 4381.7 1440.6 / 1758 46.1 / 83.5 59.0 / 158.7 75.5 / 169.7 275.0 29.6 / 27.9
5000 head 3555.6 / 4076 1769.6 / 1954.7 27.4 / 77.2 61.3 / 235.7 48.3 / 145.4 308.4 32.3 / 35.1
20000 dev 6140.9 / 6898 4496.7 / 5313.8 246.2 / 322.0 284.5 / 337.3 332.1 / 460.8 558.3 68.1 / 60.8
20000 head 6601 / 7066.9 4793.4 / 5127 87.8 / 195.1 71.4 / 146.7 105.7 / 165.8 941.5 60.2 / 73.8
Open percentiles pool all content-confirmed opens (4 cold / 2 warm per revision and size). Typing and scroll entries are medians of the two trial percentiles (20 untraced keys per position per trial). Heap is sampled before/after the same one-second final typing burst; this does not establish five-minute retention. The 20-key middle traces are separate from the typing samples. No slow trials are excluded.

Correction to earlier evidence: the earlier five-pair scroll probes reset window.scrollTo while the fixed shell uses #route-content. They did not establish a real fling and must not be used as scroll improvement evidence. Earlier typing labels also did not verify the post-layout caret.

Risk finding: the review probe could serve the shared server embedded dev assets unless CALTERNAL_E2E_ASSET_OVERRIDE was set. The probe now requires its own frozen production assets. Earlier risk failures from runs without that flag are not evidence about this branch. The verified production probe found a real 26 px bottom drift: the terminal empty paragraph has one line but its deferred estimate was two. A CSS exception lays out that one empty paragraph, preserving deferral of other blocks. The final production drift probe now reports maxInputDrift=0, maxClampPx=0 and end=finalMaximum=255696. PDF completion is still being checked.

The final production rerun is queued behind the perf-run lock holder searchperf2 (started 19:51 UTC, expected 40 minutes). The real macOS GPU run is also queued under the required locks. The job ends at its four-hour deadline, 20:29 UTC; unfinished requested measurements will be reported explicitly. No runtime feature changes are planned after the terminal paragraph correction.

Corrected measurement finding (bignote3, source 923307029): the two completed pairs below assert the actual caret Block and actual wheel travel. This branch is not consistently better than dev on typing and open. The 5k middle typing p95 is 235.7 ms versus dev 158.7 ms; the 50 ms target is not met. These are TWO pairs, not the requested five. All trials, including the slow second head trial, are retained. | Blocks | Revision | Cold open p50 / p95 | Warm open p50 / p95 | Top typing p50 / p95 | Middle typing p50 / p95 | End typing p50 / p95 | Scroll-frame p95 | Heap before / after (MiB) | | ---: | --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | | 5000 | dev | 2717.3 / 4381.7 | 1440.6 / 1758 | 46.1 / 83.5 | 59.0 / 158.7 | 75.5 / 169.7 | 275.0 | 29.6 / 27.9 | | 5000 | head | 3555.6 / 4076 | 1769.6 / 1954.7 | 27.4 / 77.2 | 61.3 / 235.7 | 48.3 / 145.4 | 308.4 | 32.3 / 35.1 | | 20000 | dev | 6140.9 / 6898 | 4496.7 / 5313.8 | 246.2 / 322.0 | 284.5 / 337.3 | 332.1 / 460.8 | 558.3 | 68.1 / 60.8 | | 20000 | head | 6601 / 7066.9 | 4793.4 / 5127 | 87.8 / 195.1 | 71.4 / 146.7 | 105.7 / 165.8 | 941.5 | 60.2 / 73.8 | Open percentiles pool all content-confirmed opens (4 cold / 2 warm per revision and size). Typing and scroll entries are medians of the two trial percentiles (20 untraced keys per position per trial). Heap is sampled before/after the same one-second final typing burst; this does not establish five-minute retention. The 20-key middle traces are separate from the typing samples. No slow trials are excluded. Correction to earlier evidence: the earlier five-pair scroll probes reset window.scrollTo while the fixed shell uses #route-content. They did not establish a real fling and must not be used as scroll improvement evidence. Earlier typing labels also did not verify the post-layout caret. Risk finding: the review probe could serve the shared server embedded dev assets unless CALTERNAL_E2E_ASSET_OVERRIDE was set. The probe now requires its own frozen production assets. Earlier risk failures from runs without that flag are not evidence about this branch. The verified production probe found a real 26 px bottom drift: the terminal empty paragraph has one line but its deferred estimate was two. A CSS exception lays out that one empty paragraph, preserving deferral of other blocks. The final production drift probe now reports maxInputDrift=0, maxClampPx=0 and end=finalMaximum=255696. PDF completion is still being checked. The final production rerun is queued behind the perf-run lock holder searchperf2 (started 19:51 UTC, expected 40 minutes). The real macOS GPU run is also queued under the required locks. The job ends at its four-hour deadline, 20:29 UTC; unfinished requested measurements will be reported explicitly. No runtime feature changes are planned after the terminal paragraph correction.
Author
Owner

bignote3 final report, #1349. Head 0743d5a9ad. TASK INCOMPLETE: the 5k typing target is not met. No push, deploy or merge into dev was done. The explicitly requested origin/dev integration was performed once (af202e151).

Built: transaction-local link decorations and stable link DOM updates; Canvas preview mapping for plain block edits; guarded sparse node-decoration mapping; stationary pointer suppression during scrolling; viewport-based shared drag-handle positioning; complete Note print layout; a one-block empty-tail exception that removes bottom scroll drift. The guarded ProseMirror private-field index and native fallback test remain. Benchmarks retain raw CPU profiles and Chrome traces, verify actual caret Blocks and real feed scroll travel, and keep all slow trials.

Files authored in this round:

  • packages/editor/src/transactionRanges.ts
  • packages/editor/src/transactionRanges.test.ts
  • packages/editor/src/indexedDecorationSet.ts
  • packages/editor/src/indexedDecorationSet.test.ts
  • packages/editor/src/extensions.ts
  • packages/editor/src/extensions.dragHandle.test.ts
  • packages/editor/src/components/NoteCardsLayer.svelte
  • packages/editor/package.json
  • apps/web/src/lib/notes/inlineLinks.ts
  • apps/web/src/lib/notes/inlineLinks.test.ts
  • apps/web/src/lib/notes/editor-types/indexedDecorationSet.d.ts
  • apps/web/src/lib/notes/editor-types/transactionRanges.d.ts
  • apps/web/src/lib/canvas/embeds.ts
  • apps/web/src/lib/canvas/embeds.test.ts
  • apps/web/src/lib/notes/NoteView.svelte
  • apps/web/src/lib/notes/noteProse.css
  • apps/web/src/routes/layout.css
  • apps/web/e2e/bignote-1349-risk.mjs
  • bench/bignote-1349.mjs
  • contracts/perf/exceptions.json
  • contracts/perf/adoption-1058.json

The continued branch also contains the previous rounds' block-anchor/document-decoration ownership, NoteCardsLayer and toast-dock optimizations. Shared Card and token changes made during this round were reverted to origin/dev; no new visible control or local shared-primitive styling ships. Shared controls remain Card, Button/IconButton, the existing drag handle and global search.

Performance: final production source 0743d5a9a versus pinned dev d395b6e25, two interleaved pairs (dev/head, head/dev), under perf-run. The final source was copied; no build ran on the VM. The same release server binary and guarded caret/wheel protocol were used. The lock became available at 20:02:48 UTC and the campaign stopped at its time-box boundary after the second pair at 20:19:23 UTC. This is TWO final pairs, not the requested five.

Blocks Revision Cold open p50 / p95 Warm open p50 / p95 Top typing p50 / p95 Middle typing p50 / p95 End typing p50 / p95 Scroll-frame p95 Heap before / after (MiB)
5000 dev 2683.4 / 4056.5 2160.6 / 2464.4 51.5 / 132.9 60.8 / 171.2 77.9 / 192.2 241.7 28.3 / 27.6
5000 head 2715.4 / 4245.1 1935.2 / 2023.9 15.3 / 113.5 51.0 / 119.3 54.6 / 128.4 250.1 34.2 / 29.6
20000 dev 6416.9 / 7092.9 4740.3 / 5211.4 271.4 / 311.4 297.4 / 365.9 278.4 / 463.1 533.3 63.9 / 71.9
20000 head 4888.2 / 5387.1 3950.5 / 4139.9 84.5 / 160.9 69.7 / 149.6 111.0 / 234.4 725.0 64.5 / 75.7
Open percentiles pool all content-confirmed opens (4 cold / 2 warm per revision and size). Typing and scroll entries are medians of the two trial percentiles (20 untraced keys per position per trial). Heap is sampled before/after the same one-second final typing burst; this does not establish five-minute retention. The 20-key middle traces are separate from the typing samples. No slow trials are excluded.

Typing improves at both sizes in this limited final comparison. The 5k middle typing p95 is 119.3 ms versus dev 171.2 ms, so the <=50 ms target still fails. The head trials are 134.2 and 104.5 ms. At 20k, cold/warm opens and typing improve. This branch is not consistently better on typing and open: 5k cold-open p95 is worse (4245.1 versus 4056.5 ms). Scroll p95 is worse at both sizes (250.1 versus 241.7 ms; 725.0 versus 533.3 ms). All eight sustained typing/save checks confirm that every inserted key reached both the live Note and durable storage.

The initial five-pair d395b6e25/bad252232 and intermediate five-pair d395b6e25/eead8044a tables are posted above. Their opens are content-confirmed, but their intended typing positions and real wheel travel were not verified; do not use their typing position or scroll claims as controlled evidence. The corrected exploratory 923307029 comparison and raw evidence remain posted, including its slow head trial. No slow trials were removed.

Verified 20-key middle typing trace (5k, source 923307029): sampled attribution is Yjs update/encode 5.99 ms/key; ProseMirror tree traversal 4.21; ProseMirror view 4.35; Card decoration ranges 0.66; other decorations 0.95; links 0.06; save debounce/NoteView 0.44; Svelte effects below the sampling resolution. NoteCardsLayer and toast dock had no attributed samples, which does not establish zero cost. Chrome Timeline reports layout 7.78 ms/key, style-tree update 1.63, and native intersection computation 14.05. These overlapping layers must not be summed as wall-clock latency. Unattributed native program time remains large. Card mapping was 4.28 ms/key in the earlier trace; the guarded single-step map avoids validating unchanged sparse spans.

Verified 5k real-fling trace: native intersection computation totals 3617.39 ms; style-tree update 1267.54; layout 1026.22; sampled Floating UI getCssDimensions 1455.66 ms; caretPositionFromPoint in BlockHoverActions 555.43 ms plus drag-handle caret lookup 151.61 ms. The stationary-pointer and viewport-reference fixes do not remove all hover/position work. The largest remaining scroll costs are not solved. Remaining full-document JavaScript work includes TipTap code-block-lowlight findChildren/nodesBetween and Yjs binding traversal. Fixing these without breaking collaboration needs another tested slice; no unsafe third-party shortcut was added.

Expected cost: changed-block traversal is changed Blocks plus a fixed neighbor margin; plain Canvas edits map existing sparse previews; the guarded node-decoration map is proportional to sparse decorations and validates only touched spans. Compound maps and unsupported private shapes use native behavior. This does not establish edited-block-only cost for every keystroke: ProseMirror/Yjs/native layout still consume Note-size-dependent work. The new empty-tail rule adds one laid-out empty paragraph. docs/perf/baseline.json has no directly comparable controlled bignote profile; pinned d395b6e25 is the comparison baseline.

Risk proof: the final frozen production assets passed the focused risk probe. Print generated a 2,764,161-byte PDF containing the first and last of 5,000 Blocks. Fresh deferred scrolling reached the exact bottom with maxInputDrift=0 px, maxClampPx=0 px, end=finalMaximum=255696. Stable Block 4000 links, browser Find, middle caret movement and Select All also passed. risk-tail-production.log bignote-1349-print.pdf

UX gaps closed: full-document print pagination; bottom scroll drift; pointer-triggered typing focus proof; real deep-link viewport confirmation. Screenshot typing now restores the whole paragraph after Undo, instead of merely waiting for a two-character marker to disappear. The risk probe explicitly serves this job's production assets.

Gates (verbatim summaries; linked files contain the complete unmodified output):

cd packages/editor && bun run test --maxWorkers=2


 Test Files  26 passed (26)
      Tests  485 passed (485)
   Start at  20:50:05
   Duration  82.42s (transform 11.34s, setup 2.05s, import 31.54s, tests 30.69s, environment 82.67s)

gate-editor-map.log

cd apps/web && bun run check

svelte-check found 0 errors and 4 warnings in 2 files

gate-web-check-tail.log

cd apps/web && bun run test --maxWorkers=2

 Test Files  297 passed (297)
      Tests  2126 passed (2126)
   Start at  20:46:25
   Duration  752.07s (transform 32%, environment 24%, import 24%, tests 14%, setup 6%)

gate-web-test-fixed.log

The last CSS-only correction was checked by bun run check and the real production regression probe. No Rust source was authored or server built in this job. No dependencies were added.

Decisions: use the existing Photos-derived 140 ms passive hover settle delay; retain immediate real pointer, button and keyboard actions; use the shared drag handle's existing viewport positioning configuration rather than runtime whole-editor geometry reads. Keep content-visibility enabled: the diagnostic that disabled it did not improve all typing positions. Lay out only a terminal empty paragraph to fix its intrinsic-height mismatch. Keep shared Card material and hide editing-only controls in print. No product behavior decision marked OPEN was built.

Known gaps / UX gaps left: 5k typing <=50 ms; open/scroll budgets; five correctly targeted final interleaved pairs; five-minute memory retention; complete real macOS before/after control. Native timing and capture status are given below. Corrected raw evidence: verified-evidence.tar.gz.

verified-typing-attributed.json

verified-scroll-attributed.json

review-tail-clean.log

Native macOS confirmation (one final-head trial, 5k, release server, actual Chrome/Metal GPU; not an A/B): cold open p50/p95 4760.2/8846.6 ms; warm 3782.3 ms; typing top 36.2/64.4, middle 38.4/130.6, end 59.2/108.6 ms (p50/p95, 20 verified keys per position); real fling scroll-frame p95 383.1 ms, scrollTop 0 -> 30000. Renderer heap 28,599,480 bytes, 12,846 DOM nodes. Metal GPU compositing is enabled; Mac load average inside the lock was {5.19 5.19 4.48}. The process host/load fields in the profile describe the local server/controller, not the Mac; GPU fields and renderer metrics come from the remote browser. The <=50 ms target fails on the Mac too.

An initial native run with the debug server reached the real "This note could not be opened" state and timed out with no editor. It is retained as a failure, not a latency sample. The focused release-server retry opened the same fixture shape and completed typing. The earlier failure's cause is not established; no claim is made that it is fixed or only host load.

Review: 19 production captures with macOS platform glyphs passed at 390/820/1440 px, light/dark; no loading placeholders or update toast. The real Mac produced all 24 large-Note captures (top, middle, pointer typing, opening Cmd+K) at the same six width/theme combinations. Pointer and shortcut outline assertions passed. Four of six nearest existing Small Note comparison captures completed; the twenty-minute browser lease ended before dark tablet/desktop comparisons. Claude must review visual quality; the captures are evidence, not an aesthetic approval.

The native measurement JSON retains a failure from the later comparison helper (it attempted a hidden phone sidebar row). Its preceding 5k open/typing/fling phases completed; a direct stable-link helper obtained four comparison captures before browser shutdown. Native 20k timing and a native before/after control remain undone.

tail-two-table.md

tail-results.tar.gz

tail-traces.tar.gz

bignote3-mac-tail.json

Native screenshot evidence (actual-size PNGs, Metal macOS rendering):

Cleanup: cargo clean completed (Removed 1 file, 356B total); web build and Svelte output were deleted. Temporary local test data was deleted. All owned measured runs and queued browser attempts are stopped; the perf lock and the original Mac browser lease were released. The remaining two comparison screenshots are not presented as complete. No screenshots or review artifacts were committed. Worktree status is clean.

Mac download cleanup: not verified; the local Mac lock was occupied. Own files may remain under ~/calternal-bench/bignote3 and must be deleted when the lock is available.

bignote3 final report, #1349. Head 0743d5a9ad8b2567719e001d063c7a4e2decf7e6. TASK INCOMPLETE: the 5k typing target is not met. No push, deploy or merge into dev was done. The explicitly requested origin/dev integration was performed once (af202e151). Built: transaction-local link decorations and stable link DOM updates; Canvas preview mapping for plain block edits; guarded sparse node-decoration mapping; stationary pointer suppression during scrolling; viewport-based shared drag-handle positioning; complete Note print layout; a one-block empty-tail exception that removes bottom scroll drift. The guarded ProseMirror private-field index and native fallback test remain. Benchmarks retain raw CPU profiles and Chrome traces, verify actual caret Blocks and real feed scroll travel, and keep all slow trials. Files authored in this round: - `packages/editor/src/transactionRanges.ts` - `packages/editor/src/transactionRanges.test.ts` - `packages/editor/src/indexedDecorationSet.ts` - `packages/editor/src/indexedDecorationSet.test.ts` - `packages/editor/src/extensions.ts` - `packages/editor/src/extensions.dragHandle.test.ts` - `packages/editor/src/components/NoteCardsLayer.svelte` - `packages/editor/package.json` - `apps/web/src/lib/notes/inlineLinks.ts` - `apps/web/src/lib/notes/inlineLinks.test.ts` - `apps/web/src/lib/notes/editor-types/indexedDecorationSet.d.ts` - `apps/web/src/lib/notes/editor-types/transactionRanges.d.ts` - `apps/web/src/lib/canvas/embeds.ts` - `apps/web/src/lib/canvas/embeds.test.ts` - `apps/web/src/lib/notes/NoteView.svelte` - `apps/web/src/lib/notes/noteProse.css` - `apps/web/src/routes/layout.css` - `apps/web/e2e/bignote-1349-risk.mjs` - `bench/bignote-1349.mjs` - `contracts/perf/exceptions.json` - `contracts/perf/adoption-1058.json` The continued branch also contains the previous rounds' block-anchor/document-decoration ownership, NoteCardsLayer and toast-dock optimizations. Shared Card and token changes made during this round were reverted to origin/dev; no new visible control or local shared-primitive styling ships. Shared controls remain Card, Button/IconButton, the existing drag handle and global search. Performance: final production source 0743d5a9a versus pinned dev d395b6e25, two interleaved pairs (dev/head, head/dev), under perf-run. The final source was copied; no build ran on the VM. The same release server binary and guarded caret/wheel protocol were used. The lock became available at 20:02:48 UTC and the campaign stopped at its time-box boundary after the second pair at 20:19:23 UTC. This is TWO final pairs, not the requested five. | Blocks | Revision | Cold open p50 / p95 | Warm open p50 / p95 | Top typing p50 / p95 | Middle typing p50 / p95 | End typing p50 / p95 | Scroll-frame p95 | Heap before / after (MiB) | | ---: | --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | | 5000 | dev | 2683.4 / 4056.5 | 2160.6 / 2464.4 | 51.5 / 132.9 | 60.8 / 171.2 | 77.9 / 192.2 | 241.7 | 28.3 / 27.6 | | 5000 | head | 2715.4 / 4245.1 | 1935.2 / 2023.9 | 15.3 / 113.5 | 51.0 / 119.3 | 54.6 / 128.4 | 250.1 | 34.2 / 29.6 | | 20000 | dev | 6416.9 / 7092.9 | 4740.3 / 5211.4 | 271.4 / 311.4 | 297.4 / 365.9 | 278.4 / 463.1 | 533.3 | 63.9 / 71.9 | | 20000 | head | 4888.2 / 5387.1 | 3950.5 / 4139.9 | 84.5 / 160.9 | 69.7 / 149.6 | 111.0 / 234.4 | 725.0 | 64.5 / 75.7 | Open percentiles pool all content-confirmed opens (4 cold / 2 warm per revision and size). Typing and scroll entries are medians of the two trial percentiles (20 untraced keys per position per trial). Heap is sampled before/after the same one-second final typing burst; this does not establish five-minute retention. The 20-key middle traces are separate from the typing samples. No slow trials are excluded. Typing improves at both sizes in this limited final comparison. The 5k middle typing p95 is 119.3 ms versus dev 171.2 ms, so the <=50 ms target still fails. The head trials are 134.2 and 104.5 ms. At 20k, cold/warm opens and typing improve. This branch is not consistently better on typing and open: 5k cold-open p95 is worse (4245.1 versus 4056.5 ms). Scroll p95 is worse at both sizes (250.1 versus 241.7 ms; 725.0 versus 533.3 ms). All eight sustained typing/save checks confirm that every inserted key reached both the live Note and durable storage. The initial five-pair d395b6e25/bad252232 and intermediate five-pair d395b6e25/eead8044a tables are posted above. Their opens are content-confirmed, but their intended typing positions and real wheel travel were not verified; do not use their typing position or scroll claims as controlled evidence. The corrected exploratory 923307029 comparison and raw evidence remain posted, including its slow head trial. No slow trials were removed. Verified 20-key middle typing trace (5k, source 923307029): sampled attribution is Yjs update/encode 5.99 ms/key; ProseMirror tree traversal 4.21; ProseMirror view 4.35; Card decoration ranges 0.66; other decorations 0.95; links 0.06; save debounce/NoteView 0.44; Svelte effects below the sampling resolution. NoteCardsLayer and toast dock had no attributed samples, which does not establish zero cost. Chrome Timeline reports layout 7.78 ms/key, style-tree update 1.63, and native intersection computation 14.05. These overlapping layers must not be summed as wall-clock latency. Unattributed native program time remains large. Card mapping was 4.28 ms/key in the earlier trace; the guarded single-step map avoids validating unchanged sparse spans. Verified 5k real-fling trace: native intersection computation totals 3617.39 ms; style-tree update 1267.54; layout 1026.22; sampled Floating UI getCssDimensions 1455.66 ms; caretPositionFromPoint in BlockHoverActions 555.43 ms plus drag-handle caret lookup 151.61 ms. The stationary-pointer and viewport-reference fixes do not remove all hover/position work. The largest remaining scroll costs are not solved. Remaining full-document JavaScript work includes TipTap code-block-lowlight findChildren/nodesBetween and Yjs binding traversal. Fixing these without breaking collaboration needs another tested slice; no unsafe third-party shortcut was added. Expected cost: changed-block traversal is changed Blocks plus a fixed neighbor margin; plain Canvas edits map existing sparse previews; the guarded node-decoration map is proportional to sparse decorations and validates only touched spans. Compound maps and unsupported private shapes use native behavior. This does not establish edited-block-only cost for every keystroke: ProseMirror/Yjs/native layout still consume Note-size-dependent work. The new empty-tail rule adds one laid-out empty paragraph. docs/perf/baseline.json has no directly comparable controlled bignote profile; pinned d395b6e25 is the comparison baseline. Risk proof: the final frozen production assets passed the focused risk probe. Print generated a 2,764,161-byte PDF containing the first and last of 5,000 Blocks. Fresh deferred scrolling reached the exact bottom with maxInputDrift=0 px, maxClampPx=0 px, end=finalMaximum=255696. Stable Block 4000 links, browser Find, middle caret movement and Select All also passed. [risk-tail-production.log](https://git.kayg.org/attachments/fb8782e7-5fd2-4b7d-a31c-193fb5339a5d) [bignote-1349-print.pdf](https://git.kayg.org/attachments/c2c8de4f-98b5-4d31-94a8-03ae1947e5be) UX gaps closed: full-document print pagination; bottom scroll drift; pointer-triggered typing focus proof; real deep-link viewport confirmation. Screenshot typing now restores the whole paragraph after Undo, instead of merely waiting for a two-character marker to disappear. The risk probe explicitly serves this job's production assets. Gates (verbatim summaries; linked files contain the complete unmodified output): `cd packages/editor && bun run test --maxWorkers=2` ``` Test Files 26 passed (26) Tests 485 passed (485) Start at 20:50:05 Duration 82.42s (transform 11.34s, setup 2.05s, import 31.54s, tests 30.69s, environment 82.67s) ``` [gate-editor-map.log](https://git.kayg.org/attachments/03a90084-44a6-4a12-9932-8932305da364) `cd apps/web && bun run check` ``` svelte-check found 0 errors and 4 warnings in 2 files ``` [gate-web-check-tail.log](https://git.kayg.org/attachments/a0100579-c007-4959-a158-99b1897a12ce) `cd apps/web && bun run test --maxWorkers=2` ``` Test Files 297 passed (297) Tests 2126 passed (2126) Start at 20:46:25 Duration 752.07s (transform 32%, environment 24%, import 24%, tests 14%, setup 6%) ``` [gate-web-test-fixed.log](https://git.kayg.org/attachments/5c2ea118-98ba-4116-90ed-b9056dfa66f6) The last CSS-only correction was checked by bun run check and the real production regression probe. No Rust source was authored or server built in this job. No dependencies were added. Decisions: use the existing Photos-derived 140 ms passive hover settle delay; retain immediate real pointer, button and keyboard actions; use the shared drag handle's existing viewport positioning configuration rather than runtime whole-editor geometry reads. Keep content-visibility enabled: the diagnostic that disabled it did not improve all typing positions. Lay out only a terminal empty paragraph to fix its intrinsic-height mismatch. Keep shared Card material and hide editing-only controls in print. No product behavior decision marked OPEN was built. Known gaps / UX gaps left: 5k typing <=50 ms; open/scroll budgets; five correctly targeted final interleaved pairs; five-minute memory retention; complete real macOS before/after control. Native timing and capture status are given below. Corrected raw evidence: [verified-evidence.tar.gz](https://git.kayg.org/attachments/9ded1e9f-911d-449e-81ad-9951c7efdd94). [verified-typing-attributed.json](https://git.kayg.org/attachments/f164438d-f062-4822-b167-038437d77147) [verified-scroll-attributed.json](https://git.kayg.org/attachments/d19084fc-14a6-4269-88b0-90581b6e49c5) [review-tail-clean.log](https://git.kayg.org/attachments/913d01f0-34e4-4593-bfd1-3a38910a6918) Native macOS confirmation (one final-head trial, 5k, release server, actual Chrome/Metal GPU; not an A/B): cold open p50/p95 4760.2/8846.6 ms; warm 3782.3 ms; typing top 36.2/64.4, middle 38.4/130.6, end 59.2/108.6 ms (p50/p95, 20 verified keys per position); real fling scroll-frame p95 383.1 ms, scrollTop 0 -> 30000. Renderer heap 28,599,480 bytes, 12,846 DOM nodes. Metal GPU compositing is enabled; Mac load average inside the lock was {5.19 5.19 4.48}. The process host/load fields in the profile describe the local server/controller, not the Mac; GPU fields and renderer metrics come from the remote browser. The <=50 ms target fails on the Mac too. An initial native run with the debug server reached the real "This note could not be opened" state and timed out with no editor. It is retained as a failure, not a latency sample. The focused release-server retry opened the same fixture shape and completed typing. The earlier failure's cause is not established; no claim is made that it is fixed or only host load. Review: 19 production captures with macOS platform glyphs passed at 390/820/1440 px, light/dark; no loading placeholders or update toast. The real Mac produced all 24 large-Note captures (top, middle, pointer typing, opening Cmd+K) at the same six width/theme combinations. Pointer and shortcut outline assertions passed. Four of six nearest existing Small Note comparison captures completed; the twenty-minute browser lease ended before dark tablet/desktop comparisons. Claude must review visual quality; the captures are evidence, not an aesthetic approval. The native measurement JSON retains a failure from the later comparison helper (it attempted a hidden phone sidebar row). Its preceding 5k open/typing/fling phases completed; a direct stable-link helper obtained four comparison captures before browser shutdown. Native 20k timing and a native before/after control remain undone. [tail-two-table.md](https://git.kayg.org/attachments/984f3a7c-82d6-4694-9ac7-86661dd2125e) [tail-results.tar.gz](https://git.kayg.org/attachments/376cb1a7-dd1f-4a07-be73-3492ff06cd4f) [tail-traces.tar.gz](https://git.kayg.org/attachments/782d8131-2ffb-40b1-9bba-aa7c6535a9cd) [bignote3-mac-tail.json](https://git.kayg.org/attachments/f0f6e1f6-7e50-4e0f-807d-851859841285) Native screenshot evidence (actual-size PNGs, Metal macOS rendering): - [existing-small-1440-light.png](https://git.kayg.org/attachments/3d8d9565-1d21-4f41-9ec3-3d669c9fd7a2) - [existing-small-390-dark.png](https://git.kayg.org/attachments/06c1b8d2-921b-4bce-9a76-956be98835ac) - [existing-small-390-light.png](https://git.kayg.org/attachments/76940ddd-a886-41d3-9617-872780454140) - [existing-small-820-light.png](https://git.kayg.org/attachments/35010965-4772-4697-9ab5-876a16c4f299) - [native-1440-dark-middle.png](https://git.kayg.org/attachments/75384d61-4591-430e-994c-20109aac9d90) - [native-1440-dark-shortcut.png](https://git.kayg.org/attachments/a28047c5-5484-4b1f-8c16-d5298cabd7fc) - [native-1440-dark-top.png](https://git.kayg.org/attachments/759e1c79-b1ab-4fb5-a2a3-5da337d5827e) - [native-1440-dark-typed.png](https://git.kayg.org/attachments/251c7195-9ec8-48e3-92d2-76777523051a) - [native-1440-light-middle.png](https://git.kayg.org/attachments/eab725f5-3e6d-40b8-9d33-dbff9f0350a9) - [native-1440-light-shortcut.png](https://git.kayg.org/attachments/ff1a851e-7ad4-4b6c-a8af-d8e7d51044bb) - [native-1440-light-top.png](https://git.kayg.org/attachments/5db383f6-4628-42d8-baf5-0377a075e250) - [native-1440-light-typed.png](https://git.kayg.org/attachments/1a4e8f9f-d814-40a9-8f29-1074b59d3f52) - [native-390-dark-middle.png](https://git.kayg.org/attachments/8b2a7380-5b18-4adf-893e-0dda5ab5cdb0) - [native-390-dark-shortcut.png](https://git.kayg.org/attachments/1e0a3362-9c57-469a-b033-131bb6dd79c9) - [native-390-dark-top.png](https://git.kayg.org/attachments/e19ce355-a927-4128-8526-1fa0238d71fb) - [native-390-dark-typed.png](https://git.kayg.org/attachments/ecc5cc59-9b5f-4733-a8ac-3ca92c140d31) - [native-390-light-middle.png](https://git.kayg.org/attachments/26d27180-3761-46e3-b7a0-3eca289aa7f4) - [native-390-light-shortcut.png](https://git.kayg.org/attachments/a221851d-f0a3-4962-8437-0bf6114e1696) - [native-390-light-top.png](https://git.kayg.org/attachments/73ac2cad-6c6c-4918-80b7-56d2f6273235) - [native-390-light-typed.png](https://git.kayg.org/attachments/ecf2c8de-8caa-4d91-afe9-99554996f4de) - [native-820-dark-middle.png](https://git.kayg.org/attachments/8fd15006-973b-4c65-bcf2-0459db58a3ab) - [native-820-dark-shortcut.png](https://git.kayg.org/attachments/6498afb2-f481-4b22-987b-937cfeab17b2) - [native-820-dark-top.png](https://git.kayg.org/attachments/4eaa7bbe-0f58-4581-bf56-3f6929812c26) - [native-820-dark-typed.png](https://git.kayg.org/attachments/75f14632-7f0b-45f7-94cb-29316d5a3b45) - [native-820-light-middle.png](https://git.kayg.org/attachments/b0761b32-7051-4f4a-be5e-4d90df285460) - [native-820-light-shortcut.png](https://git.kayg.org/attachments/869a4bf8-91a7-45e9-b06f-23ef7017a9a6) - [native-820-light-top.png](https://git.kayg.org/attachments/e02f64ca-2b30-413c-9915-d3f55ddc2c17) - [native-820-light-typed.png](https://git.kayg.org/attachments/a0f7a148-7408-4760-9ec6-740f507ebdf2) Cleanup: cargo clean completed (`Removed 1 file, 356B total`); web build and Svelte output were deleted. Temporary local test data was deleted. All owned measured runs and queued browser attempts are stopped; the perf lock and the original Mac browser lease were released. The remaining two comparison screenshots are not presented as complete. No screenshots or review artifacts were committed. Worktree status is clean. Mac download cleanup: not verified; the local Mac lock was occupied. Own files may remain under ~/calternal-bench/bignote3 and must be deleted when the lock is available.
Author
Owner

Cleanup follow-up for head 0743d5a9ad: Mac download cleanup completed under the required local lock; ~/calternal-bench/bignote3 was removed. The final report was generated before that check returned, so its unverified-cleanup note is superseded. All own measured/queued runs are stopped, local build output and temporary fixture data are removed, and the worktree is clean. The performance and measurement gaps listed in the report remain.

Cleanup follow-up for head 0743d5a9ad8b2567719e001d063c7a4e2decf7e6: Mac download cleanup completed under the required local lock; ~/calternal-bench/bignote3 was removed. The final report was generated before that check returned, so its unverified-cleanup note is superseded. All own measured/queued runs are stopped, local build output and temporary fixture data are removed, and the worktree is clean. The performance and measurement gaps listed in the report remain.
Author
Owner

Deployed to calternal.cloud in merge round 35c (build 5a2c02c13, live 2026-10-09 ~16:35 IST). Closing.

Deployed to calternal.cloud in merge round 35c (build 5a2c02c13, live 2026-10-09 ~16:35 IST). Closing.
kayg closed this issue 2026-10-09 11:11:38 +00:00
Commenting is not possible because the repository is archived.
No labels
No milestone
No project
No assignees
1 participant
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
kayg/calternal-v0#1349
No description provided.