port: note bars + Style sheet replacing the Inspector (approved mockup) #850

Closed
kayg wants to merge 0 commits from port/style into dev
Owner

port: note bars and Style sheet (approved mockup) — slice 1 of 3

Replays the stale origin/port/note (21 commits, 10-23) onto current dev (merge, conflicts resolved) and replaces the old Inspector.

What ships

  • Phone rest bar (Aa · + · Attach), typing strip with the pinned kind chip, labelled block bar, Attach menu that grows out of the capsule. Show/Hide source is one entry in the note ⋯ menu and in the Composer commands.
  • The Style sheet (three tabs, swipeable, height follows the tab, no title/✕/dim on a phone) replaces Inspector.svelte; lazy-ui loads it from idle-screens.
  • Dropped from the old branch because dev already has it: the phone note card (noteCard, note-card.css) and the palette rewrite.
  • New frontmatter key: calternal-frame: off (documented in editing.svelte.ts; round-trips, only written when off).

Decisions

  • The typing strip, block bar and Attach menu, the toolbar tools and the sheet-room helper load from idle-screens (warmed after first paint). The chip morph uses the Composer's LineMorph instead of torph (torph was 25 KB raw in the bar).
  • Slices 2 (Style sheet rewrite) and 3 (covers) are stacked on this branch.

