port: Tasks slice 6, the When field as the bottom-bar morph (approved mockup) #957

Closed
kayg wants to merge 15 commits from port/tasks-6-when into port/tasks-3-s5b
Owner

Slice 6 of the Tasks UI port: the When field as the bottom-bar morph (port of apps/mockup/src/tasks/when/, mockup review/calendar-2).

Stacked on #893 (base = port/tasks-3-s5b), which stacks on #889 / #888 / #832. Rebase onto the layer below when it moves.

What it does: the When pill on the task card morphs the shared bar (Bar + SheetBody) into ONE field for date, time and repeat, a one-sentence read-back with tappable words, chips that follow what is typed, and a month on "Pick a date". It replaces the old When date picker (the Deadline picker stays). Accepting writes only what changed through tasks.update (scheduled, RRULE repeat incl. UNTIL/COUNT/2TU, repeat_from, time_zone); opening and closing with nothing changed writes nothing, so a rule the field cannot show is never flattened.

Notes for review (full numbers, gates and screenshots follow in comments):

  • Lazy chunk WhenField, warmed on card idle / pointer near the pill, sheet opens only once it is in.
  • The card's bar is now drawn through Float into <body> (the pane has a backdrop-filter; glass inside it was opaque). Spec: tasks-when.spec.ts glass-root test.
  • Not ported: the faked Mic (no voice backend yet), the mockup-only fake phone keyboard, the swipe-date debug hook, visible.ts row scrolling and the + Date ghost (list-row entry points, see below).

Draft; never merge without kayg.

🤖 Generated with Claude Code

