port: contacts tidy up and merge (approved mockup, 4/4) #849

Closed
kayg wants to merge 14 commits from port/contacts-merge into port/contacts-edit
Owner

Slice 4 of 4 of the Contacts port. Stacked on #848 (base port/contacts-edit).

What it is

  • Tidy up row under your own card with a count (duplicates, numbers with no country code, names in capitals, empty cards), opening the Tidy up sheet: each item has Fix and Ignore. Ignore is remembered on this device. Every fix says what it did and has Undo: a rewritten note is put back as it was, a deleted card comes out of the Trash (contacts.delete / contacts.restore).
  • Merge sheet: both cards side by side (stacked on a phone), what both say kept once, what only one has kept as it is, and a pick for each fact the two say differently (name, nickname, company, job title, department, pronouns, birthday, Notes). Suggest, never auto-merge: seeing a suggestion changes nothing (a spec reads both notes before and after), Merge is a button, "Not the same person" puts the pair away for good.
  • The merge is pure (merge.ts, tested): the first card keeps its note and id and gets what the second has (same numbers by their last ten digits, same emails, same related person once); related lines pointing at either card are left out; tags are joined; a photo is carried over. The second goes to the Trash, and every note that linked it is rewritten to link the first (notes.backlinks). Undo reverses all of it.
  • Duplicates are found by a shared key, never by comparing every pair (20,000 cards in the unit test stay quick); a number or email shared by more than 12 cards (a switchboard) is not a duplicate.
  • Both sheets are chunks of their own, fetched when first asked for. They are glass sheets like the others in the product (no dim behind, grabber on a phone), not the mockup's dimmed paper panel: the product's sheets have no dim (IN5).

Needs the server (one thing)

The lists read every card's note in batches of fifty with notes.peek (the most it takes), a quiet moment between, and a card again only when its note changed. That is 400 requests for 20,000 cards, in the background. A server list of the few facts a card holds (name, numbers, emails, company, dates, empty?) would make it one request, e.g. contacts.facts over crates/contacts.

Decisions

  • "Add +91" is the mockup's: a ten-digit number is taken to be the home country's (HOME_CODE in logic.ts).
  • Not done: "Merge with…" from a card's ⋯ (you reach the sheet from Tidy up), Email everyone in a List, swipes on rows (Call/Message right; Share/Delete left), Show source, Show Large Type.

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

  • bun run check: 0 errors. bunx vitest run (apps/web): 152 passed (card 35, names 6, people 4, view 14, logic 15, merge 7, ...).
  • contacts-list, contacts-card, contacts-edit, contacts-merge specs: chromium-1440 + chromium-390 on dev-01: 41 passed, 5 skipped. webkit-1440 + webkit-390 on dev-02: 41 passed, 5 skipped. (The skipped are the phone-only / desktop-only cases.)

Bundle (brotli, scripts/bundle-size.mjs; base = dev 55f35fcd)

base stack top
first-paint JS 239.52 KB 239.99 KB (budget 240)
first-paint CSS 20.9 KB 20.9 KB
all JS 311.88 KB 338.91 KB
Contacts chunk (lazy) JS 18.2 KB, CSS 3.4 KB
Tree chunk (lazy, on scroll) JS 3.1 KB, CSS 0.6 KB
Tidy up / Merge / sheets (lazy, on ask) in "all JS"

I did not touch any budget. web.bundle.all_js_brotli (315) cannot be met by this feature as it is counted: "all JS" is every non-plugin chunk, lazy ones included, and the Contacts app is +27 KB of source (about 7,000 lines of approved mockup behaviour, plus the card format code). Splitting into lazy chunks (done: the tree, the sheets, and the whole screen) keeps first paint inside its budget but does not shrink "all". There is no duplicated shared code to remove (checked: the helpers are in the main bundle once). Whether lazy app screens should count in "all" is kayg's call; I have not changed how it is counted.