Gates (CI=1 --retries=0, through ~/bin/slot)

  • svelte-check: 0 errors. vitest: all pass.
  • Playwright (note-bars*, bar-, editor, flow, phone-, sheet-geometry, lazy-*, toast-bar, touch-select, info, opacity, width, backdrops, …) on dev-01 chromium-1440/390 and dev-02 webkit-1440/390: all pass; a few phone/WebKit cases (toast-bar, touch-select, editor:44) failed once under load and pass in isolation on the final head.
  • Bundle (brotli, vs dev): first JS 239.5 → 239.5 KB, first CSS 20.9 → 21.5 (budget 22.1), all JS 311.9 → 315.5 (budget 315). all_js needs a small raise (kayg's call); I did not touch budgets.json.
  • Screenshots: ~/Developer/Worktrees/shots/port-style/{mockup,product-pr1,product-pr2} on code.

Not ported / open

  • Mic pill beside the rest bar (voice work). Desktop popover title/✕ from the mockup: dev's sheets drop them product-wide (IN6), left as is.
  • Attach items that need pictures/files are dimmed until port/port-attachments lands; its lib/attachments/attach.ts will collide with lib/attach.ts here (trivial).

🤖 Generated with Claude Code

## port: note bars and Style sheet (approved mockup) — slice 1 of 3 Replays the stale `origin/port/note` (21 commits, 10-23) onto current dev (merge, conflicts resolved) and replaces the old Inspector. **What ships** - Phone rest bar (Aa · + · Attach), typing strip with the pinned kind chip, labelled block bar, Attach menu that grows out of the capsule. Show/Hide source is one entry in the note ⋯ menu and in the Composer commands. - The Style sheet (three tabs, swipeable, height follows the tab, no title/✕/dim on a phone) replaces `Inspector.svelte`; `lazy-ui` loads it from `idle-screens`. - Dropped from the old branch because dev already has it: the phone note card (`noteCard`, `note-card.css`) and the palette rewrite. - New frontmatter key: `calternal-frame: off` (documented in `editing.svelte.ts`; round-trips, only written when off). **Decisions** - The typing strip, block bar and Attach menu, the toolbar tools and the sheet-room helper load from `idle-screens` (warmed after first paint). The chip morph uses the Composer's `LineMorph` instead of torph (torph was 25 KB raw in the bar). - Slices 2 (Style sheet rewrite) and 3 (covers) are stacked on this branch. **Gates** (CI=1 --retries=0, through ~/bin/slot) - svelte-check: 0 errors. vitest: all pass. - Playwright (note-bars*, bar-*, editor, flow, phone-*, sheet-geometry, lazy-*, toast-bar, touch-select, info, opacity, width, backdrops, …) on dev-01 chromium-1440/390 and dev-02 webkit-1440/390: all pass; a few phone/WebKit cases (toast-bar, touch-select, editor:44) failed once under load and pass in isolation on the final head. - Bundle (brotli, vs dev): first JS 239.5 → 239.5 KB, first CSS 20.9 → 21.5 (budget 22.1), all JS 311.9 → 315.5 (budget 315). **all_js needs a small raise (kayg's call); I did not touch budgets.json.** - Screenshots: `~/Developer/Worktrees/shots/port-style/{mockup,product-pr1,product-pr2}` on `code`. **Not ported / open** - Mic pill beside the rest bar (voice work). Desktop popover title/✕ from the mockup: dev's sheets drop them product-wide (IN6), left as is. - Attach items that need pictures/files are dimmed until port/port-attachments lands; its `lib/attachments/attach.ts` will collide with `lib/attach.ts` here (trivial). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
kayg added 33 commits 2026-11-02 10:27:22 +00:00
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U5oTUycqAh7DT72mdSUztk
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U5oTUycqAh7DT72mdSUztk
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U5oTUycqAh7DT72mdSUztk
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U5oTUycqAh7DT72mdSUztk
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U5oTUycqAh7DT72mdSUztk
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U5oTUycqAh7DT72mdSUztk
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The room under a phone's Style sheet loads with the idle screens
Some checks failed
CI / server (pull_request) Has been cancelled
CI / rust (pull_request) Has been cancelled
CI / web (pull_request) Has been cancelled
Markdown extraction contract / markdown-native-contract (pull_request) Has been cancelled
Markdown extraction contract / markdown-editor-contract (pull_request) Has been cancelled
7a6d5adf4c
Author
Owner

Gate results (heads: PR1 7a6d5adf). Targeted specs, CI=1 --retries=0 via ~/bin/slot: chromium-1440 83/83, chromium-390 all pass (earlier toast-bar:121 fixed in spec), webkit-1440/390 pass except load flakes (toast-bar:40, touch-select:226, editor:44) that pass in isolation. Shots: code:~/Developer/Worktrees/shots/port-style/{mockup,product-pr1,product-pr2} (rest, typing, Style tabs at 1440 and 390; mockup pairs).

Gate results (heads: PR1 7a6d5adf). Targeted specs, CI=1 --retries=0 via ~/bin/slot: chromium-1440 83/83, chromium-390 all pass (earlier toast-bar:121 fixed in spec), webkit-1440/390 pass except load flakes (toast-bar:40, touch-select:226, editor:44) that pass in isolation. Shots: `code:~/Developer/Worktrees/shots/port-style/{mockup,product-pr1,product-pr2}` (rest, typing, Style tabs at 1440 and 390; mockup pairs).
Author
Owner

BM10 follow-up (new head de991727). What caused what, found at a local merge of origin/dev + #840 + this stack:

Product fixes

  • preload.spec palette intent (#840's Palette chunk imported LineMorph from the idle-screens chunk because the typing strip shared it): the strip's chip now has its own tiny word-in (.nb-word), nothing shared with the Composer; modifier intent fetches only Palette again.
  • layout shift on reload (prefs-offline): a note now always has its bar at first paint, and Morph drew it at its empty size for one frame; Morph now measures the first contents before first paint.
  • longest task at 6x (note-bars-motion, 212/114 ms against <250 now): the room under a phone's Style sheet was a custom property on :root (restyled the whole page every frame); it lives on the note's scroller now. Only the showing tab is built when the sheet opens; the others on intent at the tab strip or after 2.5 s.
  • Attach and Write warm their lazy bar on intent (Attach menu was empty if tapped before the idle chunk arrived).

Specs updated because they asserted the OLD Inspector/Info/bar design (same behaviour, the new design's controls; no limit loosened):

  • preload.spec: on a phone the rest bar has Style (not Note info) so the on-demand check opens Style and expects .style-sheet; first-DOM-update test opens Insert/Info by address on a phone and uses the strip's Link tool for the note picker; .inspector is .style-sheet.
  • trash.spec, trash-search.spec: Note info is opened by its address (a phone's rest bar has no Info button).
  • day.spec: "Log the time" is the typing strip's "Log time" tool on a phone (mockup TB4), the tools button on a desktop.
  • tree.spec:377: tree lines are on the Style sheet's Text tab (tab=text), reset by its name.
    Not caused by this stack: sidebar-edge:8, vim:380 (pre-existing; both passed at the merge), and lazy-styled:54 on webkit-1440 ("search: unstyled on its first frame") fails identically on origin/dev + #840 alone.
BM10 follow-up (new head de991727). What caused what, found at a local merge of origin/dev + #840 + this stack: Product fixes - `preload.spec` palette intent (#840's Palette chunk imported `LineMorph` from the `idle-screens` chunk because the typing strip shared it): the strip's chip now has its own tiny word-in (`.nb-word`), nothing shared with the Composer; modifier intent fetches only Palette again. - layout shift on reload (`prefs-offline`): a note now always has its bar at first paint, and Morph drew it at its empty size for one frame; Morph now measures the first contents before first paint. - longest task at 6x (`note-bars-motion`, 212/114 ms against <250 now): the room under a phone's Style sheet was a custom property on `:root` (restyled the whole page every frame); it lives on the note's scroller now. Only the showing tab is built when the sheet opens; the others on intent at the tab strip or after 2.5 s. - Attach and Write warm their lazy bar on intent (Attach menu was empty if tapped before the idle chunk arrived). Specs updated because they asserted the OLD Inspector/Info/bar design (same behaviour, the new design's controls; no limit loosened): - `preload.spec`: on a phone the rest bar has Style (not Note info) so the on-demand check opens Style and expects `.style-sheet`; first-DOM-update test opens Insert/Info by address on a phone and uses the strip's Link tool for the note picker; `.inspector` is `.style-sheet`. - `trash.spec`, `trash-search.spec`: Note info is opened by its address (a phone's rest bar has no Info button). - `day.spec`: "Log the time" is the typing strip's "Log time" tool on a phone (mockup TB4), the tools button on a desktop. - `tree.spec:377`: tree lines are on the Style sheet's Text tab (`tab=text`), reset by its name. Not caused by this stack: `sidebar-edge:8`, `vim:380` (pre-existing; both passed at the merge), and `lazy-styled:54` on webkit-1440 ("search: unstyled on its first frame") fails identically on origin/dev + #840 alone.
Author
Owner

BM14 follow-up at dee3e961 (integrated pinned dev 41f2efa3 first, retaining the pull hint and 23 lazy imports).

Merged-tree reproduction, --workers=1 --repeat-each=10 --retries=0:

  • throttled-1440 editor.spec.ts:57, cpu x6: 1 pass / 9 failures.
  • webkit-390 glass.spec.ts:76: 10/10 pass; original page crash not reproduced.
  • webkit-390 pill-room.spec.ts:210, note/light: 10/10 pass; original target closure not reproduced.
  • webkit-390 review4-signout.spec.ts:120, stuck uplink=true / BroadcastChannel=true: 9 pass / 1 failure during the initial save-state precondition, before logout. This repeat failed without the original explicit “Page crashed” message.

The new source toggle helper in #850 opens the palette; the old test used the former toolbar button. Captured shifts include the palette preview: it retains the last note while search changes/clears, but looked up metadata from the requested id. Clearing results removed the visible note's metadata row and moved its text by 36px. Fix: metadata follows the note actually drawn (shown). The helper now waits for palette closure and the actual editor mode before returning. The layout observer and zero-shift requirement are unchanged.

The WebKit save assertion failed about 92ms after it began despite advertising a 5s timeout, with a blank internal matcher error (trace shows _Frame.expect / ExpectError), so this is not evidence of a 5s save delay. The setup now polls the same data-save attribute from the runner with the same default 5s deadline. No durability condition changes. This is a test wait-path fix; the original WebKit crash remains unproven.

The glass test's fixed 450ms/1800ms settling sleeps now wait on its existing finite-animation settling condition; the Settings step also waits for its selected-tab state. Pill-room already waits for state and is unchanged. No perf/layout threshold is loosened. After repeats are running on dev-01 (Chromium) and dev-02 (WebKit), with WebKit browser-process diagnostics enabled. Evidence and any remaining failures will follow; no full train or merge into dev.

BM14 follow-up at `dee3e961` (integrated pinned dev `41f2efa3` first, retaining the pull hint and 23 lazy imports). Merged-tree reproduction, `--workers=1 --repeat-each=10 --retries=0`: - throttled-1440 `editor.spec.ts:57`, cpu x6: **1 pass / 9 failures**. - webkit-390 `glass.spec.ts:76`: **10/10 pass**; original page crash not reproduced. - webkit-390 `pill-room.spec.ts:210`, note/light: **10/10 pass**; original target closure not reproduced. - webkit-390 `review4-signout.spec.ts:120`, stuck uplink=true / BroadcastChannel=true: **9 pass / 1 failure** during the initial save-state precondition, before logout. This repeat failed without the original explicit “Page crashed” message. The new source toggle helper in #850 opens the palette; the old test used the former toolbar button. Captured shifts include the palette preview: it retains the last note while search changes/clears, but looked up metadata from the *requested* id. Clearing results removed the visible note's metadata row and moved its text by 36px. Fix: metadata follows the note actually drawn (`shown`). The helper now waits for palette closure and the actual editor mode before returning. The layout observer and zero-shift requirement are unchanged. The WebKit save assertion failed about 92ms after it began despite advertising a 5s timeout, with a blank internal matcher error (trace shows `_Frame.expect` / `ExpectError`), so this is not evidence of a 5s save delay. The setup now polls the same `data-save` attribute from the runner with the same default 5s deadline. No durability condition changes. This is a test wait-path fix; the original WebKit crash remains unproven. The glass test's fixed 450ms/1800ms settling sleeps now wait on its existing finite-animation settling condition; the Settings step also waits for its selected-tab state. Pill-room already waits for state and is unchanged. No perf/layout threshold is loosened. After repeats are running on dev-01 (Chromium) and dev-02 (WebKit), with WebKit browser-process diagnostics enabled. Evidence and any remaining failures will follow; no full train or merge into dev.
Author
Owner

Further WebKit evidence: pinned dev 41f2efa3, its own binary and dist, passed all three exact WebKit cases 10/10 each. After dee3e961, merged-tree glass and sign-out passed 10/10 each, but pill-room failed 1/10. A separate pill-room --repeat-each=10 diagnostic run failed 1/10 and produced a native core.

The core is from WPEWebProcess, terminated by SIGSEGV inside the packaged libWPEWebKit-2.0.so.1; this is a real renderer failure, not evidence that still() needs a longer timeout. The stripped build has no function names for the faulting frames. GDB shows repeated native frames at 0xfffff2bfda14, 0xfffff2c0035c, and 0xfffff2c01e84, with the fault at 0xfffff5c07b2c. Core inspection used Nix GDB on dev-02; only the small backtrace is retained after cleanup.

Earlier sign-out's blank internal assertion failure is therefore not enough to establish a separate Playwright matcher bug; it may also reflect renderer failure. The runner-side state poll retains exactly the same attribute and default 5s deadline. No crash is treated as a successful test.

Two diagnostic ideas did not remove the pill-room failure: keeping the toolbar mask layer stable, and WEBKIT_SKIA_CPU_PAINTING_THREADS=1. They are not being shipped. An isolated change removing only the newly introduced word-chip blur is being tested; its fade and 3px rise remain. Final results will follow. The existing pill ink-spacing/no-word-movement checks, glass checks and layout/perf thresholds remain intact.

Further WebKit evidence: pinned dev `41f2efa3`, its own binary and dist, passed all three exact WebKit cases **10/10 each**. After `dee3e961`, merged-tree glass and sign-out passed **10/10 each**, but pill-room failed **1/10**. A separate pill-room **--repeat-each=10** diagnostic run failed **1/10** and produced a native core. The core is from `WPEWebProcess`, terminated by **SIGSEGV** inside the packaged `libWPEWebKit-2.0.so.1`; this is a real renderer failure, not evidence that `still()` needs a longer timeout. The stripped build has no function names for the faulting frames. GDB shows repeated native frames at `0xfffff2bfda14`, `0xfffff2c0035c`, and `0xfffff2c01e84`, with the fault at `0xfffff5c07b2c`. Core inspection used Nix GDB on dev-02; only the small backtrace is retained after cleanup. Earlier sign-out's blank internal assertion failure is therefore not enough to establish a separate Playwright matcher bug; it may also reflect renderer failure. The runner-side state poll retains exactly the same attribute and default 5s deadline. No crash is treated as a successful test. Two diagnostic ideas did not remove the pill-room failure: keeping the toolbar mask layer stable, and `WEBKIT_SKIA_CPU_PAINTING_THREADS=1`. They are not being shipped. An isolated change removing only the newly introduced word-chip blur is being tested; its fade and 3px rise remain. Final results will follow. The existing pill ink-spacing/no-word-movement checks, glass checks and layout/perf thresholds remain intact.
Author
Owner

Pushed follow-up 1812cc5e: the newly added toolbar word-chip blur is removed; its fade, 3px rise, duration, reduced-motion behavior, and all geometry remain. With only that CSS change after dee3e961, pill-room passed 30/30 (--repeat-each=30 --workers=1 --retries=0) on the merged tree, using the original browser environment, with no renderer/thread flags.

This isolates a reproducible WPE rendering failure triggered by the transient word-chip filter during toolbar transitions. Before removing it, two separate ten-repeat runs each failed once and one yielded the native renderer SIGSEGV. The mask and serial-raster experiments failed and were reverted. The exact native function remains unknown because the packaged library is stripped; I am not claiming a symbol-level engine diagnosis.

Final exact-case ten-repeat WebKit matrix (glass, pill note/light, sign-out stuck/BroadcastChannel) and final Chromium x6 editor repeat are running against both pushed fixes. No assertion, spacing, layout or perf budget has been weakened. Final totals and cleanup will follow.

Pushed follow-up `1812cc5e`: the newly added toolbar word-chip blur is removed; its fade, 3px rise, duration, reduced-motion behavior, and all geometry remain. With only that CSS change after `dee3e961`, pill-room passed **30/30** (`--repeat-each=30 --workers=1 --retries=0`) on the merged tree, using the original browser environment, with no renderer/thread flags. This isolates a reproducible WPE rendering failure triggered by the transient word-chip filter during toolbar transitions. Before removing it, two separate ten-repeat runs each failed once and one yielded the native renderer SIGSEGV. The mask and serial-raster experiments failed and were reverted. The exact native function remains unknown because the packaged library is stripped; I am not claiming a symbol-level engine diagnosis. Final exact-case ten-repeat WebKit matrix (glass, pill note/light, sign-out stuck/BroadcastChannel) and final Chromium x6 editor repeat are running against both pushed fixes. No assertion, spacing, layout or perf budget has been weakened. Final totals and cleanup will follow.
Author
Owner

Final targeted BM14 follow-up. Fixes are pushed only to owning branches:

Pass counts, before → final:

Failure Cause and fix Before Final
Rust owner_unshared_admission_is_cached_until_a_grant_and_never_after Dev's recipient-success expectation conflicts with #829's intentional hard-off cross-owner gate. Preserve all cache/DB assertions, require recipient refusal without consuming a sequence, then require owner sequence 6. 97d790f6. 0/30 30/30
Rust replay_authorization_waits_for_the_per_note_writer_lock Same dormant-gate mismatch; its scheduling timeout also failed to prove the task had reached the lock. Poll the real future under the held mutex, require Pending for both identities, then owner success / recipient refusal. 97d790f6. 0/30 30/30
throttled-1440 editor.spec.ts:57, cpu x6 #850's new source helper opens the palette. Clearing results removed the retained preview note's metadata and moved text by 36px. Look up metadata from the drawn note and wait for palette closure/editor mode. dee3e961. 1/10 10/10
webkit-390 glass.spec.ts:76 Original page crash did not recur in the requested ten-repeat reproduction. Its initial typing gesture traverses the same new toolbar blur path isolated by pill-room's native crash. Remove that blur (1812cc5e) and replace fixed settling sleeps with state waits (dee3e961). 10/10; original crash not reproduced 10/10
webkit-390 pill-room.spec.ts:210, note/light New word-chip blur during toolbar changes triggers a native WPE renderer SIGSEGV. Remove only the transient blur; retain fade, rise and geometry. 1812cc5e. Initial 10/10, then 9/10 twice (28/30 total) 30/30 focused, plus 10/10 final matrix
webkit-390 review4-signout.spec.ts:120, stuck uplink=true / BroadcastChannel=true Failure is in setup's save-state wait, before logout, on the same typing/toolbar path. Retain the same saved-state predicate and 5s deadline using runner polling; remove the shared blur trigger. dee3e961, 1812cc5e. The original sign-out crash itself was not independently core-diagnosed. 9/10 10/10

The two Rust after results come from 30 complete auth-library runs, 64 tests each, with normal parallel test threads on the BM14 merged tree plus the fix. Before: 62 passed / 2 failed per run. Each loop overlapped one ordinary slot build on dev-01. They are not claims of 30 complete workspace/train runs. Exact Rust commands/load details: #829 (comment).

Browser commands, inside Nix/normal slots, CI=1, workers=1, retries=0, original browser environment:

# dev-01, final Chromium check
bunx playwright test e2e/editor.spec.ts:57 \
  --config=$HOME/bm14-fix-logs/chromium.mts \
  --workers=1 --repeat-each=10 --retries=0 --reporter=line,json
# dev-02, final WebKit exact-case matrix
bunx playwright test e2e/glass.spec.ts:76 e2e/pill-room.spec.ts:210 e2e/review4-signout.spec.ts:120 \
  --grep 'the glass keeps its backdrop|pill room: note, light:|stuck uplink=true, BroadcastChannel=true' \
  --config=$HOME/bm14-fix-logs/webkit.mts \
  --workers=1 --repeat-each=10 --retries=0 --reporter=line,json
# dev-02, focused pill-room validation before the final matrix
bunx playwright test e2e/pill-room.spec.ts:210 --grep 'pill room: note, light:' \
  --config=$HOME/bm14-fix-logs/webkit.mts \
  --workers=1 --repeat-each=30 --retries=0 --reporter=line,json

The wrappers import the repository config, select only the named native project (throttled-1440 or webkit-390), remove project dependencies, and set absolute testDir/webServer.cwd. They do not change thresholds or browser options. CALTERNAL_BIN and E2E_DIST point at the merged-tree build. Pinned dev 41f2efa3 with its own binary/dist passed all three WebKit cases 10/10 each.

Additional checks: production builds PASS; cargo fmt --all --check PASS; cargo clippy -p calternal-auth --lib --tests -j4 -- -D warnings PASS; local git diff --check PASS. bun run check remains blocked by pre-existing generated action-type drift (also reproduced directly on pinned dev). Direct bunx svelte-check --tsconfig ./tsconfig.json reports two existing logoutStatus narrowing errors in unchanged review4-signout.spec.ts:225-226, plus 16 warnings; that file is byte-identical between pinned dev and BM14. No new diagnostics point at the changed preview/CSS.

Limits: the packaged WPE library is stripped, so the exact native faulting function is unknown. The blur trigger is isolated by repeated before/after runs and a native core; the original glass/sign-out crashes do not each have their own core. The mask-layer and serial-raster probes failed and were reverted. No timeout, access assertion, layout/ink-spacing threshold, or perf limit was relaxed. No Linux frame-rate claims are made. No full train was run and no PR was merged.

cleanup complete: no own bm14-fix units remain active. removed both VM throwaway worktrees, build targets, temporary homes, baseline binaries, and the large native core. retained only small diagnostic logs/JSON outside the repository. owning control-host worktrees are clean.

Final targeted BM14 follow-up. Fixes are pushed only to owning branches: - #829 `feat/sharing-s1-pr2`: **97d790f69259b0308598ca0aafd2407ef1a1226e**. - #850 `port/style`: **1812cc5e10b8008e28acaa2f19234ff8123dfd73** (includes **dee3e961**, preview/wait fix). - #851, #852 and #835 unchanged. BM14's train branch remains unchanged. Pass counts, before → final: | Failure | Cause and fix | Before | Final | |---|---|---|---| | Rust `owner_unshared_admission_is_cached_until_a_grant_and_never_after` | Dev's recipient-success expectation conflicts with #829's intentional hard-off cross-owner gate. Preserve all cache/DB assertions, require recipient refusal without consuming a sequence, then require owner sequence 6. `97d790f6`. | 0/30 | 30/30 | | Rust `replay_authorization_waits_for_the_per_note_writer_lock` | Same dormant-gate mismatch; its scheduling timeout also failed to prove the task had reached the lock. Poll the real future under the held mutex, require Pending for both identities, then owner success / recipient refusal. `97d790f6`. | 0/30 | 30/30 | | throttled-1440 `editor.spec.ts:57`, cpu x6 | #850's new source helper opens the palette. Clearing results removed the retained preview note's metadata and moved text by 36px. Look up metadata from the drawn note and wait for palette closure/editor mode. `dee3e961`. | 1/10 | 10/10 | | webkit-390 `glass.spec.ts:76` | Original page crash did not recur in the requested ten-repeat reproduction. Its initial typing gesture traverses the same new toolbar blur path isolated by pill-room's native crash. Remove that blur (`1812cc5e`) and replace fixed settling sleeps with state waits (`dee3e961`). | 10/10; original crash not reproduced | 10/10 | | webkit-390 `pill-room.spec.ts:210`, note/light | New word-chip blur during toolbar changes triggers a native WPE renderer SIGSEGV. Remove only the transient blur; retain fade, rise and geometry. `1812cc5e`. | Initial 10/10, then 9/10 twice (28/30 total) | 30/30 focused, plus 10/10 final matrix | | webkit-390 `review4-signout.spec.ts:120`, stuck uplink=true / BroadcastChannel=true | Failure is in setup's save-state wait, before logout, on the same typing/toolbar path. Retain the same saved-state predicate and 5s deadline using runner polling; remove the shared blur trigger. `dee3e961`, `1812cc5e`. The original sign-out crash itself was not independently core-diagnosed. | 9/10 | 10/10 | The two Rust after results come from **30 complete auth-library runs**, 64 tests each, with normal parallel test threads on the BM14 merged tree plus the fix. Before: 62 passed / 2 failed per run. Each loop overlapped one ordinary slot build on dev-01. They are not claims of 30 complete workspace/train runs. Exact Rust commands/load details: https://git.kayg.org/kayg/calternal/pulls/829#issuecomment-76545. Browser commands, inside Nix/normal slots, CI=1, workers=1, retries=0, original browser environment: ```sh # dev-01, final Chromium check bunx playwright test e2e/editor.spec.ts:57 \ --config=$HOME/bm14-fix-logs/chromium.mts \ --workers=1 --repeat-each=10 --retries=0 --reporter=line,json # dev-02, final WebKit exact-case matrix bunx playwright test e2e/glass.spec.ts:76 e2e/pill-room.spec.ts:210 e2e/review4-signout.spec.ts:120 \ --grep 'the glass keeps its backdrop|pill room: note, light:|stuck uplink=true, BroadcastChannel=true' \ --config=$HOME/bm14-fix-logs/webkit.mts \ --workers=1 --repeat-each=10 --retries=0 --reporter=line,json # dev-02, focused pill-room validation before the final matrix bunx playwright test e2e/pill-room.spec.ts:210 --grep 'pill room: note, light:' \ --config=$HOME/bm14-fix-logs/webkit.mts \ --workers=1 --repeat-each=30 --retries=0 --reporter=line,json ``` The wrappers import the repository config, select only the named native project (throttled-1440 or webkit-390), remove project dependencies, and set absolute testDir/webServer.cwd. They do not change thresholds or browser options. `CALTERNAL_BIN` and `E2E_DIST` point at the merged-tree build. Pinned dev `41f2efa3` with its own binary/dist passed all three WebKit cases 10/10 each. Additional checks: production builds PASS; `cargo fmt --all --check` PASS; `cargo clippy -p calternal-auth --lib --tests -j4 -- -D warnings` PASS; local `git diff --check` PASS. `bun run check` remains blocked by pre-existing generated action-type drift (also reproduced directly on pinned dev). Direct `bunx svelte-check --tsconfig ./tsconfig.json` reports two existing `logoutStatus` narrowing errors in unchanged `review4-signout.spec.ts:225-226`, plus 16 warnings; that file is byte-identical between pinned dev and BM14. No new diagnostics point at the changed preview/CSS. Limits: the packaged WPE library is stripped, so the exact native faulting function is unknown. The blur trigger is isolated by repeated before/after runs and a native core; the original glass/sign-out crashes do not each have their own core. The mask-layer and serial-raster probes failed and were reverted. No timeout, access assertion, layout/ink-spacing threshold, or perf limit was relaxed. No Linux frame-rate claims are made. No full train was run and no PR was merged. cleanup complete: no own bm14-fix units remain active. removed both VM throwaway worktrees, build targets, temporary homes, baseline binaries, and the large native core. retained only small diagnostic logs/JSON outside the repository. owning control-host worktrees are clean.
Author
Owner

Pushed two e2e fixes to this branch (3744b595, d252a902), from the BM14b repeat-each study (full table on #891):

  • glass.spec.ts: dee3e961 made the flash check start with 15–19 screencast frames instead of 40+, so frames > 20 failed 20/20 on the train head. Now it waits for frames (>24) after the caret step. Train head + fix: 20/20 plain, 20/20 under load.
  • editor.spec.ts: the throttled layout-shift test is split in two (loading+typing, switching modes). It ran ~18 s of a 30 s limit at 6x and hit it whenever the host was busy. Train head + fix: 20/20 in all four (1440/390 × typing/modes), plain and under load, slowest 18.4 s.

Still open here: note-bars-motion.spec.ts:71 (Style sheet) fails ~1/40 under load because the sheet mounts in one task of ~150–260 ms at 6x against the 250 ms budget. Needs an app change or a decision on the budget; see #891.

Pushed two e2e fixes to this branch (`3744b595`, `d252a902`), from the BM14b repeat-each study (full table on #891): - `glass.spec.ts`: `dee3e961` made the flash check start with 15–19 screencast frames instead of 40+, so `frames > 20` failed 20/20 on the train head. Now it waits for frames (>24) after the caret step. Train head + fix: 20/20 plain, 20/20 under load. - `editor.spec.ts`: the throttled layout-shift test is split in two (loading+typing, switching modes). It ran ~18 s of a 30 s limit at 6x and hit it whenever the host was busy. Train head + fix: 20/20 in all four (1440/390 × typing/modes), plain and under load, slowest 18.4 s. Still open here: `note-bars-motion.spec.ts:71` (Style sheet) fails ~1/40 under load because the sheet mounts in one task of ~150–260 ms at 6x against the 250 ms budget. Needs an app change or a decision on the budget; see #891.
Author
Owner

Style sheet open: task timings before / after (6x CPU, throttled-390, dev-01)

Cause (trace of note-bars-motion.spec.ts:71): the tap opened the sheet in one task of 150–300 ms: Svelte mounted the whole sheet (strip + Page tab) in the tap's frame, Selector asked document.fonts.ready (a getter that forces a style recalc, ~39 ms at 6x), scrollLeft = index * clientWidth forced a layout, and the first pointer press of a page flipped data-last-input, which a * selector depends on (whole-page restyle, ~70 ms at 6x, in the pointerdown listener).

Fix (#850, commits fdddc714, e2146619, 3764d0b9, bcd5ef36, af6fb861):

  1. Selector asks fonts.ready only while a font is still loading.
  2. The sheet opens in steps, each its own frame: (0) a shell held at the Page tab's height (last measured, else a measured guess), so the capsule springs to its size at once; (1) the tab strip and three empty pages, two frames on (a rAF asked for inside the tap still runs in the tap's frame); (2) the shown page. Other tabs unchanged (intent / 2.5 s / on choose). The strip and the page fade in over 140 ms inside the morph's own 170 ms crossfade.
  3. data-last-input is written only when entering or leaving "keyboard" (the only value CSS reads), so the first tap costs no restyle.

Longest main-thread task, rest to Style sheet (there), spec's own trace:

runs min median max pass
before (d252a902) 6 246 ~270 306 1 / 6
after, plain --repeat-each=20 20 72 ~95 163 20 / 20 (Attach 20 / 20)
after, plain, earlier build (e2146619 only) 20 81 ~113 298 19 / 20
after, + one slot job (editor+links), run A 20 77 ~104 263 19 / 20 (one 263 ms outlier)
after, + one slot job, run B 20 77 ~84 126 20 / 20

Probe of one open at 6x (task, ms): click task 239–263 → 75–82; the Playwright pointerdown listener's forced recalc 71 → gone from the page's side; next tasks are the strip frame (~55) and the page frame (~60).
Host load average of other agents was 2–10 during these runs; the 263 outlier was one run with main-thread totals 2x its neighbours (host contention), but I cannot rule out a slow tail of ~1 in 40.

Look: frames at 1x (CDP screencast, 390 phone) before / after: the morph ends in the identical sheet; in the first 2–3 frames of the growth the capsule is empty for ~35–50 ms longer, then the strip and page fade in (no layout jump: the room is held).

Gates (dev-01, ~/bin/slot): bundle budgets perf/web.sh --bundle-only --gate ok (first JS 233.5 / 240 KB brotli); packages/ui test:primitives 55 pass, apps/web test 96 pass; 16 Style/bar/glass/sheet specs on chromium-390 (336 pass, 24 skipped), chromium-1440 (67 pass), throttled-390 (2 pass). apps/web check fails on src/lib/actions.gen.ts is out of date with contracts/actions.json (not touched by this work; present on the base).

Stack: #851 now has 994278bb (merge of the new #850 head; this stack merges port/style rather than rebasing) + d94771b6 (held room measured for its taller Page tab: 362 / 451 px) and #852 has 656b61bf (merge of #851; lazy-ui import count 25 = pull hint + covers). note-bars-motion.spec.ts Style sheet on both: 6 / 6 pass (longest 75–100 and 83–184 ms).

## Style sheet open: task timings before / after (6x CPU, throttled-390, dev-01) **Cause** (trace of `note-bars-motion.spec.ts:71`): the tap opened the sheet in one task of 150–300 ms: Svelte mounted the whole sheet (strip + Page tab) in the tap's frame, `Selector` asked `document.fonts.ready` (a getter that forces a style recalc, ~39 ms at 6x), `scrollLeft = index * clientWidth` forced a layout, and the first pointer press of a page flipped `data-last-input`, which a `*` selector depends on (whole-page restyle, ~70 ms at 6x, in the pointerdown listener). **Fix** (#850, commits fdddc714, e2146619, 3764d0b9, bcd5ef36, af6fb861): 1. `Selector` asks `fonts.ready` only while a font is still loading. 2. The sheet opens in steps, each its own frame: (0) a shell held at the Page tab's height (last measured, else a measured guess), so the capsule springs to its size at once; (1) the tab strip and three empty pages, two frames on (a rAF asked for inside the tap still runs in the tap's frame); (2) the shown page. Other tabs unchanged (intent / 2.5 s / on choose). The strip and the page fade in over 140 ms inside the morph's own 170 ms crossfade. 3. `data-last-input` is written only when entering or leaving "keyboard" (the only value CSS reads), so the first tap costs no restyle. **Longest main-thread task, `rest to Style sheet` (`there`), spec's own trace:** | | runs | min | median | max | pass | |---|---|---|---|---|---| | before (d252a902) | 6 | 246 | ~270 | 306 | **1 / 6** | | after, plain `--repeat-each=20` | 20 | 72 | ~95 | 163 | 20 / 20 (Attach 20 / 20) | | after, plain, earlier build (e2146619 only) | 20 | 81 | ~113 | 298 | 19 / 20 | | after, + one slot job (editor+links), run A | 20 | 77 | ~104 | 263 | **19 / 20** (one 263 ms outlier) | | after, + one slot job, run B | 20 | 77 | ~84 | 126 | 20 / 20 | Probe of one open at 6x (task, ms): click task 239–263 → 75–82; the Playwright pointerdown listener's forced recalc 71 → gone from the page's side; next tasks are the strip frame (~55) and the page frame (~60). Host load average of other agents was 2–10 during these runs; the 263 outlier was one run with main-thread totals 2x its neighbours (host contention), but I cannot rule out a slow tail of ~1 in 40. **Look**: frames at 1x (CDP screencast, 390 phone) before / after: the morph ends in the identical sheet; in the first 2–3 frames of the growth the capsule is empty for ~35–50 ms longer, then the strip and page fade in (no layout jump: the room is held). **Gates** (dev-01, `~/bin/slot`): bundle budgets `perf/web.sh --bundle-only --gate` ok (first JS 233.5 / 240 KB brotli); `packages/ui test:primitives` 55 pass, `apps/web test` 96 pass; 16 Style/bar/glass/sheet specs on chromium-390 (336 pass, 24 skipped), chromium-1440 (67 pass), throttled-390 (2 pass). `apps/web check` fails on `src/lib/actions.gen.ts is out of date with contracts/actions.json` (not touched by this work; present on the base). **Stack**: #851 now has `994278bb` (merge of the new #850 head; this stack merges `port/style` rather than rebasing) + `d94771b6` (held room measured for its taller Page tab: 362 / 451 px) and #852 has `656b61bf` (merge of #851; lazy-ui import count 25 = pull hint + covers). `note-bars-motion.spec.ts` Style sheet on both: 6 / 6 pass (longest 75–100 and 83–184 ms).
Author
Owner

BM14c: the red Style-stack cases came from #852's merge (a dropped noteId prop on <PageTab />, and the Page tab's held room shrinking mid-build). Fixed on #852 (f757dc1e, fed76ea1, 07b6770a); nothing needed on this PR. Details and 20x numbers: #897 and #852.

BM14c: the red Style-stack cases came from #852's merge (a dropped `noteId` prop on `<PageTab />`, and the Page tab's held room shrinking mid-build). Fixed on #852 (`f757dc1e`, `fed76ea1`, `07b6770a`); nothing needed on this PR. Details and 20x numbers: #897 and #852.
Author
Owner

Perf fix pushed (head 6eb81f62): note-bars-lazy.css holds the block bar, typing strip, chip and fade rules (5.4 of 8.5 KB), imported by BlockBar/Strip (idle-screens chunk, resolved after its CSS) instead of main.ts. First CSS raw 115.2 → 112.3 KB, brotli train 19.6 → 19.2 KB (dev 18.8).

Method: release binaries built on dev-01, relayed to the perf VMs with matching sha256 (dev de99cfbf…, train+fixes 68dd30a0…, same dev calternal-perf for every run). Every run under ~/bin/perf-lock, seed 1, 10k Home, alternating pairs. Medians of per-run p50 / p95, [min–max of p50]. The perf VMs were shared with other agents' long lock holds, so runs spread over several windows; dev-vs-dev spread alone is 0.20–0.37 ms on round trip.

Browser (Chromium 4x CPU, 10k Home; boot.perf.ts, list-search.perf.ts)

Pooled, interleaved dev / #850 / #851 / #852 / #852+CSS-split runs across three windows (D n=21, #850 n=7, #851 n=5, #852 n=14, split n=7):

Metric (p50 ms) dev #850 #851 #852 #852 + CSS split
boot.cold_fcp 744 780 736 760 748
boot.cold_note 938 988 927 951 968
list_search.key (p50 / p95) 5.9 / 8.2 6.2 / 8.3 5.9 / 8.6 6.2 / 8.3 6.1 / 8.9
The train's +10% cold FCP, +6% first note and +14% search-key p95 did not reproduce: in the quietest window (8 interleaved rounds) #852 was flat to dev (FCP 744 vs 756, first note 941 vs 962, search key 6.0 / 8.1 vs 5.8 / 8.0), and dev-vs-dev spread is 704–832 ms FCP. #850 shows the largest step (+2.6…4.8%, inside range overlap). I found no per-keystroke work added to the search path.
Bundle (brotli KB, bundle-size.mjs): first CSS dev 18.8 → train 19.6 → with split 19.2; first JS 233.2 → 233.9 → 233.6. The remaining +0.4 KB CSS is the rest bar's own rules, needed by the first note screen.
Perf fix pushed (head `6eb81f62`): `note-bars-lazy.css` holds the block bar, typing strip, chip and fade rules (5.4 of 8.5 KB), imported by `BlockBar`/`Strip` (idle-screens chunk, resolved after its CSS) instead of `main.ts`. First CSS raw 115.2 → 112.3 KB, brotli train 19.6 → 19.2 KB (dev 18.8). Method: release binaries built on dev-01, relayed to the perf VMs with matching sha256 (dev `de99cfbf…`, train+fixes `68dd30a0…`, same dev `calternal-perf` for every run). Every run under `~/bin/perf-lock`, seed 1, 10k Home, alternating pairs. Medians of per-run p50 / p95, [min–max of p50]. The perf VMs were shared with other agents' long lock holds, so runs spread over several windows; dev-vs-dev spread alone is 0.20–0.37 ms on round trip. ### Browser (Chromium 4x CPU, 10k Home; `boot.perf.ts`, `list-search.perf.ts`) Pooled, interleaved dev / #850 / #851 / #852 / #852+CSS-split runs across three windows (D n=21, #850 n=7, #851 n=5, #852 n=14, split n=7): | Metric (p50 ms) | dev | #850 | #851 | #852 | #852 + CSS split | |---|---|---|---|---|---| | boot.cold_fcp | 744 | 780 | 736 | 760 | 748 | | boot.cold_note | 938 | 988 | 927 | 951 | 968 | | list_search.key (p50 / p95) | 5.9 / 8.2 | 6.2 / 8.3 | 5.9 / 8.6 | 6.2 / 8.3 | 6.1 / 8.9 | The train's +10% cold FCP, +6% first note and +14% search-key p95 did **not** reproduce: in the quietest window (8 interleaved rounds) #852 was flat to dev (FCP 744 vs 756, first note 941 vs 962, search key 6.0 / 8.1 vs 5.8 / 8.0), and dev-vs-dev spread is 704–832 ms FCP. #850 shows the largest step (+2.6…4.8%, inside range overlap). I found no per-keystroke work added to the search path. Bundle (brotli KB, `bundle-size.mjs`): first CSS dev 18.8 → train 19.6 → with split 19.2; first JS 233.2 → 233.9 → 233.6. The remaining +0.4 KB CSS is the rest bar's own rules, needed by the first note screen.
Author
Owner

Content landed in dev via 12103f1c97 — closing.

Content landed in dev via 12103f1c973f1e810dd4a9a3bff5a705514d70b0 — closing.
kayg closed this pull request 2026-11-07 18:12:01 +00:00
Some checks failed
CI / server (pull_request) Has been cancelled
CI / rust (pull_request) Has been cancelled
CI / web (pull_request) Has been cancelled
Markdown extraction contract / markdown-native-contract (pull_request) Has been cancelled
Markdown extraction contract / markdown-editor-contract (pull_request) Has been cancelled

Pull request closed

Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
kayg/calternal!850
No description provided.