Search palette: rows show through the footer; preview meta misaligned #1137

Open
opened 2026-10-05 11:40:29 +00:00 by kayg · 32 comments
Owner

Found in review of #1123 (2026-10-05)

  1. Footer bleed: artifacts/issue-1123/search-1123-footer-clearance-4x.png (worktree palette2-1123): list rows ("5 PM", "6 PM" day rows) scroll under the action footer (Open / See all / Actions) and stay crisp and fully visible beside and behind the footer pills. Rows must fade and blur progressively into the footer edge, the same scroll-edge treatment as the top edge (#1123), with no row text visible at the footer baseline.
  2. Preview header alignment: search-1123-empty-1440-mono.png: in the right preview pane the date line ("Sep 29, 2026") starts at the icon column while "From Morgan Lee" starts at the title column. All meta lines align to the title column; the icon is vertically centred on the title's first line.

Evidence: 4x crops of footer edge mid-scroll and the preview header, light + dark, 1440 and 820.

## Found in review of #1123 (2026-10-05) 1. **Footer bleed:** artifacts/issue-1123/search-1123-footer-clearance-4x.png (worktree palette2-1123): list rows ("5 PM", "6 PM" day rows) scroll under the action footer (Open / See all / Actions) and stay crisp and fully visible beside and behind the footer pills. Rows must fade and blur progressively into the footer edge, the same scroll-edge treatment as the top edge (#1123), with no row text visible at the footer baseline. 2. **Preview header alignment:** search-1123-empty-1440-mono.png: in the right preview pane the date line ("Sep 29, 2026") starts at the icon column while "From Morgan Lee" starts at the title column. All meta lines align to the title column; the icon is vertically centred on the title's first line. Evidence: 4x crops of footer edge mid-scroll and the preview header, light + dark, 1440 and 820.
Author
Owner

Owner (2026-10-05): "please look out for misalignments". Orchestrator audit of the owner's production palette screenshot (pre-#1123 build) — fix every item still present after #1123, with a 4x crop per item:

  1. Label column: Mail and Journal rows start their title at a different x than Settings/Navigate rows (8 px apart). One label column for every row kind regardless of icon glyph width (fixed icon box).
  2. Trailing date column mixes formats in one list: "Wed, 2026 Sep 30" vs "Mon, Sep 28, 2026". One shared short date format (locale-aware), right-aligned on one edge.
  3. Preview header: the leading icon sits above the title's optical centre (icon top-aligned, title baseline lower). Centre the icon on the title's first line; meta lines align to the title column (see item 2 of this issue).
  4. Footer: the action pills overlap the last visible list row, and the next row shows cut off below them. The list ends above the footer (reserve its height as scroll padding) and rows fade/blur under it.
  5. Settings-type results (Analytics) show an empty preview pane with only a title. Show a one-line description of the destination, or no preview pane for pure navigation results — follow the shared preview rules, no placeholder.

Add an e2e geometry check: across all visible rows, the icon box left, label left and trailing-meta right edges are equal within 1 px.

Owner (2026-10-05): "please look out for misalignments". Orchestrator audit of the owner's production palette screenshot (pre-#1123 build) — fix every item still present after #1123, with a 4x crop per item: 1. Label column: Mail and Journal rows start their title at a different x than Settings/Navigate rows (8 px apart). One label column for every row kind regardless of icon glyph width (fixed icon box). 2. Trailing date column mixes formats in one list: "Wed, 2026 Sep 30" vs "Mon, Sep 28, 2026". One shared short date format (locale-aware), right-aligned on one edge. 3. Preview header: the leading icon sits above the title's optical centre (icon top-aligned, title baseline lower). Centre the icon on the title's first line; meta lines align to the title column (see item 2 of this issue). 4. Footer: the action pills overlap the last visible list row, and the next row shows cut off below them. The list ends above the footer (reserve its height as scroll padding) and rows fade/blur under it. 5. Settings-type results (Analytics) show an empty preview pane with only a title. Show a one-line description of the destination, or no preview pane for pure navigation results — follow the shared preview rules, no placeholder. Add an e2e geometry check: across all visible rows, the icon box left, label left and trailing-meta right edges are equal within 1 px.
Author
Owner

Owner report (2026-10-05, production, desktop): "when search is open there's some sort of border on the right side"

With the palette open on /files (wide desktop window), a vertical seam runs the full window height ~40 CSS px from the right edge: the strip to its right is blurred/tinted differently from the rest of the backdrop (owner crop: scratchpad palette-right-band.webp; full window shows the same). Likely the palette scrim/backdrop does not cover the full viewport (100% vs 100vw, a scrollbar gutter, scrollbar-gutter: stable, or the scrim sized to the route column instead of the window), or an element's edge (frame border, header end) shows through the blur.

Expected: one uniform scrim + blur across the whole viewport edge to edge, no seam, at every width, with and without a scrollbar on the page beneath. Find the element at the seam with document.elementsFromPoint in a real production build and fix it at the source. e2e: sample pixel columns across the right 80 px of the window with the palette open and assert no step in luminance at a single column. Screenshots 1440 and 1920, light + dark, plus a 4x crop of the right edge.

## Owner report (2026-10-05, production, desktop): "when search is open there's some sort of border on the right side" With the palette open on /files (wide desktop window), a vertical seam runs the full window height ~40 CSS px from the right edge: the strip to its right is blurred/tinted differently from the rest of the backdrop (owner crop: scratchpad palette-right-band.webp; full window shows the same). Likely the palette scrim/backdrop does not cover the full viewport (100% vs 100vw, a scrollbar gutter, `scrollbar-gutter: stable`, or the scrim sized to the route column instead of the window), or an element's edge (frame border, header end) shows through the blur. Expected: one uniform scrim + blur across the whole viewport edge to edge, no seam, at every width, with and without a scrollbar on the page beneath. Find the element at the seam with document.elementsFromPoint in a real production build and fix it at the source. e2e: sample pixel columns across the right 80 px of the window with the palette open and assert no step in luminance at a single column. Screenshots 1440 and 1920, light + dark, plus a 4x crop of the right edge.
Author
Owner

Owner report (2026-10-05): top scroll-edge blur starts in the wrong place

"The progressive blur should start under RECENT since it's the immediate next header. The blur starts under the search input field and the results section border right now." (crop: scratchpad palette-blur-start.png: a scrolled row, "webtropia.com – Your invoice…", is blurred BEHIND and beside the sticky "RECENT 5" header.)

Expected: the sticky section header (RECENT, NAVIGATE, NOTES …) is the top edge of the scroll area. Rows stay sharp until they reach the header's bottom edge, then blur/fade progressively over a short band under it; no row text is visible behind or beside the header itself (the header has the panel's own surface behind it). When the next section header pushes the previous one out, the band follows the active header. Keep the band height a token.

## Owner report (2026-10-05): top scroll-edge blur starts in the wrong place "The progressive blur should start under RECENT since it's the immediate next header. The blur starts under the search input field and the results section border right now." (crop: scratchpad palette-blur-start.png: a scrolled row, "webtropia.com – Your invoice…", is blurred BEHIND and beside the sticky "RECENT 5" header.) Expected: the sticky section header (RECENT, NAVIGATE, NOTES …) is the top edge of the scroll area. Rows stay sharp until they reach the header's bottom edge, then blur/fade progressively over a short band under it; no row text is visible behind or beside the header itself (the header has the panel's own surface behind it). When the next section header pushes the previous one out, the band follows the active header. Keep the band height a token.
Author
Owner

