Train y: fast appends, search speedups, block selection look, tag/log/link fixes, CSS budget, parallel trains #565

Closed
kayg wants to merge 0 commits from train/2026-10-17y into dev
Owner

Train y is the first run of the PARALLEL sharded runner: 40 minutes of wall time instead of about 2.5 hours, with the same full coverage (all 11 projects; the colour matrices sampled per #554, plus a nightly full run).

  • fmt, clippy, workspace tests and the build are green. The only fmt diff came from #557 and was fixed with a rustfmt-only commit, merged and re-checked (fmt clean, clippy for calternal-daily clean).
  • e2e: chromium-1440, chromium-390 shard 2, the small projects and webkit-390 shards 2 and 3 were green.
  • First-run failures, all green on reruns:
    • missing-links:379 on chromium-390: 54/54 on rerun;
    • on webkit-1440, backdrops:126, toast-bar:40, trash:18/33 and tree:176: 78/78 on rerun;
    • webkit-390 shard 1 lost a port race (a harness issue, now retried automatically): 233/233 on rerun.

Contents:

  • #529 fast appends (reviewed);
  • #514 search and tag speedups;
  • dark-mode smoothing;
  • #533 Filter gap and heading flips;
  • #526 first CSS under budget;
  • #523 the approved block-selection look plus multi-select plus the 6px bullet;
  • #554 matrix sampling;
  • #555 nested tag matching;
  • #557 lenient log times;
  • #558 accent labels;
  • #562 link parity.

Merging.

🤖 Generated with Claude Code

Train y is the first run of the PARALLEL sharded runner: 40 minutes of wall time instead of about 2.5 hours, with the same full coverage (all 11 projects; the colour matrices sampled per #554, plus a nightly full run). - **fmt, clippy, workspace tests and the build** are green. The only fmt diff came from #557 and was fixed with a rustfmt-only commit, merged and re-checked (fmt clean, clippy for calternal-daily clean). - **e2e:** chromium-1440, chromium-390 shard 2, the small projects and webkit-390 shards 2 and 3 were green. - **First-run failures, all green on reruns:** - `missing-links:379` on chromium-390: 54/54 on rerun; - on webkit-1440, `backdrops:126`, `toast-bar:40`, `trash:18/33` and `tree:176`: 78/78 on rerun; - webkit-390 shard 1 lost a port race (a harness issue, now retried automatically): 233/233 on rerun. Contents: - #529 fast appends (reviewed); - #514 search and tag speedups; - dark-mode smoothing; - #533 Filter gap and heading flips; - #526 first CSS under budget; - #523 the approved block-selection look plus multi-select plus the 6px bullet; - #554 matrix sampling; - #555 nested tag matching; - #557 lenient log times; - #558 accent labels; - #562 link parity. Merging. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
kayg added 30 commits 2026-10-17 20:10:06 +00:00
perf(notes): skip tag parsing on lines without hashes
Some checks failed
CI / server (pull_request) Successful in 28s
CI / rust (pull_request) Successful in 2m11s
CI / web (pull_request) Failing after 50m46s
be555c1dfc
First CSS under budget: sheets, search and Settings load on demand (#327)
Some checks failed
CI / server (pull_request) Successful in 30s
CI / rust (pull_request) Successful in 2m31s
CI / web (pull_request) Failing after 43m14s
529f7448c3
The sheets (Insert, Style, Note info, Move to, Link to), the search palette and Settings are now
lazy chunks with their own styles. First CSS 22.8 KB -> 19.4 KB brotli, first JS 227.6 -> 222 KB.
They are fetched when the app goes idle after sign-in, so opening one is instant.
A new test checks each is styled on its first frame.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Append cost no longer grows with the note (#527)
Some checks failed
CI / server (pull_request) Successful in 35s
CI / rust (pull_request) Successful in 2m55s
CI / web (pull_request) Failing after 22s
71de5551a7
notes.append used to copy the whole note (ydoc::fork of its full state)
to find where the text ends, so every line added to a log made the next
append slower: the copy's Yjs integration is about quadratic in the
number of writers, and every keyed append is its own writer.

The room now remembers where its last append ended, together with the
document's state vector at that moment. While the state vector is
unchanged the document holds the very same pieces, so the next append is
built directly as a one-item Yjs update (ydoc::append_update). Anything
that adds text (typing, outside edits, server keys) changes the state
vector, and that one append makes the copy as before. The writer id
(idempotency key), history rows, versions and merge behaviour are
unchanged: tests check the applied change is byte-identical to the copy
path while typists insert, delete and deliver out of order.

- room/tail.rs: the remembered end and the append itself
- ydoc::append_update: the one-item update
- tests/appends.rs: byte-for-byte equivalence fuzz, typists + appends
  in a real room, long-note append stays small
- notes_crash.rs: kill -9 mid-append on a 1,000-line note, 4 writers
- examples/append_bench.rs: append p50/p95 at 100, 1k and 3.5k lines

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WCcFhwwgMK66k9LMVqogNJ
A Yjs client that formats the end of the text leaves a closing format
mark as the last item. The copy path appends before it (the mark is its
right origin), so that append is not the end, and the next direct append
would have had no right origin: same text, different bytes. The room now
remembers the end only when the applied append has no right origin
(ydoc::added_last), so the next append goes by copy and stays
byte-identical. Doc comments say exactly where the end is.

Adds the reviewer's tests (tests/appends_review.rs): trailing format
mark regression, deleting the end, another root type, and a 60-seed fuzz
with restarts and parked changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WCcFhwwgMK66k9LMVqogNJ
On an iPhone the swipe picks the block (the block bar shows; reproduced in the simulator with
real touch events), but the phone paints no selection with the keyboard down and CodeMirror
adds only two handles, so a picked block looked like half-selected text. The look is now ours,
as kayg approved it (the select.html mockup, left circles):

- picked.ts: while a block is picked, every block slides right on a critically damped spring
  (no overshoot, about 250 ms) so the text starts 60 pt from the edge, and a 24 pt circle shows
  14 pt from the left edge: a hollow ring (2 pt) on each block, a filled accent circle with a
  check on the picked ones. Picked blocks wear a 16% accent tint (10 px radius, 8 px past the
  text, 20 pt from the right edge, 2 px shorter at top and bottom so neighbours show a gap). No
  handles or native selection paint while it lasts. The tint, circles and slide cover any range
  `pickBlock` is given, so two or more blocks work.
- follow.ts: while the finger swipes, the block follows it (half the distance, at most 56 px, and
  never past the page edge), a ring and tint show once the swipe is far enough (32 px), and the
  block settles back on the same spring.
- spring.ts: the one spring.
- touch.ts and the gesture-claim logic are unchanged; the look is only picked.ts and follow.ts.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WCcFhwwgMK66k9LMVqogNJ
While blocks are selected, a swipe on another block, or a tap on its circle, adds it to the
selection, or takes it out if it is already in. Same as the approved select.html mockup.

- editing.svelte.ts: `toggleBlock` keeps the selected blocks as a list (they need not touch);
  the text selection is the span from the first to the last. `refresh` keeps that list while the
  span is still theirs. The block bar already says "N blocks"; delete, duplicate and type
  changes work on the list.
- picked.ts: a pick is a list of blocks; `togglePick` and `isPicking`.
- touch.ts: while picking, a swipe or a tap on the circle toggles (the 'toggle' action).
- Editor.svelte: Esc lets go of selected blocks when the text has no focus (a swipe selects
  without it), like Done.
- follow.ts: a pulled block's ring and tint were found by the circles' shared class, so they
  restyled the first circle of the page and left it filled; found by their own class now.
- e2e: adding a second and third block, taking one out, Done, a tap on a circle, Esc.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WCcFhwwgMK66k9LMVqogNJ
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WCcFhwwgMK66k9LMVqogNJ
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WCcFhwwgMK66k9LMVqogNJ
List headings: every group label has dates to show (Previous 30 days, Upcoming, Earlier), so a tap morphs; tests for the tap and Enter (#469)
Some checks failed
CI / server (pull_request) Successful in 30s
CI / rust (pull_request) Successful in 2m24s
CI / web (pull_request) Failing after 23s
5f471bdf30
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WCcFhwwgMK66k9LMVqogNJ
The WebKit failure was the editor built beside Settings: CodeMirror adds its styles on its first
measure. Lazy chunks already wait for their stylesheet (Vite's preload waits for the link's load
event), so no unstyled frame. The test now looks at .settings and .palette only.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Trains sample the colour matrices; the full matrix runs nightly
Some checks failed
CI / server (pull_request) Successful in 46s
CI / rust (pull_request) Failing after 2m38s
CI / web (pull_request) Failing after 27s
0bd4185b52
E2E_MATRIX=sample|full (default full). Sample is a pairwise cover of phone-bars
(60 of 240) and phone-edges (36 of 144) plus an even top-up to a quarter.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Tag picker matches nested tags (#449)
Some checks failed
CI / server (pull_request) Successful in 32s
CI / rust (pull_request) Successful in 2m33s
CI / web (pull_request) Failing after 29s
3c2eda4556
Typing #fitness now also offers area/fitness and goals/fitness/strength.
A tag matches when its path starts with the query, any path segment
starts with it, or (for a query with a slash) the path holds it starting
at a segment. Order: exact, path prefix, exact last segment, other
segment, then note count, then A to Z. The matched letters are drawn
stronger.

One matcher (matchTags) now serves the # list and the + picker. Tags are
split and lowercased once per tag list; 10k tags take about 1 ms a key.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Log times: forgive typos like 08;45 (#556)
Some checks failed
CI / rust (pull_request) Failing after 8s
CI / server (pull_request) Successful in 25s
CI / web (pull_request) Failing after 28s
4b4d38256b
Accept : . ; h between hour and minute, 1-2 digit hours, - – — or 'to'
between times, optional am/pm. The editor's grey now uses the same reader
as + Log; the Rust twin and shared vectors agree. Text is never rewritten.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Accent labels centred under their swatches, bold without shift (#546)
Some checks failed
CI / server (pull_request) Successful in 26s
CI / rust (pull_request) Failing after 2m19s
CI / web (pull_request) Failing after 28s
ad133b9939
Each swatch is a centred flex column. The name is sized by a hidden bold copy
(::after from data-label), so selecting a swatch does not move any label.
A generic .dot rule (margin-left: auto) pushed the swatch dot to the edge; reset it.

Adds an e2e check (chromium-1440, webkit-390): labels are centred under their dots,
and no label's centre moves more than 0.5 px as each swatch is selected.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WCcFhwwgMK66k9LMVqogNJ
Links match the approved look: icon gap .3em, the 70% of missing links mixed like opacity (#448)
Some checks failed
CI / server (pull_request) Successful in 28s
CI / rust (pull_request) Successful in 2m26s
CI / web (pull_request) Failing after 28s
e133019d50
Measured the approved mockup (links.html, #457) against the app in Chromium and WebKit, light and
dark, at 1440 and 390. Two link rules deviated: the gap after the kind icon (.28em, approved .3em;
web .24em, approved .26em) and the 70% of notes that are not there, which was mixed in oklab and
came out about 8 levels darker than the mockup's opacity .7 (now mixed in sRGB, the same blend).
Everything else matched. links-parity.spec.ts pins the approved box, icon, gap, 70% and lit form.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WCcFhwwgMK66k9LMVqogNJ
kayg asked for the mockup's bullet everywhere: a 6 px dot with the text starting 21 px in
(it was a 5 px dot and 26 px). Nested items too.

- cm.css: the marker box is 21 px (still growing with the checkbox at larger text sizes); the
  dot is 6 px, 4 px in; a number starts 4 px in; a to-do box keeps its size with a 3 px gap, so
  its text starts at the same edge as the bullets' text.
- The tree lines meet the markers where the app's `.page` now says: a bullet's centre 6.5 px,
  half height 3 px, left edge 0 (tree.css's defaults stay for the mockup).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WCcFhwwgMK66k9LMVqogNJ
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WCcFhwwgMK66k9LMVqogNJ
Merge remote-tracking branch 'origin/issue/log-times-lenient' into train/2026-10-17y
Some checks failed
CI / server (pull_request) Successful in 36s
CI / rust (pull_request) Failing after 2m44s
CI / web (pull_request) Failing after 28s
99e24d6a58
Author
Owner

This PR's commits are on dev (landed). Forgejo kept it open and its merge endpoint answers 405, so it is closed by hand.

This PR's commits are on dev (landed). Forgejo kept it open and its merge endpoint answers 405, so it is closed by hand.
kayg closed this pull request 2026-10-21 11:32:52 +00:00
Some checks failed
CI / server (pull_request) Successful in 36s
CI / rust (pull_request) Failing after 2m44s
CI / web (pull_request) Failing after 28s

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!565
No description provided.