Budget (per-app gate, PR #866), this stack's tip

perf/web.sh --bundle-only --gate with perf/budgets-per-app merged in (scratch worktree, dev-01): first-paint JS 239.886 KB (≤240), ContactsScreen 13.8 KB (≤14.5), TreeSection 3.05 KB (≤3.25). To keep the screen's own chunk under its allowance the stack loads lazily: the edits (edits), the card's ⋯ menu (cardmenu), the timeline (Timeline), the many-cards rules (logic), and the Tidy up / Merge sheets (TidySheet, MergeSheet, fix).

Chunks with no allowance yet (the gate says "missing named chunk budget"; I have not edited perf/budgets.json): edits 1.42, cardmenu 0.55, Timeline 0.78, logic 1.71, names 0.62 and card 1.10 (shared fragments the bundler makes of modules the screen and a lazy chunk both use), TidySheet 1.31, MergeSheet 2.10, fix 2.19 KB: 11.8 KB in all, which also moves total_js_brotli. #848 needs the first five of those, #849 all nine. They are new code, not a change to an allowance in force; adding them is kayg's call.

Slice 4 of 4 of the Contacts port. **Stacked on #848** (base `port/contacts-edit`). ## What it is - **Tidy up** row under your own card with a count (duplicates, numbers with no country code, names in capitals, empty cards), opening the Tidy up sheet: each item has **Fix** and **Ignore**. Ignore is remembered on this device. Every fix says what it did and has **Undo**: a rewritten note is put back as it was, a deleted card comes out of the Trash (`contacts.delete` / `contacts.restore`). - **Merge sheet**: both cards side by side (stacked on a phone), what both say kept once, what only one has kept as it is, and a pick for each fact the two say differently (name, nickname, company, job title, department, pronouns, birthday, Notes). **Suggest, never auto-merge**: seeing a suggestion changes nothing (a spec reads both notes before and after), Merge is a button, "Not the same person" puts the pair away for good. - The merge is pure (`merge.ts`, tested): the first card keeps its note and id and gets what the second has (same numbers by their last ten digits, same emails, same related person once); related lines pointing at either card are left out; tags are joined; a photo is carried over. The second goes to the Trash, and every note that linked it is rewritten to link the first (`notes.backlinks`). Undo reverses all of it. - **Duplicates** are found by a shared key, never by comparing every pair (20,000 cards in the unit test stay quick); a number or email shared by more than 12 cards (a switchboard) is not a duplicate. - Both sheets are chunks of their own, fetched when first asked for. They are glass sheets like the others in the product (no dim behind, grabber on a phone), not the mockup's dimmed paper panel: the product's sheets have no dim (IN5). ## Needs the server (one thing) The lists read every card's note in batches of fifty with `notes.peek` (the most it takes), a quiet moment between, and a card again only when its note changed. That is 400 requests for 20,000 cards, in the background. **A server list of the few facts a card holds (name, numbers, emails, company, dates, empty?) would make it one request**, e.g. `contacts.facts` over `crates/contacts`. ## Decisions - "Add +91" is the mockup's: a ten-digit number is taken to be the home country's (`HOME_CODE` in `logic.ts`). - Not done: "Merge with…" from a card's ⋯ (you reach the sheet from Tidy up), Email everyone in a List, swipes on rows (Call/Message right; Share/Delete left), Show source, Show Large Type. ## Gates (CI=1 --retries=0, through ~/bin/slot, head `1cd97777`) - `bun run check`: 0 errors. `bunx vitest run` (apps/web): 152 passed (card 35, names 6, people 4, view 14, logic 15, merge 7, ...). - `contacts-list`, `contacts-card`, `contacts-edit`, `contacts-merge` specs: chromium-1440 + chromium-390 on dev-01: 41 passed, 5 skipped. webkit-1440 + webkit-390 on dev-02: 41 passed, 5 skipped. (The skipped are the phone-only / desktop-only cases.) ## Bundle (brotli, `scripts/bundle-size.mjs`; base = dev `55f35fcd`) | | base | stack top | |---|---|---| | first-paint JS | 239.52 KB | 239.99 KB (budget 240) | | first-paint CSS | 20.9 KB | 20.9 KB | | all JS | 311.88 KB | 338.91 KB | | Contacts chunk (lazy) | | JS 18.2 KB, CSS 3.4 KB | | Tree chunk (lazy, on scroll) | | JS 3.1 KB, CSS 0.6 KB | | Tidy up / Merge / sheets (lazy, on ask) | | in "all JS" | I did not touch any budget. **`web.bundle.all_js_brotli` (315) cannot be met by this feature as it is counted**: "all JS" is every non-plugin chunk, lazy ones included, and the Contacts app is +27 KB of source (about 7,000 lines of approved mockup behaviour, plus the card format code). Splitting into lazy chunks (done: the tree, the sheets, and the whole screen) keeps first paint inside its budget but does not shrink "all". There is no duplicated shared code to remove (checked: the helpers are in the main bundle once). Whether lazy app screens should count in "all" is kayg's call; I have not changed how it is counted. --- ## Budget (per-app gate, PR #866), this stack's tip `perf/web.sh --bundle-only --gate` with `perf/budgets-per-app` merged in (scratch worktree, dev-01): first-paint JS **239.886 KB** (≤240), `ContactsScreen` **13.8 KB** (≤14.5), `TreeSection` **3.05 KB** (≤3.25). To keep the screen's own chunk under its allowance the stack loads lazily: the edits (`edits`), the card's ⋯ menu (`cardmenu`), the timeline (`Timeline`), the many-cards rules (`logic`), and the Tidy up / Merge sheets (`TidySheet`, `MergeSheet`, `fix`). **Chunks with no allowance yet** (the gate says "missing named chunk budget"; I have not edited `perf/budgets.json`): `edits` 1.42, `cardmenu` 0.55, `Timeline` 0.78, `logic` 1.71, `names` 0.62 and `card` 1.10 (shared fragments the bundler makes of modules the screen and a lazy chunk both use), `TidySheet` 1.31, `MergeSheet` 2.10, `fix` 2.19 KB: 11.8 KB in all, which also moves `total_js_brotli`. #848 needs the first five of those, #849 all nine. They are new code, not a change to an allowance in force; adding them is kayg's call.
Contacts: Tidy up and Merge (slice 4)
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
1cd977777f
A Tidy up row under your own card (duplicates, numbers with no country code, names in capitals, empty cards), each with Fix and Ignore; a
merge sheet that shows both cards, what is the same and a pick for each fact that differs. Suggest only: nothing merges or changes unless
asked, every fix has Undo (a note put back as it was, a deleted card out of the Trash), and a pair said to be two people stays so. The
merge is pure (merge.ts), written through the normal save, and the cards that linked the second now link the first. Both sheets are
chunks of their own, fetched when first asked for.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Author
Owner

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

restacked contact merge on #848. inherits lazy Contacts icon test update.

head: a8a0d427438a996e02b9570ac7e8a711ad1ae706; 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 230765 B (-12 B), CSS 18386 B (+0 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-849.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 contact merge on #848. inherits lazy Contacts icon test update. head: `a8a0d427438a996e02b9570ac7e8a711ad1ae706`; 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 230765 B (-12 B), CSS 18386 B (+0 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-849.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.

head a8a0d427438a996e02b9570ac7e8a711ad1ae706

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
contacts-merge 4/4 4/4 4/4 4/4

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.

  • Chunks with no budget: card 1.10, cardmenu 0.54, edits 1.42, fix 2.18, logic 1.71, MergeSheet 2.12, names 0.62, TidySheet 1.29, Timeline 0.78 KB.

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.** head `a8a0d427438a996e02b9570ac7e8a711ad1ae706` 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 | |---|---|---|---|---| | contacts-merge | 4/4 | 4/4 | 4/4 | 4/4 | **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. - Chunks with no budget: `card` 1.10, `cardmenu` 0.54, `edits` 1.42, `fix` 2.18, `logic` 1.71, `MergeSheet` 2.12, `names` 0.62, `TidySheet` 1.29, `Timeline` 0.78 KB. **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

Screenshots and state (issue #1009), 023209e582

Contacts (#848 edit fields, #849 Tidy up and Merge; this is the #849 tip), restacked on dev 661123e94. READY FOR MERGE apart from one item: the perf ABAB x5 run (queued behind other lanes). First paint JS vs dev (plain 227125 B): #848 -43 B, #849 -195 B (normalised 226798 B: +105 B and -55 B); CSS +0. Specs: contacts-card, contacts-edit, contacts-list, contacts-merge: 41 passed on WebKit (1440 + 390), 40 passed + 1 flaky on Chromium (contacts-edit:100 passes 6 of 6 when run alone). Bundle gate passes. Budget: the Contacts chunks have their lines at the measured sizes, kayg's approval for them; total 519.6 KiB. Product (Chromium, 2x) next to the approved mockup, then real Safari (1x).

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

card

mockup this PR
1440 light
1440 dark
390 light
390 dark

edit

mockup this PR
1440 light
1440 dark
390 light
390 dark

tidy

mockup this PR
1440 light
1440 dark
390 light
390 dark

merge

mockup this PR
1440 light
1440 dark
390 light
390 dark

Differences from the mockup: initials where the mockup has photos; no Me row, Shared with me or Pinned in the sidebar; the card lacks the camera badge, Last mentioned, the On Calternal pill and the Keep in touch row; the product's Tidy up and Merge sheets are centred where the mockup anchors Tidy to its row and pins the Merge footer; on the phone the edit state has no company and job title group; the backdrop is the product's own.

Real Safari (Mac VM, 1x)

list

light dark
1440
390

card

light dark
1440
390

edit

light dark
1440
390

tidy

light dark
1440
390

merge

light dark
1440
390
**Screenshots and state (issue #1009), 023209e582633048b97f1732c906f8f80c6fe7e1** Contacts (#848 edit fields, #849 Tidy up and Merge; this is the #849 tip), restacked on dev `661123e94`. **READY FOR MERGE apart from one item: the perf ABAB x5 run (queued behind other lanes).** First paint JS vs dev (plain 227125 B): #848 **-43 B**, #849 **-195 B** (normalised 226798 B: +105 B and -55 B); CSS +0. Specs: contacts-card, contacts-edit, contacts-list, contacts-merge: 41 passed on WebKit (1440 + 390), 40 passed + 1 flaky on Chromium (`contacts-edit:100` passes 6 of 6 when run alone). Bundle gate passes. Budget: the Contacts chunks have their lines at the measured sizes, kayg's approval for them; total 519.6 KiB. Product (Chromium, 2x) next to the approved mockup, then real Safari (1x). ### 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/d44b2656-b996-49b5-a3ce-5149b5eb1397) | ![](https://git.kayg.org/attachments/3c81e2b2-5a70-43e8-9739-70e4adb4edc7) | | 1440 dark | ![](https://git.kayg.org/attachments/8a91b6a3-e2a7-46c7-b30d-2e022d4a6083) | ![](https://git.kayg.org/attachments/84b08990-f8cc-4392-aff0-71c6b1d3f2ea) | | 390 light | ![](https://git.kayg.org/attachments/b7df9e78-40ea-47d8-8266-2a6361737ba1) | ![](https://git.kayg.org/attachments/e027341d-55af-4b2d-9fd0-e2fdbb24f43d) | | 390 dark | ![](https://git.kayg.org/attachments/a24fe4b9-856a-491d-89d0-2287991b1cf1) | ![](https://git.kayg.org/attachments/7cd1db7c-1f5a-4033-9266-1711c7df8c73) | **card** | | mockup | this PR | |---|---|---| | 1440 light | ![](https://git.kayg.org/attachments/d0677ab4-9ab3-4023-92bb-36b8075c2160) | ![](https://git.kayg.org/attachments/8b744aee-c6cd-4024-bfe1-f3e0806fd95b) | | 1440 dark | ![](https://git.kayg.org/attachments/0a004e0e-591a-4711-870a-18e46f224fba) | ![](https://git.kayg.org/attachments/50abd0eb-b5d2-44b5-ac0e-b5464ccff269) | | 390 light | ![](https://git.kayg.org/attachments/55a52c6a-869e-45c9-ab5b-b17376cf2165) | ![](https://git.kayg.org/attachments/938502a1-2ee0-4e22-9ae4-9442021dc49b) | | 390 dark | ![](https://git.kayg.org/attachments/063e7211-41f4-4483-976a-79c3d01458ea) | ![](https://git.kayg.org/attachments/d4692c80-1654-4edb-98d9-d3e7952490e7) | **edit** | | mockup | this PR | |---|---|---| | 1440 light | ![](https://git.kayg.org/attachments/bf47bd44-e5a3-4608-8c8b-082a0d707249) | ![](https://git.kayg.org/attachments/52b832fd-0722-4882-9a10-05c7dbfdd486) | | 1440 dark | ![](https://git.kayg.org/attachments/69c9f060-1770-4696-a229-793025aca738) | ![](https://git.kayg.org/attachments/5c386b08-451d-402f-94ac-7b4dae3da526) | | 390 light | ![](https://git.kayg.org/attachments/57da5908-3962-499b-a009-3596d5ada6e8) | ![](https://git.kayg.org/attachments/26805f0c-f70f-4551-9071-f96c21ca5ee2) | | 390 dark | ![](https://git.kayg.org/attachments/cb65b721-eb1c-4e2d-a8b5-25b6aa9f5c6d) | ![](https://git.kayg.org/attachments/dd9dd9ae-5026-492e-9497-f3e76d43be4d) | **tidy** | | mockup | this PR | |---|---|---| | 1440 light | ![](https://git.kayg.org/attachments/b1e29071-0e56-445a-9075-0b2549096cd4) | ![](https://git.kayg.org/attachments/d356338f-d632-4479-8366-adc3d3c78348) | | 1440 dark | ![](https://git.kayg.org/attachments/6e501763-c2e0-4284-b0d4-02ca9ad5ecc4) | ![](https://git.kayg.org/attachments/3f5dbdfd-6e8b-4156-9971-621140605a38) | | 390 light | ![](https://git.kayg.org/attachments/4b2d4f03-e112-4202-96dd-99e7474e911e) | ![](https://git.kayg.org/attachments/a3331482-e7ea-4c0c-a788-6296bec9180f) | | 390 dark | ![](https://git.kayg.org/attachments/ef1a7142-5090-4af3-a7a5-ce6678dda1b6) | ![](https://git.kayg.org/attachments/17df4175-2f7d-45a0-bdcc-8a782851730b) | **merge** | | mockup | this PR | |---|---|---| | 1440 light | ![](https://git.kayg.org/attachments/c751eb8e-7dcb-4465-af58-bb6073934b82) | ![](https://git.kayg.org/attachments/7ae76269-9dfc-499d-a7a2-4661d1777388) | | 1440 dark | ![](https://git.kayg.org/attachments/a0a82781-e214-45ff-a2f4-94a7b35a3126) | ![](https://git.kayg.org/attachments/c037e92b-bf08-4a99-aa4d-e01234967f70) | | 390 light | ![](https://git.kayg.org/attachments/3ff38108-6e46-4f29-8e6f-68c07a7c5fe2) | ![](https://git.kayg.org/attachments/976fe277-5e18-4fa1-8cb6-14bc8bb41964) | | 390 dark | ![](https://git.kayg.org/attachments/e06af6e3-4a12-4214-a72d-5abc9cc5d952) | ![](https://git.kayg.org/attachments/e7cc2d74-8188-49a7-9257-5caa84879f9b) | Differences from the mockup: initials where the mockup has photos; no Me row, Shared with me or Pinned in the sidebar; the card lacks the camera badge, Last mentioned, the On Calternal pill and the Keep in touch row; the product's Tidy up and Merge sheets are centred where the mockup anchors Tidy to its row and pins the Merge footer; on the phone the edit state has no company and job title group; the backdrop is the product's own. ### Real Safari (Mac VM, 1x) **list** | | light | dark | |---|---|---| | 1440 | ![](https://git.kayg.org/attachments/8a371b80-78c9-4a8f-9bcf-d3d5a3d73f31) | ![](https://git.kayg.org/attachments/9fcaeaa2-4219-4f2f-a191-0f4948ca286e) | | 390 | ![](https://git.kayg.org/attachments/96b28025-8ee9-4793-b0d7-eb959f53e2c1) | ![](https://git.kayg.org/attachments/424e5e7e-00af-4317-92c1-f7ad79c5a234) | **card** | | light | dark | |---|---|---| | 1440 | ![](https://git.kayg.org/attachments/9fdf4d79-bff0-4a3f-98b4-66adb4ac6423) | ![](https://git.kayg.org/attachments/099ab8f6-61f0-479b-9f1e-91ae80432700) | | 390 | ![](https://git.kayg.org/attachments/09884221-1ec7-4994-90e2-b13692e5fa0e) | ![](https://git.kayg.org/attachments/f58e3559-5baf-4fd1-9f93-14c00f8be240) | **edit** | | light | dark | |---|---|---| | 1440 | ![](https://git.kayg.org/attachments/57fa4b53-bc9d-4d7f-a41d-bbc16edcc9c9) | ![](https://git.kayg.org/attachments/d45f14b0-72a9-47db-b43d-c1741b658dc3) | | 390 | ![](https://git.kayg.org/attachments/e8ef1ba0-7139-4891-b9dc-d469ae916660) | ![](https://git.kayg.org/attachments/3c6ba228-3ab4-438a-97d2-edb3b00ec3f3) | **tidy** | | light | dark | |---|---|---| | 1440 | ![](https://git.kayg.org/attachments/828e38d1-ab2f-44b0-9c07-0b92848f9c09) | ![](https://git.kayg.org/attachments/f693fcb4-5f95-43f1-a1da-f42492271783) | | 390 | ![](https://git.kayg.org/attachments/670aecd4-2119-4861-beb8-5ca132d85536) | ![](https://git.kayg.org/attachments/17f841bb-6e2a-4d9c-846b-e2275ee8ab10) | **merge** | | light | dark | |---|---|---| | 1440 | ![](https://git.kayg.org/attachments/e8f364a3-b465-4c7b-b47d-48dcce66b272) | ![](https://git.kayg.org/attachments/cf229db7-97c2-471d-ba38-7340dafb1f38) | | 390 | ![](https://git.kayg.org/attachments/210aabc4-b4ca-4c9d-91ab-6808764c8ae7) | ![](https://git.kayg.org/attachments/642c40c6-f6b4-4eb5-851c-45af4d3cd7b4) |
Author
Owner

READY FOR MERGE: Contacts Tidy up and Merge (head 1a85e1944, on #848)

Rebased on dev 3f079de39 (#909, #1025, #1029 in). The old icons test commit is gone: dev's icon test already reads every screen's own icons.ts, so Contacts' icons are covered. Budget lines regenerated from a fresh build, at measured size (kayg's Contacts ceiling), total = sum of the lines.

check dev 3f079de39 this PR (#848 + #849)
first paint, plain brotli 227240 B 227051 B (−189 B)
first paint, normalised 226769 B 226652 B (−117 B)
budget total 506.34 KiB 519.12 KiB (≤ 543.9)
bundle gate passes

Specs: 163 passed, 11 failed, 26 skipped: dev's 10 (glass:76, lazy-ui:70, preload:89 at 390) plus lazy-offline:3 at chromium-390, which also fails on dev intermittently (reruns on dev: fail, fail; here pass/fail). All contacts specs pass in all four projects.

Perf (5 interleaved rounds against a dev-vs-dev control): blaze.shown p50 37.3 / p95 65.1 against dev 36.2 / 64.7 and control 36.0 / 65.7; type.long_note 23.3 / 54.8 against 21.9 / 55.5; nested_list 42.4 / 51.0 against 42.1 / 51.0; blaze.cpu 75.8 against 76.8. Nothing beyond the control's own noise. Full table on #1022: #1022 (comment)

## READY FOR MERGE: Contacts Tidy up and Merge (head `1a85e1944`, on #848) Rebased on dev `3f079de39` (#909, #1025, #1029 in). The old icons test commit is gone: dev's icon test already reads every screen's own `icons.ts`, so Contacts' icons are covered. Budget lines regenerated from a fresh build, at measured size (kayg's Contacts ceiling), total = sum of the lines. | check | dev `3f079de39` | this PR (#848 + #849) | |---|---|---| | first paint, plain brotli | 227240 B | 227051 B (−189 B) | | first paint, normalised | 226769 B | 226652 B (−117 B) | | budget total | 506.34 KiB | 519.12 KiB (≤ 543.9) | | bundle gate | | passes | Specs: 163 passed, 11 failed, 26 skipped: dev's 10 (glass:76, lazy-ui:70, preload:89 at 390) plus `lazy-offline:3` at chromium-390, which also fails on dev intermittently (reruns on dev: fail, fail; here pass/fail). All contacts specs pass in all four projects. **Perf** (5 interleaved rounds against a dev-vs-dev control): blaze.shown p50 37.3 / p95 65.1 against dev 36.2 / 64.7 and control 36.0 / 65.7; type.long_note 23.3 / 54.8 against 21.9 / 55.5; nested_list 42.4 / 51.0 against 42.1 / 51.0; blaze.cpu 75.8 against 76.8. Nothing beyond the control's own noise. Full table on #1022: https://git.kayg.org/kayg/calternal/pulls/1022#issuecomment-88950
Author
Owner

READY FOR MERGE: Contacts Tidy up and Merge (head 4d95b20b5, on #848)

Rebased on dev 5a4e2dd0f (#1022 in); it also merges cleanly with 7c50123c3 (#1042; git merge-tree, no conflicts). My old per-stack budget commit conflicted on perf/budgets.json, so it is regenerated: only the Contacts lines and what they moved changed, every other line is dev's own. Builds, gate and specs ran on dev-02 (idle host; builds are deterministic, the dev baseline measured there equals dev-01's byte for byte).

check dev 5a4e2dd0f #848 + #849
first paint, plain brotli 227848 B 227531 B (−317 B)
first paint, hash-normalised 227107 B 227081 B (−26 B)
first-screen CSS 18234 B 18234 B
budget total 525.01 KiB 537.55 KiB (≤ 543.9): adds MergeSheet 2.15, TidySheet 1.33, card 1.13, fix 2.23; edits 1.46
bundle gate passes

Specs (same set, four projects): 194 passed, 46 skipped, 0 failed. Perf was run on the previous heads, the code is unchanged: #1022 (comment)

## READY FOR MERGE: Contacts Tidy up and Merge (head `4d95b20b5`, on #848) Rebased on dev `5a4e2dd0f` (#1022 in); it also merges cleanly with `7c50123c3` (#1042; `git merge-tree`, no conflicts). My old per-stack budget commit conflicted on `perf/budgets.json`, so it is regenerated: only the Contacts lines and what they moved changed, every other line is dev's own. Builds, gate and specs ran on dev-02 (idle host; builds are deterministic, the dev baseline measured there equals dev-01's byte for byte). | check | dev `5a4e2dd0f` | #848 + #849 | |---|---|---| | first paint, plain brotli | 227848 B | 227531 B (−317 B) | | first paint, hash-normalised | 227107 B | 227081 B (−26 B) | | first-screen CSS | 18234 B | 18234 B | | budget total | 525.01 KiB | 537.55 KiB (≤ 543.9): adds MergeSheet 2.15, TidySheet 1.33, card 1.13, fix 2.23; edits 1.46 | | bundle gate | | passes | Specs (same set, four projects): **194 passed, 46 skipped, 0 failed**. Perf was run on the previous heads, the code is unchanged: https://git.kayg.org/kayg/calternal/pulls/1022#issuecomment-88950
Author
Owner

Merged into dev at 9438918f3; closing.

Merged into dev at `9438918f3`; closing.
kayg closed this pull request 2026-11-09 19:53:03 +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!849
No description provided.