Owner reports (2026-10-05)

  1. Mail preview must render the email as-is (scratchpad palette-mail-preview.png): the palette preview shows a newsletter as plain text with raw tracking URLs in brackets and a line of "****". Render the message the way the Mail reader does (sanitised HTML through the same reader component/proxy, images via the image proxy, links as links, no raw URLs), scaled to the pane. Also fix the header: the mail icon sits above the title line, "From …" is indented under the title but the date "Sep 30, 2026" starts at the far left edge. Icon centred on the title's first line; From and date on the title column.
  2. Focus ring clips the list (palette-days-focus.webp): a purple keyboard-focus outline is drawn around the whole results list and its bottom edge cuts across the last row ("Thursday, 2025 May 15") just above the footer; the right edge runs through the row area. Focus is shown on the active row only (the shared row highlight), not as an outline on the scroll container; nothing draws across rows.
  3. Day result titles read "Saturday, 2025 May 10": same odd year-first long format as #1139. Use the shared locale date formatter everywhere in the palette (rows, preview, meta).
  4. The selected row highlight extends further left than the row icons' column offset used by other rows; align highlight insets with the list's edges (one inset token both sides).
## Owner reports (2026-10-05) 1. **Mail preview must render the email as-is** (scratchpad palette-mail-preview.png): the palette preview shows a newsletter as plain text with raw tracking URLs in brackets and a line of "****". Render the message the way the Mail reader does (sanitised HTML through the same reader component/proxy, images via the image proxy, links as links, no raw URLs), scaled to the pane. Also fix the header: the mail icon sits above the title line, "From …" is indented under the title but the date "Sep 30, 2026" starts at the far left edge. Icon centred on the title's first line; From and date on the title column. 2. **Focus ring clips the list** (palette-days-focus.webp): a purple keyboard-focus outline is drawn around the whole results list and its bottom edge cuts across the last row ("Thursday, 2025 May 15") just above the footer; the right edge runs through the row area. Focus is shown on the active row only (the shared row highlight), not as an outline on the scroll container; nothing draws across rows. 3. **Day result titles read "Saturday, 2025 May 10"**: same odd year-first long format as #1139. Use the shared locale date formatter everywhere in the palette (rows, preview, meta). 4. The selected row highlight extends further left than the row icons' column offset used by other rows; align highlight insets with the list's edges (one inset token both sides).
Author
Owner

Starting #1137 on branch job/palfoot-1137, based at 54c658489d306cf2d1528929dbada088b245a02f (origin/dev is 35 commits ahead; I will merge it once before final gates). I am tracing the shared search palette, row geometry, preview container and glass backdrop before editing so the fixes stay in their shared owners.

Starting #1137 on branch `job/palfoot-1137`, based at `54c658489d306cf2d1528929dbada088b245a02f` (origin/dev is 35 commits ahead; I will merge it once before final gates). I am tracing the shared search palette, row geometry, preview container and glass backdrop before editing so the fixes stay in their shared owners.
Author
Owner

Finding: Search reused formatLongDate, but numeric date preferences also forced a year-first month-name display. The result was labels such as “Monday, 2026 September 28” even when the User locale expects “Monday, 28 September 2026” or “Monday, September 28, 2026”. Commit 6e108f862 adds a locale-order option for long dates and applies it to Search rows and previews.

Focused verification passed:

Test Files  2 passed (2)
      Tests  42 passed (42)
   Start at  14:59:55
   Duration  41.54s (transform 86%, tests 5%, import 4%, environment 3%, setup 1%)

  Transform  |component| transforming modules took 33.36s · 81% of tracked time, re-done on every run
             persist transforms across runs with fsModuleCache: true
             learn more: https://vitest.dev/guide/improving-performance#caching-between-reruns
Finding: Search reused `formatLongDate`, but numeric date preferences also forced a year-first month-name display. The result was labels such as “Monday, 2026 September 28” even when the User locale expects “Monday, 28 September 2026” or “Monday, September 28, 2026”. Commit `6e108f862` adds a locale-order option for long dates and applies it to Search rows and previews. Focused verification passed: ``` Test Files 2 passed (2) Tests 42 passed (42) Start at 14:59:55 Duration 41.54s (transform 86%, tests 5%, import 4%, environment 3%, setup 1%) Transform |component| transforming modules took 33.36s · 81% of tracked time, re-done on every run persist transforms across runs with fsModuleCache: true learn more: https://vitest.dev/guide/improving-performance#caching-between-reruns ```
Author
Owner

Finding: bun run check from apps/web stops before Svelte validation because the existing origin/dev performance exception ledger is larger than its ratchet: contracts/perf/exceptions.json has 21,977 entries while contracts/perf/ratchet.json allows 21,964. Thirteen rule ceilings are each exceeded by one. Neither file is changed in this job. I will run the TypeScript/Svelte checker and focused tests separately and report this gate result for merge-round reconciliation.

Exact output:

perf-lint: INVALID: exception ratchet: contract.blaze: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; contract.blocked-network: 356 exceptions exceed the ratchet ceiling 355; fix the new violation instead; contract.dom-bound: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; contract.model-bound: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; contract.row-identity: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; contract.snapshot: 356 exceptions exceed the ratchet ceiling 355; fix the new violation instead; coverage.profile: 356 exceptions exceed the ratchet ceiling 355; fix the new violation instead; coverage.readiness: 356 exceptions exceed the ratchet ceiling 355; fix the new violation instead; io.unresolved-call: 16191 exceptions exceed the ratchet ceiling 16190; fix the new violation instead; render.blaze-adapter: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; render.bound: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; render.model_byte_cap: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; render.model_row_cap: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; total: ledger has 21977 exceptions; ratchet total is 21964
Finding: `bun run check` from `apps/web` stops before Svelte validation because the existing `origin/dev` performance exception ledger is larger than its ratchet: `contracts/perf/exceptions.json` has 21,977 entries while `contracts/perf/ratchet.json` allows 21,964. Thirteen rule ceilings are each exceeded by one. Neither file is changed in this job. I will run the TypeScript/Svelte checker and focused tests separately and report this gate result for merge-round reconciliation. Exact output: ``` perf-lint: INVALID: exception ratchet: contract.blaze: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; contract.blocked-network: 356 exceptions exceed the ratchet ceiling 355; fix the new violation instead; contract.dom-bound: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; contract.model-bound: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; contract.row-identity: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; contract.snapshot: 356 exceptions exceed the ratchet ceiling 355; fix the new violation instead; coverage.profile: 356 exceptions exceed the ratchet ceiling 355; fix the new violation instead; coverage.readiness: 356 exceptions exceed the ratchet ceiling 355; fix the new violation instead; io.unresolved-call: 16191 exceptions exceed the ratchet ceiling 16190; fix the new violation instead; render.blaze-adapter: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; render.bound: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; render.model_byte_cap: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; render.model_row_cap: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; total: ledger has 21977 exceptions; ratchet total is 21964 ```
Author
Owner

Production e2e finding: assertMailPreviewReader rendered the expected Mail body text but found no data-mail-link in the inert frame and no parent-owned safe link. The shared fixture inserted raw body_html with empty body_links_json instead of the sanitized projection returned after the Mail worker. I kept the hostile source intact for sanitizer probes and seeded the safe sanitized body/link projection for the Search preview. Focused production e2e is rerunning.