Slice 6 of the Tasks UI port: **the When field as the bottom-bar morph** (port of `apps/mockup/src/tasks/when/`, mockup `review/calendar-2`). Stacked on #893 (base = `port/tasks-3-s5b`), which stacks on #889 / #888 / #832. Rebase onto the layer below when it moves. What it does: the When pill on the task card morphs the shared bar (`Bar` + `SheetBody`) into ONE field for date, time and repeat, a one-sentence read-back with tappable words, chips that follow what is typed, and a month on "Pick a date". It replaces the old When date picker (the Deadline picker stays). Accepting writes only what changed through `tasks.update` (`scheduled`, RRULE `repeat` incl. `UNTIL`/`COUNT`/`2TU`, `repeat_from`, `time_zone`); opening and closing with nothing changed writes nothing, so a rule the field cannot show is never flattened. Notes for review (full numbers, gates and screenshots follow in comments): - Lazy chunk `WhenField`, warmed on card idle / pointer near the pill, sheet opens only once it is in. - The card's bar is now drawn through `Float` into `<body>` (the pane has a backdrop-filter; glass inside it was opaque). Spec: `tasks-when.spec.ts` glass-root test. - Not ported: the faked Mic (no voice backend yet), the mockup-only fake phone keyboard, the swipe-date debug hook, `visible.ts` row scrolling and the `+ Date` ghost (list-row entry points, see below). Draft; never merge without kayg. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
kayg added 15 commits 2026-11-05 09:52:21 +00:00
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>
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>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
tasks: card spec finds the bar in its own box
Some checks failed
CI / rust (pull_request) Has been cancelled
CI / server (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
2b0b19ae73
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Author
Owner

Product vs mockup, 1440x900, light. Headless WebKit on dev-02. The mockup also draws its stand-in phone keyboard and a mic; the product has neither (see PR body).

product-empty-1440x900-light.png

product-empty-1440x900-light.png

mockup-empty-1440x900-light.png

mockup-empty-1440x900-light.png

product-phrase-1440x900-light.png

product-phrase-1440x900-light.png

mockup-phrase-1440x900-light.png

mockup-phrase-1440x900-light.png

product-repeat-menu-1440x900-light.png

product-repeat-menu-1440x900-light.png

mockup-repeat-menu-1440x900-light.png

mockup-repeat-menu-1440x900-light.png

product-month-1440x900-light.png

product-month-1440x900-light.png

mockup-month-1440x900-light.png

mockup-month-1440x900-light.png

Product vs mockup, 1440x900, light. Headless WebKit on dev-02. The mockup also draws its stand-in phone keyboard and a mic; the product has neither (see PR body). **product-empty-1440x900-light.png** ![product-empty-1440x900-light.png](https://git.kayg.org/attachments/2d78ffd5-ab8b-4275-97be-8b907d743291) **mockup-empty-1440x900-light.png** ![mockup-empty-1440x900-light.png](https://git.kayg.org/attachments/f5285084-88e9-42bb-8368-b05d8159b8d5) **product-phrase-1440x900-light.png** ![product-phrase-1440x900-light.png](https://git.kayg.org/attachments/1277b888-de5e-4c90-b36a-0345faca21c5) **mockup-phrase-1440x900-light.png** ![mockup-phrase-1440x900-light.png](https://git.kayg.org/attachments/74adbf19-b4a3-44bd-b503-985fce8f007d) **product-repeat-menu-1440x900-light.png** ![product-repeat-menu-1440x900-light.png](https://git.kayg.org/attachments/b46f1126-5df2-414e-b119-2d974d53e987) **mockup-repeat-menu-1440x900-light.png** ![mockup-repeat-menu-1440x900-light.png](https://git.kayg.org/attachments/8ebe285b-f9d6-4afa-a969-e38e1f25caa3) **product-month-1440x900-light.png** ![product-month-1440x900-light.png](https://git.kayg.org/attachments/98e54de1-db55-45c7-99ad-8d85e780f20c) **mockup-month-1440x900-light.png** ![mockup-month-1440x900-light.png](https://git.kayg.org/attachments/7c51ce79-d121-448d-b7be-69a857741432)
Author
Owner

Product vs mockup, 1440x900, dark. Headless WebKit on dev-02. The mockup also draws its stand-in phone keyboard and a mic; the product has neither (see PR body).

product-empty-1440x900-dark.png

product-empty-1440x900-dark.png

mockup-empty-1440x900-dark.png

mockup-empty-1440x900-dark.png

product-phrase-1440x900-dark.png

product-phrase-1440x900-dark.png

mockup-phrase-1440x900-dark.png

mockup-phrase-1440x900-dark.png

product-repeat-menu-1440x900-dark.png

product-repeat-menu-1440x900-dark.png

mockup-repeat-menu-1440x900-dark.png

mockup-repeat-menu-1440x900-dark.png

product-month-1440x900-dark.png

product-month-1440x900-dark.png

mockup-month-1440x900-dark.png

mockup-month-1440x900-dark.png

Product vs mockup, 1440x900, dark. Headless WebKit on dev-02. The mockup also draws its stand-in phone keyboard and a mic; the product has neither (see PR body). **product-empty-1440x900-dark.png** ![product-empty-1440x900-dark.png](https://git.kayg.org/attachments/a27875e7-e16d-41e5-8379-f28868cf1bb9) **mockup-empty-1440x900-dark.png** ![mockup-empty-1440x900-dark.png](https://git.kayg.org/attachments/436a9773-860b-4e61-9c60-562da45af790) **product-phrase-1440x900-dark.png** ![product-phrase-1440x900-dark.png](https://git.kayg.org/attachments/067e64c2-cabc-4ef5-9441-1a07bba405c5) **mockup-phrase-1440x900-dark.png** ![mockup-phrase-1440x900-dark.png](https://git.kayg.org/attachments/f710af2d-8b5e-4e76-a11d-1fa29dad009e) **product-repeat-menu-1440x900-dark.png** ![product-repeat-menu-1440x900-dark.png](https://git.kayg.org/attachments/f36c2e99-463a-4e44-9d6a-50a2fec36635) **mockup-repeat-menu-1440x900-dark.png** ![mockup-repeat-menu-1440x900-dark.png](https://git.kayg.org/attachments/4c4d0531-7480-4e10-9085-e1dccb5c8325) **product-month-1440x900-dark.png** ![product-month-1440x900-dark.png](https://git.kayg.org/attachments/a8b07fd6-53a9-4e06-b5bf-3a812c2d9b8b) **mockup-month-1440x900-dark.png** ![mockup-month-1440x900-dark.png](https://git.kayg.org/attachments/e26fc27d-4c16-4901-a4c5-9fc0aa5942dc)
Author
Owner

Product vs mockup, 390x844, light. Headless WebKit on dev-02. The mockup also draws its stand-in phone keyboard and a mic; the product has neither (see PR body).

product-empty-390x844-light.png

product-empty-390x844-light.png

mockup-empty-390x844-light.png

mockup-empty-390x844-light.png

product-phrase-390x844-light.png

product-phrase-390x844-light.png

mockup-phrase-390x844-light.png

mockup-phrase-390x844-light.png

product-repeat-menu-390x844-light.png

product-repeat-menu-390x844-light.png

mockup-repeat-menu-390x844-light.png

mockup-repeat-menu-390x844-light.png

product-month-390x844-light.png

product-month-390x844-light.png

mockup-month-390x844-light.png

mockup-month-390x844-light.png

Product vs mockup, 390x844, light. Headless WebKit on dev-02. The mockup also draws its stand-in phone keyboard and a mic; the product has neither (see PR body). **product-empty-390x844-light.png** ![product-empty-390x844-light.png](https://git.kayg.org/attachments/0dd0e4a2-605e-41f0-a08f-c23aa19593aa) **mockup-empty-390x844-light.png** ![mockup-empty-390x844-light.png](https://git.kayg.org/attachments/f1dd8acc-9757-4d29-9cf2-baaba22d2962) **product-phrase-390x844-light.png** ![product-phrase-390x844-light.png](https://git.kayg.org/attachments/fef551e5-8017-40a7-ae63-dc084b20ed24) **mockup-phrase-390x844-light.png** ![mockup-phrase-390x844-light.png](https://git.kayg.org/attachments/12fb8f92-5add-417c-b129-eddbf61c5b3c) **product-repeat-menu-390x844-light.png** ![product-repeat-menu-390x844-light.png](https://git.kayg.org/attachments/39a98d58-4f08-49bd-84f9-89b103120bab) **mockup-repeat-menu-390x844-light.png** ![mockup-repeat-menu-390x844-light.png](https://git.kayg.org/attachments/2a6e0152-4df1-442b-89ea-67c88ebff962) **product-month-390x844-light.png** ![product-month-390x844-light.png](https://git.kayg.org/attachments/c31e71dd-88bb-482e-9401-5c7075aab1a5) **mockup-month-390x844-light.png** ![mockup-month-390x844-light.png](https://git.kayg.org/attachments/4f8a66b0-6f78-40e9-8f0b-fb59ae0d0eee)
Author
Owner

Product vs mockup, 390x844, dark. Headless WebKit on dev-02. The mockup also draws its stand-in phone keyboard and a mic; the product has neither (see PR body).

product-empty-390x844-dark.png

product-empty-390x844-dark.png

mockup-empty-390x844-dark.png

mockup-empty-390x844-dark.png

product-phrase-390x844-dark.png

product-phrase-390x844-dark.png

mockup-phrase-390x844-dark.png

mockup-phrase-390x844-dark.png

product-repeat-menu-390x844-dark.png

product-repeat-menu-390x844-dark.png

mockup-repeat-menu-390x844-dark.png

mockup-repeat-menu-390x844-dark.png

product-month-390x844-dark.png

product-month-390x844-dark.png

mockup-month-390x844-dark.png

mockup-month-390x844-dark.png

Product vs mockup, 390x844, dark. Headless WebKit on dev-02. The mockup also draws its stand-in phone keyboard and a mic; the product has neither (see PR body). **product-empty-390x844-dark.png** ![product-empty-390x844-dark.png](https://git.kayg.org/attachments/09cfd4aa-7999-49e3-b379-1afbe03ef8fd) **mockup-empty-390x844-dark.png** ![mockup-empty-390x844-dark.png](https://git.kayg.org/attachments/cdbc8527-4829-45ba-aa02-f0340d843fcf) **product-phrase-390x844-dark.png** ![product-phrase-390x844-dark.png](https://git.kayg.org/attachments/b145fba9-4b33-44a7-9f37-dcc72bbe99fa) **mockup-phrase-390x844-dark.png** ![mockup-phrase-390x844-dark.png](https://git.kayg.org/attachments/98787389-3e56-4189-a563-0d6b5addeabd) **product-repeat-menu-390x844-dark.png** ![product-repeat-menu-390x844-dark.png](https://git.kayg.org/attachments/76aab048-9787-46fd-8456-7bc361a85a4d) **mockup-repeat-menu-390x844-dark.png** ![mockup-repeat-menu-390x844-dark.png](https://git.kayg.org/attachments/4010a66a-4b55-4e12-b64c-56d7a0db5adb) **product-month-390x844-dark.png** ![product-month-390x844-dark.png](https://git.kayg.org/attachments/1a7e198b-5431-4b29-92e1-faa55871484c) **mockup-month-390x844-dark.png** ![mockup-month-390x844-dark.png](https://git.kayg.org/attachments/37e56f8c-81a0-4545-8b9e-696f06b054cb)
Author
Owner

Gates and numbers (head 536f59d2, base #893 d7df9bbb)

Unit + types (dev-02, ~/bin/slot): bunx vitest run src/tasks 31 passed; svelte-check clean for every file this PR touches (2 existing errors in e2e/review4-signout.spec.ts and actions.gen.ts out of date are on the base).

Playwright, CI=1 --retries=0 --workers=1, via ~/bin/slot, specs tasks-when tasks-card tasks-lazy tasks-swipe tasks-no-hscroll tasks-contrast tasks-tick tasks-lists tasks-board:

  • dev-02 WebKit --project=webkit-1440 --project=webkit-390: 90 passed, 10 skipped, 0 failed.
  • dev-01 Chromium --project=chromium-1440 --project=chromium-390: 89 passed, 10 skipped, 1 failed: tasks-board.spec.ts:56 (a row dropped on Someday in the sidebar). It is intermittent on the base too: --repeat-each=10 chromium-1440 gives 3/10 failures on this head and 1/10 on #893's head d7df9bbb. Not touched by this PR; needs a stability issue. (By the flaky rule it reproduces, so it is on #893's side to fix.)
  • New tasks-when.spec.ts (14 tests): morph + caret, phrase + offset, Escape writes nothing, untouched Enter writes nothing (keeps BYDAY=MO,WE), chips, word menus, rules written (INTERVAL=2;BYDAY=TU, BYDAY=2TU, weekdays, COUNT), month, No date, Tab/arrows/Escape, tap outside accepts, swipe's ?pick=when, lazy chunk, glass root.

Bundle (brotli, node scripts/bundle-size.mjs dist, dev-01):

base #893 this PR
first paint JS 235.0 KB 235.0 KB (no change)
first paint CSS 18.9 KB 18.9 KB (no change)
TasksScreen JS 12.0 KB 12.7 KB (+0.7: card lazy-loader, Float)
WhenField JS chunk n/a 8.7 KB (24.5 raw / 9.6 gzip)
WhenField CSS n/a 1.2 KB (4.8 raw / 1.4 gzip)
all JS 337.5 KB 346.9 KB

No budget file touched. Needs a decision: perf/web-report.mjs wants an explicit web.bundle.chunk.WhenField budget for a new chunk name, and total_js_brotli must equal the sum of chunk budgets, so merging needs a new entry of about 8.7 KB (plus a total that grows by the same). I did not add or raise anything.

Frames, Mac VM lume@calternal-macos-01-std (WebKit, real GPU), 15 open/close cycles per run, ABAB x3 rounds, base = #893's When date picker (same Bar morph): p95 of rAF deltas in ms, frames over 25 ms / frames:

open p95 open >25 ms close p95 close >25 ms
1440 base r1/r2/r3 32 / 32 / 34 52/609, 43/562, 54/605 30 / 28 / 29 41/575, 35/574, 42/569
1440 head r1/r2/r3 31 / 29 / 27 49/644, 41/655, 39/653 30 / 28 / 24 39/571, 43/601, 27/599
390 base r1/r2/r3 24 / 25 / 24 22/655, 30/658, 22/688 24 / 26 / 24 16/628, 39/624, 24/632
390 head r1/r2/r3 23 / 24 / 23 12/673, 18/666, 11/692 23 / 24 / 25 16/631, 24/636, 29/631

Tap to sheet in the DOM: p50 about 50 ms at both sizes. Head is equal or better than base in every round, but neither meets the app's 20 ms p95 / 0 frames over 25 ms gate on this 4-core Mac VM (even the old picker does not). One head close at 1440 had a 3,678 ms gap in round 1 (a VM stall, not seen in rounds 2-3). The numbers say the morph is no worse than what was there; they do not prove 60 fps.

Not ported, and why

  • Mic (hold to talk): the mockup's is a fake transcript; no voice backend exists. Not shipped as a lie.
  • Keyboard.svelte (stand-in phone keyboard) and debug.ts (swipe-date hook): mockup test aids.
  • visible.ts and GhostDate (+ Date on a row): they belong to opening the field from a list row without the card; this slice opens it from the card's When pill and the swipe's Date. Row-chip entry is a follow-up.
  • SheetBody title + close ✕ (mockup): the shared product SheetBody is the inspector's (IN6: no title, no ✕); not forked.
  • repeat_from is written ("After I finish") but tasks.get does not return it, so reopening shows it off until the backend exposes it. Words on reopen: "Every 2nd Tuesday" Props pill still says "Monthly" (describeRepeat is the base's).
  • Named days ("3 days after Diwali") resolve to a plain date; a short table (2026-27) feeds them.
## Gates and numbers (head `536f59d2`, base #893 `d7df9bbb`) **Unit + types** (dev-02, `~/bin/slot`): `bunx vitest run src/tasks` 31 passed; `svelte-check` clean for every file this PR touches (2 existing errors in `e2e/review4-signout.spec.ts` and `actions.gen.ts` out of date are on the base). **Playwright**, `CI=1 --retries=0 --workers=1`, via `~/bin/slot`, specs `tasks-when tasks-card tasks-lazy tasks-swipe tasks-no-hscroll tasks-contrast tasks-tick tasks-lists tasks-board`: - dev-02 WebKit `--project=webkit-1440 --project=webkit-390`: **90 passed, 10 skipped, 0 failed**. - dev-01 Chromium `--project=chromium-1440 --project=chromium-390`: **89 passed, 10 skipped, 1 failed**: `tasks-board.spec.ts:56` (a row dropped on Someday in the sidebar). It is intermittent on the base too: `--repeat-each=10` chromium-1440 gives 3/10 failures on this head and 1/10 on #893's head `d7df9bbb`. Not touched by this PR; needs a stability issue. (By the flaky rule it reproduces, so it is on #893's side to fix.) - New `tasks-when.spec.ts` (14 tests): morph + caret, phrase + offset, Escape writes nothing, untouched Enter writes nothing (keeps `BYDAY=MO,WE`), chips, word menus, rules written (`INTERVAL=2;BYDAY=TU`, `BYDAY=2TU`, weekdays, `COUNT`), month, No date, Tab/arrows/Escape, tap outside accepts, swipe's `?pick=when`, lazy chunk, glass root. **Bundle** (brotli, `node scripts/bundle-size.mjs dist`, dev-01): | | base #893 | this PR | |---|---|---| | first paint JS | 235.0 KB | **235.0 KB** (no change) | | first paint CSS | 18.9 KB | **18.9 KB** (no change) | | TasksScreen JS | 12.0 KB | 12.7 KB (+0.7: card lazy-loader, Float) | | `WhenField` JS chunk | n/a | **8.7 KB** (24.5 raw / 9.6 gzip) | | `WhenField` CSS | n/a | 1.2 KB (4.8 raw / 1.4 gzip) | | all JS | 337.5 KB | 346.9 KB | No budget file touched. **Needs a decision:** `perf/web-report.mjs` wants an explicit `web.bundle.chunk.WhenField` budget for a new chunk name, and `total_js_brotli` must equal the sum of chunk budgets, so merging needs a new entry of about 8.7 KB (plus a total that grows by the same). I did not add or raise anything. **Frames**, Mac VM `lume@calternal-macos-01-std` (WebKit, real GPU), 15 open/close cycles per run, ABAB x3 rounds, base = #893's When date picker (same Bar morph): p95 of rAF deltas in ms, frames over 25 ms / frames: | | open p95 | open >25 ms | close p95 | close >25 ms | |---|---|---|---|---| | 1440 base r1/r2/r3 | 32 / 32 / 34 | 52/609, 43/562, 54/605 | 30 / 28 / 29 | 41/575, 35/574, 42/569 | | 1440 head r1/r2/r3 | 31 / 29 / 27 | 49/644, 41/655, 39/653 | 30 / 28 / 24 | 39/571, 43/601, 27/599 | | 390 base r1/r2/r3 | 24 / 25 / 24 | 22/655, 30/658, 22/688 | 24 / 26 / 24 | 16/628, 39/624, 24/632 | | 390 head r1/r2/r3 | 23 / 24 / 23 | 12/673, 18/666, 11/692 | 23 / 24 / 25 | 16/631, 24/636, 29/631 | Tap to sheet in the DOM: p50 about 50 ms at both sizes. Head is equal or better than base in every round, but **neither meets the app's 20 ms p95 / 0 frames over 25 ms gate on this 4-core Mac VM** (even the old picker does not). One head close at 1440 had a 3,678 ms gap in round 1 (a VM stall, not seen in rounds 2-3). The numbers say the morph is no worse than what was there; they do not prove 60 fps. **Not ported, and why** - Mic (hold to talk): the mockup's is a fake transcript; no voice backend exists. Not shipped as a lie. - `Keyboard.svelte` (stand-in phone keyboard) and `debug.ts` (swipe-date hook): mockup test aids. - `visible.ts` and `GhostDate` (`+ Date` on a row): they belong to opening the field from a list row without the card; this slice opens it from the card's When pill and the swipe's Date. Row-chip entry is a follow-up. - SheetBody `title` + close ✕ (mockup): the shared product SheetBody is the inspector's (IN6: no title, no ✕); not forked. - `repeat_from` is written ("After I finish") but `tasks.get` does not return it, so reopening shows it off until the backend exposes it. Words on reopen: "Every 2nd Tuesday" Props pill still says "Monthly" (`describeRepeat` is the base's). - Named days ("3 days after Diwali") resolve to a plain date; a short table (2026-27) feeds them.
Author
Owner

housekeeping #1009: rebased+failing, left open for review.

restacked on #893. reconciled async When selection and keyboard ownership with swipe query restoration; fixed whitespace. documented explicit Swap start/end blur and resting blur zero; inherits TaskCard repairs.

head: 92d926dbbecf748fe7c9779462dbd0366ced7753; based on dev cd7f84432febfc63b788fbb9b9f9950452982d74, pushed with the original exact force-with-lease.

frontend frozen install, check, lint, build and unit tests passed. bundle gate failed. first-paint brotli vs dev: JS 232434 B (+1657 B), CSS 18561 B (+175 B).

targeted Chromium and WebKit specs at 1440 and 390 never started. the audit waited more than three hours behind the live daily-train-1107 locks (first queue at 23:45 IST, 7 November; final queue cleanup after 02:46 IST, 8 November). browser validation and UI captures are unrun. only this audit’s exact queued units were stopped; the train locks and owners were left intact. hot-path perf qualification is unrun.

all executed gates used the VM Nix environment, shared Mac lock and slot. exact commands, source heads, logs and dev baseline. frontend inputs are identical to the tested frontend tree when a Rust-only repair changed the head.

original-head cherry/patch inventory, pr-957.md; unmatched entries are missing-patch candidates, with semantic overlap/replacements noted above.

final queue, cleanup and source-verification evidence.

housekeeping #1009: rebased+failing, left open for review. restacked on #893. reconciled async When selection and keyboard ownership with swipe query restoration; fixed whitespace. documented explicit Swap start/end blur and resting blur zero; inherits TaskCard repairs. head: `92d926dbbecf748fe7c9779462dbd0366ced7753`; based on dev `cd7f84432febfc63b788fbb9b9f9950452982d74`, pushed with the original exact force-with-lease. frontend frozen install, check, lint, build and unit tests passed. bundle gate failed. first-paint brotli vs dev: JS 232434 B (+1657 B), CSS 18561 B (+175 B). targeted Chromium and WebKit specs at 1440 and 390 never started. the audit waited more than three hours behind the live daily-train-1107 locks (first queue at 23:45 IST, 7 November; final queue cleanup after 02:46 IST, 8 November). browser validation and UI captures are unrun. only this audit’s exact queued units were stopped; the train locks and owners were left intact. hot-path perf qualification is unrun. all executed gates used the VM Nix environment, shared Mac lock and slot. [exact commands, source heads, logs and dev baseline](https://git.kayg.org/attachments/870a0fef-2e31-425c-aea6-eb87a66d365a). frontend inputs are identical to the tested frontend tree when a Rust-only repair changed the head. [original-head cherry/patch inventory](https://git.kayg.org/attachments/e05a38dc-c028-4d77-8655-efa9d5c8ea50), `pr-957.md`; unmatched entries are missing-patch candidates, with semantic overlap/replacements noted above. [final queue, cleanup and source-verification evidence](https://git.kayg.org/attachments/7ab315a5-4b6c-4af1-971b-cdae2637adae).
Author
Owner

Final-port test pass (issue #1009), READY: no: specs pass; bundle gate fails; first paint is bigger than dev.

head 92d926dbbecf748fe7c9779462dbd0366ced7753

Targeted specs, CI=1 --retries=0 --workers=1, dev-01 Chromium and dev-02 WebKit (through ~/bin/slot), against a dev-head backend (cd7f84432).

spec Chromium 1440 Chromium 390 WebKit 1440 WebKit 390
tasks-card, tasks-when 21/21 19/19 21/21 19/19

Bundle gate: perf/web.sh --bundle-only --gate (the 17 failures from the housekeeping audit). Per the gate's own rule (total_js_brotli budget must equal the sum of the named chunk budgets) a cap can only move between named chunks; there is no donor chunk inside this PR, so a fix is a code cut or a decision by kayg. I raised nothing and moved nothing.

  • Over: total_js_brotli 499.17 vs 488.3 (+10.9 KB), TasksScreen 12.82, index 226.99, idle-screens 55.75, and WhenField (8.7 KB), press, recognise have no budget.
  • First paint: JS +1657 B, CSS +175 B vs dev (rule: <= dev).

Not done: Not run yet: Mac VM Safari blur/frame check and perf ABAB x5 on the perf VMs (they need a ready PR first); light/dark 2x screenshots against the mockup are only done for #888 (see its comment).

Not marked READY FOR MERGE.

**Final-port test pass (issue #1009), READY: no: specs pass; bundle gate fails; first paint is bigger than dev.** head `92d926dbbecf748fe7c9779462dbd0366ced7753` Targeted specs, `CI=1 --retries=0 --workers=1`, dev-01 Chromium and dev-02 WebKit (through `~/bin/slot`), against a dev-head backend (`cd7f84432`). | spec | Chromium 1440 | Chromium 390 | WebKit 1440 | WebKit 390 | |---|---|---|---|---| | tasks-card, tasks-when | 21/21 | 19/19 | 21/21 | 19/19 | **Bundle gate:** `perf/web.sh --bundle-only --gate` (the 17 failures from the housekeeping audit). Per the gate's own rule (`total_js_brotli` budget must equal the sum of the named chunk budgets) a cap can only move between named chunks; there is no donor chunk inside this PR, so a fix is a code cut or a decision by kayg. I raised nothing and moved nothing. - Over: `total_js_brotli` 499.17 vs 488.3 (+10.9 KB), `TasksScreen` 12.82, `index` 226.99, `idle-screens` 55.75, and `WhenField` (8.7 KB), `press`, `recognise` have no budget. - First paint: JS +1657 B, CSS +175 B vs dev (rule: <= dev). **Not done:** Not run yet: Mac VM Safari blur/frame check and perf ABAB x5 on the perf VMs (they need a ready PR first); light/dark 2x screenshots against the mockup are only done for #888 (see its comment). Not marked READY FOR MERGE.
Author
Owner

Final gates (issue #1009), 3d4e16c3e9

head 3d4e16c3e9e7729a1aadf36d2dad709dbb79a25d, on dev 2fa9e18fb (#888 merged).

READY FOR MERGE (after #893).

gate result
first paint JS, plain build, median of 3 builds (the three are byte-identical) 228459 B vs dev 231155 B: -2696 B
first paint JS, hash-normalised 228128 B vs 230622 B: -2494 B
first paint CSS 18126 B vs 18371 B: -245 B
specs, Chromium 1440 + 390 (dev-01) tasks-card, tasks-when, press, tasks-board, tasks-swipe: 58 passed (18 skipped by design)
specs, WebKit 1440 + 390 (dev-02) 58 passed (18 skipped)
perf/web.sh --bundle-only --gate passes
perf ABAB x5 + control below (taken on the previous dev; this PR's hot paths are unchanged since)
screenshots, 2x light and dark, 1440 and 390; real Safari on #957 below

First paint, two ways. Plain: the build as shipped, brotli of the first-screen files (dev 231155 B JS, 18371 B CSS). Hash-normalised: the same files with the random chunk hashes replaced by a constant, which removes the 100 to 250 B that any change adds through the hashes (dev 230622 B). Stack tip.

Typing and open-note, perf-02, Chromium with 4x CPU slowdown, 10k Home, release server (dev head, 20eab8d3a) for every arm, rounds rotated, 5 rounds. devA and devB are the same dev build (the control). Median of the 5 per-run medians [min-max], ms:

metric devA devB (control) #957 (stack tip)
typing, long note p50 22.3 [22.1-22.6] 22.4 [21.8-23.4] 22.5 [21.8-26.2]
typing, long note CPU/key 26.9 [26.5-27.3] 27.4 [26.7-27.7] 27.2 [26.7-27.9]
typing, nested list p50 42.2 [42.1-42.9] 42.4 [42.1-43.1] 42.5 [41.9-43.5]
typing, nested list CPU/key 49.1 [48.8-50.9] 49.8 [49.0-50.4] 50.2 [49.1-51.0]
open note (blaze), shown p50 35.0 [34.3-35.8] 35.3 [34.0-36.4] 35.2 [33.5-35.3]
open note, back p50 30.9 [30.1-31.5] 31.2 [30.8-31.8] 31.7 [31.1-32.0]
flick through 50 notes, CPU 70.8 [70.5-77.1] 75.4 [72.2-82.7] 73.1 [69.4-77.3]
longest task in the flick 143 [133-151] 151 [150-184] 142 [129-173]

Every metric of the tip sits inside the dev-vs-dev control (the control itself differs by 4.6 ms in the flick's CPU). Two variants of the press registration (one effect per row; the press engine asked for on pointer intent) were built and measured in the same session (v1 76.4, v2 74.8 in the flick's CPU): neither beats the control, so neither is in the PRs. The earlier session (which showed +1.4 to +3.3 % on the tip) was one that the control spread covers as well.

Screenshots (2x; light and dark; 1440x900 and 390x844). Left: the approved mockup (review/calendar-2). Right: this PR.

list

mockup this PR
1440 light
1440 dark
390 light
390 dark

list-ticked

mockup this PR
1440 light a tick is interactive; not in the static mockup
1440 dark a tick is interactive; not in the static mockup
390 light a tick is interactive; not in the static mockup
390 dark a tick is interactive; not in the static mockup

card

mockup this PR
1440 light
1440 dark
390 light
390 dark

board

mockup this PR
1440 light
1440 dark
390 light
390 dark

when

mockup this PR
1440 light
1440 dark
390 light
390 dark

Differences from the mockup that are later slices or not ported: the view switcher beyond List and Board, the Views section, the big title, the share and more pills on the card, the mic in the When field; the product also shows its own sky backdrop and the seeded tasks above.

Real Safari (Mac VM, safaridriver, 1x: the VM reports devicePixelRatio 1), this stack's tip, #957

Taken on 11-08 from the #957 build (it carries #888 to #957). Where glass and blur show: the sidebar, the card and the When sheet.

list

light dark
1440
390

card

light dark
1440
390

when

light dark
1440
390
**Final gates (issue #1009), 3d4e16c3e9e7729a1aadf36d2dad709dbb79a25d** head `3d4e16c3e9e7729a1aadf36d2dad709dbb79a25d`, on dev `2fa9e18fb` (#888 merged). **READY FOR MERGE** (after #893). | gate | result | |---|---| | first paint JS, plain build, median of 3 builds (the three are byte-identical) | **228459 B vs dev 231155 B: -2696 B** | | first paint JS, hash-normalised | 228128 B vs 230622 B: **-2494 B** | | first paint CSS | 18126 B vs 18371 B: -245 B | | specs, Chromium 1440 + 390 (dev-01) | tasks-card, tasks-when, press, tasks-board, tasks-swipe: 58 passed (18 skipped by design) | | specs, WebKit 1440 + 390 (dev-02) | 58 passed (18 skipped) | | `perf/web.sh --bundle-only --gate` | passes | | perf ABAB x5 + control | below (taken on the previous dev; this PR's hot paths are unchanged since) | | screenshots, 2x light and dark, 1440 and 390; real Safari on #957 | below | **First paint, two ways.** Plain: the build as shipped, brotli of the first-screen files (dev 231155 B JS, 18371 B CSS). Hash-normalised: the same files with the random chunk hashes replaced by a constant, which removes the 100 to 250 B that any change adds through the hashes (dev 230622 B). Stack tip. Typing and open-note, perf-02, Chromium with 4x CPU slowdown, 10k Home, release server (dev head, 20eab8d3a) for every arm, rounds rotated, 5 rounds. `devA` and `devB` are the same dev build (the control). Median of the 5 per-run medians [min-max], ms: | metric | devA | devB (control) | #957 (stack tip) | |---|---|---|---| | typing, long note p50 | 22.3 [22.1-22.6] | 22.4 [21.8-23.4] | 22.5 [21.8-26.2] | | typing, long note CPU/key | 26.9 [26.5-27.3] | 27.4 [26.7-27.7] | 27.2 [26.7-27.9] | | typing, nested list p50 | 42.2 [42.1-42.9] | 42.4 [42.1-43.1] | 42.5 [41.9-43.5] | | typing, nested list CPU/key | 49.1 [48.8-50.9] | 49.8 [49.0-50.4] | 50.2 [49.1-51.0] | | open note (blaze), shown p50 | 35.0 [34.3-35.8] | 35.3 [34.0-36.4] | 35.2 [33.5-35.3] | | open note, back p50 | 30.9 [30.1-31.5] | 31.2 [30.8-31.8] | 31.7 [31.1-32.0] | | flick through 50 notes, CPU | 70.8 [70.5-77.1] | 75.4 [72.2-82.7] | 73.1 [69.4-77.3] | | longest task in the flick | 143 [133-151] | 151 [150-184] | 142 [129-173] | Every metric of the tip sits inside the dev-vs-dev control (the control itself differs by 4.6 ms in the flick's CPU). Two variants of the press registration (one effect per row; the press engine asked for on pointer intent) were built and measured in the same session (v1 76.4, v2 74.8 in the flick's CPU): neither beats the control, so neither is in the PRs. The earlier session (which showed +1.4 to +3.3 % on the tip) was one that the control spread covers as well. ### Screenshots (2x; light and dark; 1440x900 and 390x844). Left: the approved mockup (review/calendar-2). Right: this PR. **list** | | mockup | this PR | |---|---|---| | 1440 light | ![](https://git.kayg.org/attachments/19f321d2-f2a1-4365-aa2d-6fbb8513f1a2) | ![](https://git.kayg.org/attachments/25840458-bfb6-4163-983b-c7c9ee968314) | | 1440 dark | ![](https://git.kayg.org/attachments/afb72d9e-60f3-47f1-aa9c-0a0fc6b4ee11) | ![](https://git.kayg.org/attachments/740c2631-9a14-4155-a4ae-5e84e15dd81e) | | 390 light | ![](https://git.kayg.org/attachments/45d03148-7ec2-4058-91d9-11300d515f4b) | ![](https://git.kayg.org/attachments/a17d2883-615f-4bdb-9432-ca20b1028a4c) | | 390 dark | ![](https://git.kayg.org/attachments/8f3796e3-5c7f-47f7-8cdb-82ec6d223d6a) | ![](https://git.kayg.org/attachments/39609085-9d58-45bc-82c7-6d9cca1a3388) | **list-ticked** | | mockup | this PR | |---|---|---| | 1440 light | a tick is interactive; not in the static mockup | ![](https://git.kayg.org/attachments/6634d172-bcc5-41bf-a971-e290ff3dd3fa) | | 1440 dark | a tick is interactive; not in the static mockup | ![](https://git.kayg.org/attachments/63d57a8e-9d31-4a48-ad96-82cd72f9cf7f) | | 390 light | a tick is interactive; not in the static mockup | ![](https://git.kayg.org/attachments/a89a4433-2ace-4f4d-ace1-e418d9fbce25) | | 390 dark | a tick is interactive; not in the static mockup | ![](https://git.kayg.org/attachments/ccae935d-c76d-4f41-a97b-ab5df08014a1) | **card** | | mockup | this PR | |---|---|---| | 1440 light | ![](https://git.kayg.org/attachments/5f2b88c8-da1b-46f6-92c5-88da9e955f92) | ![](https://git.kayg.org/attachments/ea307319-92c2-48b4-b155-7bc1403eeaf8) | | 1440 dark | ![](https://git.kayg.org/attachments/b6a6625b-fa77-448c-9d08-4334ff29c587) | ![](https://git.kayg.org/attachments/6c5aaedf-8571-4289-8b5a-761d3823a62d) | | 390 light | ![](https://git.kayg.org/attachments/6638b24a-0b0d-41ab-9aad-e9126708842f) | ![](https://git.kayg.org/attachments/06a475a9-b4e4-4eda-bd1f-477b10d21df2) | | 390 dark | ![](https://git.kayg.org/attachments/e15cbb58-f92a-4c8c-8d98-0d46ab1ab565) | ![](https://git.kayg.org/attachments/6d831a08-addc-4d87-991e-cd68889ad184) | **board** | | mockup | this PR | |---|---|---| | 1440 light | ![](https://git.kayg.org/attachments/c2c39bc6-039f-4e62-b7d8-930018286558) | ![](https://git.kayg.org/attachments/76579a03-1c6e-454d-aee1-e4a8f46855b7) | | 1440 dark | ![](https://git.kayg.org/attachments/6be0c763-d41c-4c1d-b757-c5deb2cf5fa3) | ![](https://git.kayg.org/attachments/8163446a-8e3a-433a-a5bf-69bce748a3a4) | | 390 light | ![](https://git.kayg.org/attachments/686d1e64-c8c5-4402-80c2-8b379a614f6a) | ![](https://git.kayg.org/attachments/ba92bea3-60b9-4ee7-829d-5c0891a40859) | | 390 dark | ![](https://git.kayg.org/attachments/e1460b77-4201-4cde-a614-fa8f905df294) | ![](https://git.kayg.org/attachments/4b59aa58-7673-4282-9f68-09acba208226) | **when** | | mockup | this PR | |---|---|---| | 1440 light | ![](https://git.kayg.org/attachments/29197123-ad47-4f0e-9d1d-e4c2ed253ed5) | ![](https://git.kayg.org/attachments/b2e0d32f-7aa4-4025-b399-b660e7963a85) | | 1440 dark | ![](https://git.kayg.org/attachments/705a2d3a-4fee-4a9a-925f-05acb06b9586) | ![](https://git.kayg.org/attachments/3e73c9d4-8550-49e3-9627-644bd6023369) | | 390 light | ![](https://git.kayg.org/attachments/f52ac1d7-bf55-4e0f-9a89-fb3b1ba04426) | ![](https://git.kayg.org/attachments/2f40eebd-f429-40d4-bde7-eeddf4a5d9e9) | | 390 dark | ![](https://git.kayg.org/attachments/ce3edd8b-8096-46aa-a0e5-5a664bae4c6f) | ![](https://git.kayg.org/attachments/e5ef4b92-d0ca-4d64-bae7-5509601f03af) | Differences from the mockup that are later slices or not ported: the view switcher beyond List and Board, the Views section, the big title, the share and more pills on the card, the mic in the When field; the product also shows its own sky backdrop and the seeded tasks above. ### Real Safari (Mac VM, safaridriver, 1x: the VM reports devicePixelRatio 1), this stack's tip, #957 Taken on 11-08 from the #957 build (it carries #888 to #957). Where glass and blur show: the sidebar, the card and the When sheet. **list** | | light | dark | |---|---|---| | 1440 | ![](https://git.kayg.org/attachments/dca6f6ed-ffdc-443a-9921-d5d0b977e26a) | ![](https://git.kayg.org/attachments/abd969a6-11cd-401e-9315-961d7606f683) | | 390 | ![](https://git.kayg.org/attachments/8c18727f-771e-48f9-93a0-544503f14ded) | ![](https://git.kayg.org/attachments/57834704-8681-4e6f-8b6f-8a52de2c3dc4) | **card** | | light | dark | |---|---|---| | 1440 | ![](https://git.kayg.org/attachments/00cd7dd3-16b9-4c42-8e55-679c309e1e01) | ![](https://git.kayg.org/attachments/9dccd6a3-cf25-486d-af49-0c678516c530) | | 390 | ![](https://git.kayg.org/attachments/bb62a827-b81b-4499-bcac-0ed4ef30615d) | ![](https://git.kayg.org/attachments/e2e1ca5a-e9ac-4d67-9283-e726ca1ab6b2) | **when** | | light | dark | |---|---|---| | 1440 | ![](https://git.kayg.org/attachments/afc85d7a-03eb-4657-a785-b0497af6777e) | ![](https://git.kayg.org/attachments/f3d03683-a472-4f53-90a5-324e436738a5) | | 390 | ![](https://git.kayg.org/attachments/3d1dc89e-289b-43de-aea8-03cb71447cc9) | ![](https://git.kayg.org/attachments/7cd62509-6245-4e0f-aa00-bbbf07c427da) |
Author
Owner

Header and card crops (issue #1009), 3d4e16c3e9

The layout switcher's List and Board icons were never registered in the Tasks icon set (the switcher arrived with #893), so both drew the notes icon: two identical document icons. They are registered now (the mockup's own paths), in this PR's range and carried into #957. The mockup also has a third switcher icon, Matrix (a 2x2 grid); the Matrix view is not part of the ported slices, so the product has two icons, not a dead third button.

Header, 2x crop of the list pane (the switcher at the top right)

mockup this PR
1440 light
1440 dark
390 light
390 dark
**Header and card crops (issue #1009), 3d4e16c3e9e7729a1aadf36d2dad709dbb79a25d** The layout switcher's List and Board icons were never registered in the Tasks icon set (the switcher arrived with #893), so both drew the notes icon: two identical document icons. They are registered now (the mockup's own paths), in this PR's range and carried into #957. The mockup also has a third switcher icon, Matrix (a 2x2 grid); the Matrix view is not part of the ported slices, so the product has two icons, not a dead third button. **Header, 2x crop of the list pane (the switcher at the top right)** | | mockup | this PR | |---|---|---| | 1440 light | ![](https://git.kayg.org/attachments/92908d49-5d91-4343-9c2a-a2c27c03d910) | ![](https://git.kayg.org/attachments/2a686b75-3b82-4238-8e98-d871bb7bb071) | | 1440 dark | ![](https://git.kayg.org/attachments/8feb2ea9-b0bb-41d7-9816-bf25ea3470eb) | ![](https://git.kayg.org/attachments/ef0de9ea-5912-4911-b8d1-8e2ab972dab1) | | 390 light | ![](https://git.kayg.org/attachments/288f436c-0aaa-4aa5-b210-6bc01e95ba69) | ![](https://git.kayg.org/attachments/2eb2f48e-a475-42a1-bb67-748d3269e2b9) | | 390 dark | ![](https://git.kayg.org/attachments/28ff9ecc-59ed-4dfc-851c-a4011a156f98) | ![](https://git.kayg.org/attachments/01268eca-107e-4695-b195-390286846003) |
Author
Owner

Merged to dev (head 3d4e16c3e; merge chain 24b3d75db → 0635d3de7 → d4b32af94). Checked by the orchestrator: first paint gate, specs in Chromium and WebKit at 1440/390, typing/open-note ABAB inside the control, 2× crops vs mockup (switcher icons fixed). Matrix view not ported yet (separate follow-up). Ships with the next daily train.

Merged to dev (head 3d4e16c3e; merge chain 24b3d75db → 0635d3de7 → d4b32af94). Checked by the orchestrator: first paint gate, specs in Chromium and WebKit at 1440/390, typing/open-note ABAB inside the control, 2× crops vs mockup (switcher icons fixed). Matrix view not ported yet (separate follow-up). Ships with the next daily train.
kayg closed this pull request 2026-11-09 04:54:49 +00:00
Some checks failed
CI / rust (pull_request) Has been cancelled
CI / server (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!957
No description provided.