Production e2e finding: `assertMailPreviewReader` rendered the expected Mail body text but found no `data-mail-link` in the inert frame and no parent-owned safe link. The shared fixture inserted raw `body_html` with empty `body_links_json` instead of the sanitized projection returned after the Mail worker. I kept the hostile source intact for sanitizer probes and seeded the safe sanitized body/link projection for the Search preview. Focused production e2e is rerunning.
Author
Owner

Built

  • Fixed the Search palette's shared row columns, locale-ordered dates, active-row highlight inset, and list-wide focus outline.
  • Added a sticky heading surface with a top fade, reserved scroll clearance and progressive blur above the action footer, and a real viewport-wide scrim seam probe.
  • Unified preview insets. Mail now uses the shared sanitized HTML reader and safe link controls. Preview metadata aligns under the title; preview icons center on its first line. Calendar time ranges stay together and dates follow the User's locale.
  • Added Analytics destination text and the indexed Note fixture wait used by the production review.

UX gaps closed

Rows no longer scroll crisply through the footer, sticky headings cover rows behind them, and keyboard focus no longer outlines the whole result list. Icon, label, metadata and selection columns share stable edges. Mail previews show the sanitized message, sender and date in the shared header column. Note, Mail, Journal, Event and Task previews use the same inset. Calendar ranges stay on one line unit.

Files

  • apps/web/src/lib/components/search-dialog.svelte, apps/web/src/lib/search/SearchGroupHeading.svelte, apps/web/src/lib/search/SearchResultRow.svelte, apps/web/src/lib/search/SearchPreview.svelte, apps/web/src/lib/search/server.ts, apps/web/src/lib/search/providers.ts
  • apps/web/src/calternal-app.css, packages/ui/src/tokens.css, packages/ui/src/time.ts, packages/ui/src/components/calendar/ItemPreview.svelte
  • apps/web/src/lib/time.test.ts, apps/web/src/lib/calendar/ItemPreview.svelte.test.ts, apps/web/e2e/search.mjs, tests/adversarial/mail_screenshot_fixture.py, docs/DESIGN.md

Evidence

Production macOS review set: 84 PNGs, including 4× edge, inset and scrim crops

Head and commits

Head: c01abaef8550aa46c5efd3062006530b07b46e25

Commits: 6e108f862, b866734c0, 51f708eed, 1494d41b9, 545792006, 7ba2b127c, c01abaef8.

Verification

Focused production e2e (run from apps/web):

SEARCH_E2E_1123_ONLY=1 SEARCH_E2E_MACOS=1 SEARCH_E2E_REVIEW_ONLY=1 CALTERNAL_SERVER_BIN=/home/kayg/build/targets/palfoot-1137/debug/calternal-server bun e2e/search.mjs --screenshots ../../artifacts/issue-1137
PASS #1137/#1139 native 4x sticky, footer, preview and scrim crops at required widths and themes
PASS #1123 rows, no query ring, Recent icons, Mail/Note previews and footer at 1440px/820px/390px in mono/noir/tokyo-night; #1137/#1139 edge and preview evidence captured
CSP REPORTS search: 0 across 4 pages

Focused Vitest:

Test Files  3 passed (3)
      Tests  27 passed (27)
   Start at  17:11:15
   Duration  13.24s (transform 72%, environment 11%, import 8%, tests 6%, setup 3%)

  Transform  |component| transforming modules took 18.21s · 72% of tracked time, re-done on every run
             persist transforms across runs with fsModuleCache: true
             learn more: https://vitest.dev/guide/improving-performance#caching-between-reruns

Direct Svelte diagnostics:

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

bun run check stopped before Svelte diagnostics because the perf-lint exception ratchet is already over its checked-in ceiling:

$ ../../scripts/perf-lint --check && node scripts/check-user-storage.mjs && node scripts/check-glass-tokens.mjs && node scripts/check-type-tokens.mjs && node scripts/check-focus-tokens.mjs && node scripts/check-motion-tokens.mjs && svelte-kit sync && svelte-check --tsconfig ./tsconfig.json
perf-lint: INVALID: exception ratchet: contract.blaze: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; contract.blocked-network: 356 exceptions exceed the ratchet ceiling 355; fix the new violation instead; contract.dom-bound: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; contract.model-bound: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; contract.row-identity: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; contract.snapshot: 356 exceptions exceed the ratchet ceiling 355; fix the new violation instead; coverage.profile: 356 exceptions exceed the ratchet ceiling 355; fix the new violation instead; coverage.readiness: 356 exceptions exceed the ratchet ceiling 355; fix the new violation instead; io.unresolved-call: 16191 exceptions exceed the ratchet ceiling 16190; fix the new violation instead; render.blaze-adapter: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; render.bound: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; render.model_byte_cap: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; render.model_row_cap: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; total: ledger has 21977 exceptions; ratchet total is 21964

No Rust code changed, so Rust fmt, clippy and test gates were not run. Cleanup output:

Removed 8626 files, 7.2GiB total

Known gaps

No user-visible UX gaps remain from the reports. The repository bun run check gate remains blocked by the exception ratchet above. The full web suite and full Search e2e remain for the merge round.

Decisions

The Search split preview starts at 768 px so the required 820 px tablet view includes its real preview. I recorded this threshold in docs/DESIGN.md §32 and the UI comment.

For the merge round

  • From apps/web, run bun run test to verify the combined full web test suite.
  • From apps/web, run bun run test:e2e:search to verify the complete Search flows beyond this focused production review.
  • Run the full application e2e gate bun run test:e2e on the merged branch.
## Built - Fixed the Search palette's shared row columns, locale-ordered dates, active-row highlight inset, and list-wide focus outline. - Added a sticky heading surface with a top fade, reserved scroll clearance and progressive blur above the action footer, and a real viewport-wide scrim seam probe. - Unified preview insets. Mail now uses the shared sanitized HTML reader and safe link controls. Preview metadata aligns under the title; preview icons center on its first line. Calendar time ranges stay together and dates follow the User's locale. - Added Analytics destination text and the indexed Note fixture wait used by the production review. ## UX gaps closed Rows no longer scroll crisply through the footer, sticky headings cover rows behind them, and keyboard focus no longer outlines the whole result list. Icon, label, metadata and selection columns share stable edges. Mail previews show the sanitized message, sender and date in the shared header column. Note, Mail, Journal, Event and Task previews use the same inset. Calendar ranges stay on one line unit. ## Files - `apps/web/src/lib/components/search-dialog.svelte`, `apps/web/src/lib/search/SearchGroupHeading.svelte`, `apps/web/src/lib/search/SearchResultRow.svelte`, `apps/web/src/lib/search/SearchPreview.svelte`, `apps/web/src/lib/search/server.ts`, `apps/web/src/lib/search/providers.ts` - `apps/web/src/calternal-app.css`, `packages/ui/src/tokens.css`, `packages/ui/src/time.ts`, `packages/ui/src/components/calendar/ItemPreview.svelte` - `apps/web/src/lib/time.test.ts`, `apps/web/src/lib/calendar/ItemPreview.svelte.test.ts`, `apps/web/e2e/search.mjs`, `tests/adversarial/mail_screenshot_fixture.py`, `docs/DESIGN.md` ## Evidence [Production macOS review set: 84 PNGs, including 4× edge, inset and scrim crops](https://git.kayg.org/attachments/9b57ad77-22ce-4c5e-afa5-668a111fb3d9) ## Head and commits Head: `c01abaef8550aa46c5efd3062006530b07b46e25` Commits: `6e108f862`, `b866734c0`, `51f708eed`, `1494d41b9`, `545792006`, `7ba2b127c`, `c01abaef8`. ## Verification Focused production e2e (run from `apps/web`): ```text SEARCH_E2E_1123_ONLY=1 SEARCH_E2E_MACOS=1 SEARCH_E2E_REVIEW_ONLY=1 CALTERNAL_SERVER_BIN=/home/kayg/build/targets/palfoot-1137/debug/calternal-server bun e2e/search.mjs --screenshots ../../artifacts/issue-1137 PASS #1137/#1139 native 4x sticky, footer, preview and scrim crops at required widths and themes PASS #1123 rows, no query ring, Recent icons, Mail/Note previews and footer at 1440px/820px/390px in mono/noir/tokyo-night; #1137/#1139 edge and preview evidence captured CSP REPORTS search: 0 across 4 pages ``` Focused Vitest: ```text Test Files 3 passed (3) Tests 27 passed (27) Start at 17:11:15 Duration 13.24s (transform 72%, environment 11%, import 8%, tests 6%, setup 3%) Transform |component| transforming modules took 18.21s · 72% of tracked time, re-done on every run persist transforms across runs with fsModuleCache: true learn more: https://vitest.dev/guide/improving-performance#caching-between-reruns ``` Direct Svelte diagnostics: ```text svelte-check found 0 errors and 4 warnings in 3 files ``` `bun run check` stopped before Svelte diagnostics because the perf-lint exception ratchet is already over its checked-in ceiling: ```text $ ../../scripts/perf-lint --check && node scripts/check-user-storage.mjs && node scripts/check-glass-tokens.mjs && node scripts/check-type-tokens.mjs && node scripts/check-focus-tokens.mjs && node scripts/check-motion-tokens.mjs && svelte-kit sync && svelte-check --tsconfig ./tsconfig.json perf-lint: INVALID: exception ratchet: contract.blaze: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; contract.blocked-network: 356 exceptions exceed the ratchet ceiling 355; fix the new violation instead; contract.dom-bound: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; contract.model-bound: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; contract.row-identity: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; contract.snapshot: 356 exceptions exceed the ratchet ceiling 355; fix the new violation instead; coverage.profile: 356 exceptions exceed the ratchet ceiling 355; fix the new violation instead; coverage.readiness: 356 exceptions exceed the ratchet ceiling 355; fix the new violation instead; io.unresolved-call: 16191 exceptions exceed the ratchet ceiling 16190; fix the new violation instead; render.blaze-adapter: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; render.bound: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; render.model_byte_cap: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; render.model_row_cap: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; total: ledger has 21977 exceptions; ratchet total is 21964 ``` No Rust code changed, so Rust fmt, clippy and test gates were not run. Cleanup output: ```text Removed 8626 files, 7.2GiB total ``` ## Known gaps No user-visible UX gaps remain from the reports. The repository `bun run check` gate remains blocked by the exception ratchet above. The full web suite and full Search e2e remain for the merge round. ## Decisions The Search split preview starts at 768 px so the required 820 px tablet view includes its real preview. I recorded this threshold in `docs/DESIGN.md` §32 and the UI comment. ## For the merge round - From `apps/web`, run `bun run test` to verify the combined full web test suite. - From `apps/web`, run `bun run test:e2e:search` to verify the complete Search flows beyond this focused production review. - Run the full application e2e gate `bun run test:e2e` on the merged branch.
Author
Owner

Starting #1137/#1139 merge-and-polish on job/palfoot-1137. Initial job head: c01abaef8550aa46c5efd3062006530b07b46e25; base before the required merge: 04afb0043c559c59084e4ec12609bb9fe679cbf6. I will merge origin/dev, keep the MIME glyph and aligned search-row behavior, then fix the preview date/time grouping and footer fade before the requested E2E and screenshot checks.

Starting #1137/#1139 merge-and-polish on `job/palfoot-1137`. Initial job head: `c01abaef8550aa46c5efd3062006530b07b46e25`; base before the required merge: `04afb0043c559c59084e4ec12609bb9fe679cbf6`. I will merge `origin/dev`, keep the MIME glyph and aligned search-row behavior, then fix the preview date/time grouping and footer fade before the requested E2E and screenshot checks.
Author
Owner

Finding while merging #1137/#1139: bun run check stops at perf-lint --check before Svelte validation. The gate reports 21,977 entries in contracts/perf/exceptions.json against a ratchet total of 21,964; 13 per-rule ceilings are short by one. I compared the pre-merge job head and origin/dev: both already have this same ledger/ratchet mismatch, so it predates this merge and this polish change. I did not raise the ratchet. I will run the remaining web validation directly and include the gate output in the final report.

Finding while merging #1137/#1139: `bun run check` stops at `perf-lint --check` before Svelte validation. The gate reports 21,977 entries in `contracts/perf/exceptions.json` against a ratchet total of 21,964; 13 per-rule ceilings are short by one. I compared the pre-merge job head and `origin/dev`: both already have this same ledger/ratchet mismatch, so it predates this merge and this polish change. I did not raise the ratchet. I will run the remaining web validation directly and include the gate output in the final report.
Author
Owner

Finding in the required bun run test:e2e:search: the budget preview reaches the two-row layout assertion, but compactLayoutMetrics reports previewTitle: null at apps/web/e2e/search.mjs:2638. Search file/text previews use the shared ItemCard title (.item-title, #851), while the layout probe only queried .preview h3. I updated the probe and the title-review selectors to accept the shared title element; the UI assertion still checks the title's bounds and line box.

Finding in the required `bun run test:e2e:search`: the `budget` preview reaches the two-row layout assertion, but `compactLayoutMetrics` reports `previewTitle: null` at `apps/web/e2e/search.mjs:2638`. Search file/text previews use the shared `ItemCard` title (`.item-title`, #851), while the layout probe only queried `.preview h3`. I updated the probe and the title-review selectors to accept the shared title element; the UI assertion still checks the title's bounds and line box.
Author
Owner

E2E finding: bun run test:e2e:search passed the title and content-height checks, then timed out waiting for the expanded Search surface. The primary Playwright context always runs emulateMacPlatform, while the keyboard expansion step pressed Control+Enter; the shortcut registry maps search.all to Meta+Enter on macOS. Updated the probe to use its existing PRIMARY_MODIFIER so it tests the intended shortcut and animation on the emulated platform.

E2E finding: `bun run test:e2e:search` passed the title and content-height checks, then timed out waiting for the expanded Search surface. The primary Playwright context always runs `emulateMacPlatform`, while the keyboard expansion step pressed `Control+Enter`; the shortcut registry maps `search.all` to Meta+Enter on macOS. Updated the probe to use its existing `PRIMARY_MODIFIER` so it tests the intended shortcut and animation on the emulated platform.
Author
Owner

E2E finding: after the macOS shortcut probe passed, bun run test:e2e:search reached the grouped-results check and reported actual section headings Notes, Journal, Days, Photos, and Files. The assertion still expected Log entries, while the Search kind map uses Journal and CONTEXT.md names the UI source label as Journal. Updated the assertion and ordering list to use the glossary term; result grouping is unchanged.

E2E finding: after the macOS shortcut probe passed, `bun run test:e2e:search` reached the grouped-results check and reported actual section headings `Notes`, `Journal`, `Days`, `Photos`, and `Files`. The assertion still expected `Log entries`, while the Search kind map uses `Journal` and CONTEXT.md names the UI source label as Journal. Updated the assertion and ordering list to use the glossary term; result grouping is unchanged.
Author
Owner

E2E finding: the Search flow passed grouped results and keyboard navigation, then the shortcut-presence assertion returned empty strings. The current shared Kbd renders the caps variant as .kbd-caps with nested .kbd-cap elements; the test still queried the old inline .kbd span. Updated the probe to inspect the rendered caps container while keeping the assertion that every desktop action shows a registered shortcut.

E2E finding: the Search flow passed grouped results and keyboard navigation, then the shortcut-presence assertion returned empty strings. The current shared `Kbd` renders the caps variant as `.kbd-caps` with nested `.kbd-cap` elements; the test still queried the old inline `.kbd` span. Updated the probe to inspect the rendered caps container while keeping the assertion that every desktop action shows a registered shortcut.
Author
Owner

E2E finding: the production Search flow passed selected-result actions, filters, expansion, and photo-grid checks, then emitted Cannot read properties of null (reading 'pathname') from the Search route chunk while restoring a deep link. The follow-up expanded-view wait timed out. The route's afterNavigate callback reads to.url.pathname and from.url.pathname without guarding the nullable URL in SvelteKit navigation targets. I’m adding nested URL guards so document/unload transitions do not throw and deep-link restoration remains error-free.

E2E finding: the production Search flow passed selected-result actions, filters, expansion, and photo-grid checks, then emitted `Cannot read properties of null (reading 'pathname')` from the Search route chunk while restoring a deep link. The follow-up expanded-view wait timed out. The route's `afterNavigate` callback reads `to.url.pathname` and `from.url.pathname` without guarding the nullable URL in SvelteKit navigation targets. I’m adding nested URL guards so document/unload transitions do not throw and deep-link restoration remains error-free.
Author
Owner

E2E finding: the deep-link restore now passes with no route error, but the #851 extensionless HEIC row probe timed out after the Photos group appeared. The fixture's preceding API poll had already confirmed the indexed file path and image/heic MIME. This step waited for a generic spinner-free state, not the query-specific API response, so it could observe a stale group before the target row rendered. I’m tying the UI assertion to that query’s response and its returned title.

E2E finding: the deep-link restore now passes with no route error, but the #851 extensionless HEIC row probe timed out after the Photos group appeared. The fixture's preceding API poll had already confirmed the indexed file path and `image/heic` MIME. This step waited for a generic spinner-free state, not the query-specific API response, so it could observe a stale group before the target row rendered. I’m tying the UI assertion to that query’s response and its returned title.
Author
Owner

Correction to my previous HEIC note: the query-specific response and row were both present. The failure snapshot shows a Photos grid tile with role="option" and aria-label="atlas-extensionless-851"; its visible text is intentionally empty in the image grid. The test incorrectly used hasText for that tile. I’m changing it to locate the exact accessible option name, preserving the check that the extensionless HEIC appears in Photos.

Correction to my previous HEIC note: the query-specific response and row were both present. The failure snapshot shows a Photos grid tile with `role="option"` and `aria-label="atlas-extensionless-851"`; its visible text is intentionally empty in the image grid. The test incorrectly used `hasText` for that tile. I’m changing it to locate the exact accessible option name, preserving the check that the extensionless HEIC appears in Photos.
Author
Owner

E2E finding: in the #544 Show all flow, the fixture readiness poll confirmed eight Note and eight text-file hits. After pressing Enter on “Show all 8 Files results,” the test sampled the expanded DOM as soon as the spinner disappeared and saw eight options instead of the expected sixteen. I’m waiting for the expansion’s query-specific response and all sixteen rendered options before asserting the existing result count.

E2E finding: in the #544 Show all flow, the fixture readiness poll confirmed eight Note and eight text-file hits. After pressing Enter on “Show all 8 Files results,” the test sampled the expanded DOM as soon as the spinner disappeared and saw eight options instead of the expected sixteen. I’m waiting for the expansion’s query-specific response and all sixteen rendered options before asserting the existing result count.
Author
Owner

E2E finding: the full Search run now passes the HEIC MIME/group/accessibility check. It then timed out filling .desktop-sidebar input.rename in the saved-search rename flow. SavedSearchList uses the shared InlineRename component, whose control is exposed as the textbox “Name of saved search”; the dedicated rename E2E already selects it by role and name. I’m aligning this Search probe with that accessible selector.

E2E finding: the full Search run now passes the HEIC MIME/group/accessibility check. It then timed out filling `.desktop-sidebar input.rename` in the saved-search rename flow. `SavedSearchList` uses the shared `InlineRename` component, whose control is exposed as the textbox “Name of saved search”; the dedicated rename E2E already selects it by role and name. I’m aligning this Search probe with that accessible selector.
Author
Owner

E2E finding: after the saved-search rename selector passed, the phone sidebar action measured 28×28px, below the 44px coarse-pointer target. The measurement also ran while the mobile sheet was still sliding (left: -43px), so I’m making the ellipsis control use the shared --hit size on coarse pointers and waiting for the sheet to settle before checking the target.

E2E finding: after the saved-search rename selector passed, the phone sidebar action measured 28×28px, below the 44px coarse-pointer target. The measurement also ran while the mobile sheet was still sliding (`left: -43px`), so I’m making the ellipsis control use the shared `--hit` size on coarse pointers and waiting for the sheet to settle before checking the target.
Author
Owner

E2E environment finding: the production server did not emit its setup token within Search's custom 60-second startup loop, and a 15-second local probe produced no startup output. Search's loop was shorter than the shared E2E harness's five-minute startup bound, so this is not yet evidence of a server crash. I’m aligning Search with the shared bound and surfacing startup diagnostics with the setup token redacted.

E2E environment finding: the production server did not emit its setup token within Search's custom 60-second startup loop, and a 15-second local probe produced no startup output. Search's loop was shorter than the shared E2E harness's five-minute startup bound, so this is not yet evidence of a server crash. I’m aligning Search with the shared bound and surfacing startup diagnostics with the setup token redacted.
Author
Owner

Full bun run test:e2e:search verification: all preceding functional checks passed, including preview, deep link, extensionless HEIC, saved-search actions, the 44px phone target, Files, Calendar and command mode. The run then failed at the existing palette first-result p95 is within 50 ms assertion with p50=93.5ms and p95=194.3ms (39 samples). The test was running on the shared host alongside concurrent Rust builds/tests. I left the assertion unchanged; this is a timing-only result under host load, not a functional failure from this patch.

Full `bun run test:e2e:search` verification: all preceding functional checks passed, including preview, deep link, extensionless HEIC, saved-search actions, the 44px phone target, Files, Calendar and command mode. The run then failed at the existing `palette first-result p95 is within 50 ms` assertion with p50=93.5ms and p95=194.3ms (39 samples). The test was running on the shared host alongside concurrent Rust builds/tests. I left the assertion unchanged; this is a timing-only result under host load, not a functional failure from this patch.
Author
Owner

Screenshot finding: the production matrix generated the requested full 820/1440 Noir and Mono views. In the dedicated 4x crop pass, Mono 1440 and 820 footer edges and Journal/Event time rows were captured, but the 820px Mono Task card wait expired before the Noir 4x phase began. The normal 820px Task screenshots were captured in the same run. I’m adding targeted diagnostics and rerunning the missing Noir crops to distinguish a cold-preview timing issue from a Search Task preview failure.

Screenshot finding: the production matrix generated the requested full 820/1440 Noir and Mono views. In the dedicated 4x crop pass, Mono 1440 and 820 footer edges and Journal/Event time rows were captured, but the 820px Mono Task card wait expired before the Noir 4x phase began. The normal 820px Task screenshots were captured in the same run. I’m adding targeted diagnostics and rerunning the missing Noir crops to distinguish a cold-preview timing issue from a Search Task preview failure.
Author
Owner

Completed

Finished the #1137/#1139 search merge-and-polish pass. Merged origin/dev once and kept both behaviors in the result rows: MIME-based file glyphs and the aligned label/date columns. The date clock and value chip now wrap as one group. The footer fade uses the panel surface token, so Noir fades into its own panel. Search navigation handles missing route endpoints, and the saved-search menu meets the shared touch hit target.

Head SHA: fcdfaf2a5afee9ece0a34fb8a75f2b2630f2a663
Commits: fecf0737c merge, 97d72893a preview grouping/fade, 5e7a6e050 route guard, 6f5a2adea touch target, 244c1215f E2E probe alignment, 371584795 focused crop retry, fcdfaf2a5 crop flag docs.

Files

  • Search surface and results: apps/web/src/lib/components/search-dialog.svelte, apps/web/src/lib/search/SearchGroupHeading.svelte, apps/web/src/lib/search/SearchPreview.svelte, apps/web/src/lib/search/SearchResultRow.svelte, apps/web/src/lib/search/SavedSearchList.svelte, apps/web/src/lib/search/providers.ts, apps/web/src/lib/search/server.ts, apps/web/src/routes/search/+page.svelte.
  • Shared preview and tokens: packages/ui/src/components/calendar/ItemPreview.svelte, packages/ui/src/time.ts, packages/ui/src/tokens.css, apps/web/src/calternal-app.css.
  • Tests and decisions: apps/web/e2e/search.mjs, apps/web/src/lib/calendar/ItemPreview.svelte.test.ts, apps/web/src/lib/time.test.ts, tests/adversarial/mail_screenshot_fixture.py, docs/DESIGN.md.

Screenshot evidence

All screenshots use macOS platform signals. The 820px and 1440px Mono and Noir matrix, plus the 4× journal/event/task date-time rows and 4× footer edges, are attached to this issue:

Width Theme Search matrix 4× date-time rows 4× footer
820px Mono Journal · Event · Task Journal · Event · Task footer edge
820px Noir Journal · Event · Task Journal · Event · Task footer edge
1440px Mono Journal · Event · Task Journal · Event · Task footer edge
1440px Noir Journal · Event · Task Journal · Event · Task footer edge

Gate results

bun run check stops in the existing performance exception ratchet before Svelte validation. Verbatim output:

perf-lint: INVALID: exception ratchet: contract.blaze: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; contract.blocked-network: 356 exceptions exceed the ratchet ceiling 355; fix the new violation instead; contract.dom-bound: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; contract.model-bound: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; contract.row-identity: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; contract.snapshot: 356 exceptions exceed the ratchet ceiling 355; fix the new violation instead; coverage.profile: 356 exceptions exceed the ratchet ceiling 355; fix the new violation instead; coverage.readiness: 356 exceptions exceed the ratchet ceiling 355; fix the new violation instead; io.unresolved-call: 16191 exceptions exceed the ratchet ceiling 16190; fix the new violation instead; render.blaze-adapter: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; render.bound: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; render.model_byte_cap: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; render.model_row_cap: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; total: ledger has 21977 exceptions; ratchet total is 21964

The direct Svelte checker passed with 0 errors and 4 existing warnings in 3 files. The focused ItemPreview.svelte.test.ts passed (18 tests). bun run build passed and ended with:

Compressed 887 static variants; saved 20916964 bytes.

bun run test:e2e:search passed the functional search flows, then failed its unchanged first-result performance assertion under shared-host load:

keystroke to first result frame: p50=93.5ms p95=194.3ms (n=39)
AssertionError [ERR_ASSERTION]: palette first-result p95 is within 50 ms

The focused 4× crop retries passed for Mono and Noir at both widths. Verbatim output:

PASS #1137/#1139 native 4x sticky, footer, preview and scrim crops at required widths and themes
CSP REPORTS search: 0 across 2 pages

cargo clean completed: Removed 8633 files, 7.2GiB total. Web build outputs were removed. There are no Rust changes.

UX gaps closed

  • Clock icons stay beside their date/time values when a row wraps.
  • Noir footer blur fades to the panel surface.
  • Saved-search menu controls use the shared 44px coarse-pointer target.
  • Search route transitions tolerate missing from or to URLs.
  • E2E probes use current visible labels and accessible result names; no test expectation was loosened.

UX gaps left

No additional interaction gaps surfaced in this pass. The unresolved E2E result is the 50ms performance budget noted above, not a failed interaction assertion.

Decisions

No design-doc gap required a new product decision. The 768px Search preview breakpoint is recorded in docs/DESIGN.md §32 and makes the preview available at the requested 820px tablet width. The date-time grouping and surface fade follow the #1139 request and existing shared tokens.

For the merge round

  • bun run check — clear or reconcile the origin/dev perf-lint ratchet mismatch, then prove the web gate passes.
  • bun run test — run the full web unit and performance source suite.
  • bun run test:e2e — run the shell E2E smoke suite against the combined branch.
  • Rerun bun run test:e2e:search with a quiet or controlled host to determine whether the 50ms first-result p95 is a real regression; keep the existing threshold unchanged.
## Completed Finished the #1137/#1139 search merge-and-polish pass. Merged `origin/dev` once and kept both behaviors in the result rows: MIME-based file glyphs and the aligned label/date columns. The date clock and value chip now wrap as one group. The footer fade uses the panel surface token, so Noir fades into its own panel. Search navigation handles missing route endpoints, and the saved-search menu meets the shared touch hit target. Head SHA: `fcdfaf2a5afee9ece0a34fb8a75f2b2630f2a663` Commits: `fecf0737c` merge, `97d72893a` preview grouping/fade, `5e7a6e050` route guard, `6f5a2adea` touch target, `244c1215f` E2E probe alignment, `371584795` focused crop retry, `fcdfaf2a5` crop flag docs. ## Files - Search surface and results: `apps/web/src/lib/components/search-dialog.svelte`, `apps/web/src/lib/search/SearchGroupHeading.svelte`, `apps/web/src/lib/search/SearchPreview.svelte`, `apps/web/src/lib/search/SearchResultRow.svelte`, `apps/web/src/lib/search/SavedSearchList.svelte`, `apps/web/src/lib/search/providers.ts`, `apps/web/src/lib/search/server.ts`, `apps/web/src/routes/search/+page.svelte`. - Shared preview and tokens: `packages/ui/src/components/calendar/ItemPreview.svelte`, `packages/ui/src/time.ts`, `packages/ui/src/tokens.css`, `apps/web/src/calternal-app.css`. - Tests and decisions: `apps/web/e2e/search.mjs`, `apps/web/src/lib/calendar/ItemPreview.svelte.test.ts`, `apps/web/src/lib/time.test.ts`, `tests/adversarial/mail_screenshot_fixture.py`, `docs/DESIGN.md`. ## Screenshot evidence All screenshots use macOS platform signals. The 820px and 1440px Mono and Noir matrix, plus the 4× journal/event/task date-time rows and 4× footer edges, are attached to this issue: | Width | Theme | Search matrix | 4× date-time rows | 4× footer | |---|---|---|---|---| | 820px | Mono | [Journal](https://git.kayg.org/attachments/528091a8-db25-4a43-93d2-b1e8cc0ee8fe) · [Event](https://git.kayg.org/attachments/39028020-dca8-4ab2-a109-6809624e8dfc) · [Task](https://git.kayg.org/attachments/049cdfc9-e244-4316-b98d-547303a15ba5) | [Journal](https://git.kayg.org/attachments/daec479e-8a38-4671-a99a-0a2e47003a71) · [Event](https://git.kayg.org/attachments/d87fddd6-16fe-402e-8037-44f600810860) · [Task](https://git.kayg.org/attachments/43049716-c80c-4e12-807b-bb9766f7b8fe) | [footer edge](https://git.kayg.org/attachments/8b120669-e5a8-4a4c-85ec-63d85cdd6a09) | | 820px | Noir | [Journal](https://git.kayg.org/attachments/ef79bab6-4624-457b-92be-b6ba5e054dce) · [Event](https://git.kayg.org/attachments/b332ca03-b6a1-47ac-8af2-e5b5e6beacc3) · [Task](https://git.kayg.org/attachments/b6d00a82-6efc-4d08-a757-151f4c5a66e1) | [Journal](https://git.kayg.org/attachments/4f3e1403-1018-4342-8150-0b19a313214d) · [Event](https://git.kayg.org/attachments/861b71da-2637-4c69-a46c-98d6668c0c85) · [Task](https://git.kayg.org/attachments/6f0e569a-07fd-45a3-a92a-ee3cd3d6648f) | [footer edge](https://git.kayg.org/attachments/c322b883-5e4a-4b8a-ab52-3f5be33c15a5) | | 1440px | Mono | [Journal](https://git.kayg.org/attachments/f589f9b9-6a38-4944-81c5-856ef71caec8) · [Event](https://git.kayg.org/attachments/83ddbf4f-c5c7-4f07-b063-1df6930da480) · [Task](https://git.kayg.org/attachments/4bf28c92-ef2f-4cbb-aafd-33099ea7ce97) | [Journal](https://git.kayg.org/attachments/1ec705dd-7e1f-4cee-9d9d-d85ebe9fe0fd) · [Event](https://git.kayg.org/attachments/fc536110-ff58-4e90-a941-f222af6fd557) · [Task](https://git.kayg.org/attachments/2ded17e7-a967-4cc4-ba45-1d18b4fac1b1) | [footer edge](https://git.kayg.org/attachments/32d9a92d-61ae-422e-aa38-2ceefa4390ab) | | 1440px | Noir | [Journal](https://git.kayg.org/attachments/dc6f2773-2b1c-43e2-b113-9fca05bde536) · [Event](https://git.kayg.org/attachments/71adef98-9dad-41d6-afed-cd875eb18b9b) · [Task](https://git.kayg.org/attachments/660e99e6-8fcf-43bf-855c-ea19dc9cfc09) | [Journal](https://git.kayg.org/attachments/88239b3e-ba63-4c6e-baca-3b99efa93c66) · [Event](https://git.kayg.org/attachments/0b94c20b-af61-48a1-9b43-94e17856ff0f) · [Task](https://git.kayg.org/attachments/9c56a5ff-83ea-4c5a-a709-15bf1515549c) | [footer edge](https://git.kayg.org/attachments/f7ca96da-bca3-46d2-a1a0-1b04514c4809) | ## Gate results `bun run check` stops in the existing performance exception ratchet before Svelte validation. Verbatim output: ```text perf-lint: INVALID: exception ratchet: contract.blaze: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; contract.blocked-network: 356 exceptions exceed the ratchet ceiling 355; fix the new violation instead; contract.dom-bound: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; contract.model-bound: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; contract.row-identity: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; contract.snapshot: 356 exceptions exceed the ratchet ceiling 355; fix the new violation instead; coverage.profile: 356 exceptions exceed the ratchet ceiling 355; fix the new violation instead; coverage.readiness: 356 exceptions exceed the ratchet ceiling 355; fix the new violation instead; io.unresolved-call: 16191 exceptions exceed the ratchet ceiling 16190; fix the new violation instead; render.blaze-adapter: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; render.bound: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; render.model_byte_cap: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; render.model_row_cap: 290 exceptions exceed the ratchet ceiling 289; fix the new violation instead; total: ledger has 21977 exceptions; ratchet total is 21964 ``` The direct Svelte checker passed with 0 errors and 4 existing warnings in 3 files. The focused `ItemPreview.svelte.test.ts` passed (18 tests). `bun run build` passed and ended with: ```text Compressed 887 static variants; saved 20916964 bytes. ``` `bun run test:e2e:search` passed the functional search flows, then failed its unchanged first-result performance assertion under shared-host load: ```text keystroke to first result frame: p50=93.5ms p95=194.3ms (n=39) AssertionError [ERR_ASSERTION]: palette first-result p95 is within 50 ms ``` The focused 4× crop retries passed for Mono and Noir at both widths. Verbatim output: ```text PASS #1137/#1139 native 4x sticky, footer, preview and scrim crops at required widths and themes CSP REPORTS search: 0 across 2 pages ``` `cargo clean` completed: `Removed 8633 files, 7.2GiB total`. Web build outputs were removed. There are no Rust changes. ## UX gaps closed - Clock icons stay beside their date/time values when a row wraps. - Noir footer blur fades to the panel surface. - Saved-search menu controls use the shared 44px coarse-pointer target. - Search route transitions tolerate missing `from` or `to` URLs. - E2E probes use current visible labels and accessible result names; no test expectation was loosened. ## UX gaps left No additional interaction gaps surfaced in this pass. The unresolved E2E result is the 50ms performance budget noted above, not a failed interaction assertion. ## Decisions No design-doc gap required a new product decision. The 768px Search preview breakpoint is recorded in `docs/DESIGN.md` §32 and makes the preview available at the requested 820px tablet width. The date-time grouping and surface fade follow the #1139 request and existing shared tokens. ## For the merge round - `bun run check` — clear or reconcile the `origin/dev` perf-lint ratchet mismatch, then prove the web gate passes. - `bun run test` — run the full web unit and performance source suite. - `bun run test:e2e` — run the shell E2E smoke suite against the combined branch. - Rerun `bun run test:e2e:search` with a quiet or controlled host to determine whether the 50ms first-result p95 is a real regression; keep the existing threshold unchanged.
Author
Owner

Starting merge-round work on branch job/merge25. Initial HEAD: b968d04928; origin/dev merge base: 41bf97fb28. The palette branch merge is in progress with SearchPreview.svelte unresolved; I am checking both implementations before resolving it.

Starting merge-round work on branch job/merge25. Initial HEAD: b968d04928f12bdacb77cb33b9367160a8d360ee; origin/dev merge base: 41bf97fb2861ea6e4ea70aab7d3b15a1c9aa278d. The palette branch merge is in progress with SearchPreview.svelte unresolved; I am checking both implementations before resolving it.
Author
Owner

Finding: the first scripts/perf-lint --check stopped before pin validation because the worktree could not resolve typescript (Cannot find module from Node; Bun exposed no ScriptTarget). I am restoring dependencies from the committed lockfile, then I will validate the exact pins.

Finding: the first `scripts/perf-lint --check` stopped before pin validation because the worktree could not resolve `typescript` (`Cannot find module` from Node; Bun exposed no `ScriptTarget`). I am restoring dependencies from the committed lockfile, then I will validate the exact pins.
Author
Owner

Finding: after the SearchPreview conflict was resolved, scripts/perf-lint --check identified a moved layout.observer-purpose exception in apps/web/src/lib/components/search-dialog.svelte (scope <module>:dd9d7691a28135ce). The rule remains active; I will refresh only exact live pins after updating the branch from origin/dev.

Finding: after the SearchPreview conflict was resolved, `scripts/perf-lint --check` identified a moved `layout.observer-purpose` exception in `apps/web/src/lib/components/search-dialog.svelte` (scope `<module>:dd9d7691a28135ce`). The rule remains active; I will refresh only exact live pins after updating the branch from origin/dev.
Author
Owner

Pin refresh: after the required origin/dev merge check, scripts/perf-lint --adopt-7c refreshed 349 existing hash pins across the eight changed UI source files and added 16 exact Search surface checkpoint scopes. It changed only exact source hashes plus the owning issue/reason metadata for 16 existing scopes; it did not add or remove exception rules, change caps, or alter contracts/perf/ratchet.json (22104 exceptions before and after). Gate output: Adopted 5064 exact #1058 sites; ordinary future ratchet remains active and perf-lint: PASS; 0 violations; 22104 scoped exceptions.

Pin refresh: after the required `origin/dev` merge check, `scripts/perf-lint --adopt-7c` refreshed 349 existing hash pins across the eight changed UI source files and added 16 exact Search surface checkpoint scopes. It changed only exact source hashes plus the owning issue/reason metadata for 16 existing scopes; it did not add or remove exception rules, change caps, or alter `contracts/perf/ratchet.json` (22104 exceptions before and after). Gate output: `Adopted 5064 exact #1058 sites; ordinary future ratchet remains active` and `perf-lint: PASS; 0 violations; 22104 scoped exceptions`.
Author
Owner

Starting on branch job/merge25, based at origin/dev merge-base 41bf97fb28. The issue reports one unused-or-changed exact pin for layout.observer-purpose in search-dialog.svelte; I will refresh only live pins after merging origin/dev.

Starting on branch job/merge25, based at origin/dev merge-base 41bf97fb2861ea6e4ea70aab7d3b15a1c9aa278d. The issue reports one unused-or-changed exact pin for layout.observer-purpose in search-dialog.svelte; I will refresh only live pins after merging origin/dev.
Author
Owner

Evidence: after git fetch origin and git merge origin/dev (Already up to date), search-dialog.svelte still emits layout.observer-purpose for :dd9d7691a28135ce. The current parser hash is 596a9fef99e92cb91dcd6a0596f22aa7f34c94f72e6518c34de1725ebbb4cc2a; both worktree records in exceptions.json and adoption-1058.json carry that exact hash. The committed record had 71a6d0c3b434f38faa723b2cf74f94dc274a6079330098998cd68852c29c6ab9. Owner, reason, replacement test, limit and expiry remain unchanged.

Evidence: after git fetch origin and git merge origin/dev (Already up to date), search-dialog.svelte still emits layout.observer-purpose for <module>:dd9d7691a28135ce. The current parser hash is 596a9fef99e92cb91dcd6a0596f22aa7f34c94f72e6518c34de1725ebbb4cc2a; both worktree records in exceptions.json and adoption-1058.json carry that exact hash. The committed record had 71a6d0c3b434f38faa723b2cf74f94dc274a6079330098998cd68852c29c6ab9. Owner, reason, replacement test, limit and expiry remain unchanged.
Author
Owner

Finished: #1137

What changed

Refreshed the exact live syntax pins in the performance exception ledger and the #1058 adoption checkpoint. The search-dialog.svelte layout.observer-purpose record now carries the live syntax hash 596a9fef99e92cb91dcd6a0596f22aa7f34c94f72e6518c34de1725ebbb4cc2a. The full guard confirms 0 violations. No rule or ratchet change was made.

Files

  • contracts/perf/exceptions.json
  • contracts/perf/adoption-1058.json

Merge and commit

git fetch origin and git merge origin/dev: Already up to date.
Head: d0061ec3df127d81c86729d07d899b0bf2b6de91 (perf: refresh exact live pins after merge (#1137)).

Gates

bun install --frozen-lockfile exited 0:

bun install v1.4.2 (744846f84)
Resolving dependencies
Resolved, downloaded and extracted [20]
911 packages installed [8.88s]

cd apps/web && bun run check exited 0. Verbatim output excerpts:

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

cd apps/web && bun run test --maxWorkers=2 exited 0. Verbatim output:

 Test Files  266 passed (266)
      Tests  1830 passed (1830)
   Start at  02:43:38
   Duration  941.85s (transform 31%, environment 27%, import 20%, tests 16%, setup 6%)

cargo clean exited 0 and removed 1 file (356B). The web .svelte-kit output was removed.

Known gaps

The successful check reports 4 Svelte warnings in unmodified files: empty focus rulesets in AttachmentDeck.svelte and AgendaList.svelte, and unused .note-page-lede and .note-state selectors in the Notes route.

Decisions

No new design decision was needed. DESIGN §59 and the perf guard already require exact live syntax pins. The target pin's owner, reason, replacement test, limit and expiry remain unchanged.

# Finished: #1137 ## What changed Refreshed the exact live syntax pins in the performance exception ledger and the #1058 adoption checkpoint. The `search-dialog.svelte` `layout.observer-purpose` record now carries the live syntax hash `596a9fef99e92cb91dcd6a0596f22aa7f34c94f72e6518c34de1725ebbb4cc2a`. The full guard confirms 0 violations. No rule or ratchet change was made. ## Files - `contracts/perf/exceptions.json` - `contracts/perf/adoption-1058.json` ## Merge and commit `git fetch origin` and `git merge origin/dev`: `Already up to date.` Head: `d0061ec3df127d81c86729d07d899b0bf2b6de91` (`perf: refresh exact live pins after merge (#1137)`). ## Gates `bun install --frozen-lockfile` exited 0: ```text bun install v1.4.2 (744846f84) Resolving dependencies Resolved, downloaded and extracted [20] 911 packages installed [8.88s] ``` `cd apps/web && bun run check` exited 0. Verbatim output excerpts: ```text perf-lint: PASS; 0 violations; 22104 scoped exceptions svelte-check found 0 errors and 4 warnings in 3 files ``` `cd apps/web && bun run test --maxWorkers=2` exited 0. Verbatim output: ```text Test Files 266 passed (266) Tests 1830 passed (1830) Start at 02:43:38 Duration 941.85s (transform 31%, environment 27%, import 20%, tests 16%, setup 6%) ``` `cargo clean` exited 0 and removed 1 file (356B). The web `.svelte-kit` output was removed. ## Known gaps The successful check reports 4 Svelte warnings in unmodified files: empty focus rulesets in `AttachmentDeck.svelte` and `AgendaList.svelte`, and unused `.note-page-lede` and `.note-state` selectors in the Notes route. ## Decisions No new design decision was needed. DESIGN §59 and the perf guard already require exact live syntax pins. The target pin's owner, reason, replacement test, limit and expiry remain unchanged.
Sign in to join this conversation.
No labels
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#1137
No description provided.