From d7c603b1dd08981f024ed40dd83d66e75b5c6d2d Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 14 Aug 2026 11:40:28 +0000 Subject: [PATCH 1/4] fix(pwa): add decoding=async to PWA install-sheet icon Ledger #215, remaining item (a): the PWA install-sheet app icon (pwa-lifecycle.tsx) had no decoding attribute, unlike the lightbox (image-lightbox.tsx) and non-PDF document preview (non-pdf-source-preview.tsx) images that already carry decoding="async". Bring it in line with that established pattern so the browser can decode it off the main thread. The other remaining item from #215 (demo-document PNG -> WebP conversion) is addressed separately in this PR's body with an explicit keep-as-PNG decision, not a code change. --- src/components/pwa-lifecycle.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/pwa-lifecycle.tsx b/src/components/pwa-lifecycle.tsx index 3fd2cda8e3..7957b09977 100644 --- a/src/components/pwa-lifecycle.tsx +++ b/src/components/pwa-lifecycle.tsx @@ -150,6 +150,7 @@ function InstallAppIdentity({ title, titleId, tagline }: { title: string; titleI src="/icons/icon-192" alt="" aria-hidden="true" + decoding="async" width={56} height={56} className="h-14 w-14 shrink-0 rounded-xl border border-[color:var(--border-lux)] shadow-[var(--shadow-tight)]" From 19caec950e6f201a5e7799d11695896103b18e2b Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 14 Aug 2026 11:41:48 +0000 Subject: [PATCH 2/4] docs(issues): attribute desktop /documents/search CLS to shared search-chrome composer adoption (#308) Ledger #308. Profiled the page with a Playwright + PerformanceObserver layout-shift harness at desktop emulation (1350x940, DPR 1, matching the Lighthouse desktop preset), driving the same offline production build the committed baseline was measured against - the method the row's own "Next" note prescribed. Reproduced CLS 0.118 against the 0.1192626548872241 baseline, one dominant shift responsible for ~99.98% of the total. Root cause traced with a rect-timeline: MasterSearchHeader's desktop composer-adoption effect (the desktopComposerPortalActive / isDesktopComposerSlotReady gate on data-composer-slot-ready, added to avoid a React #418 hydration mismatch) portals the search composer out of its header-inline hydration position and into GlobalSearchShell's #desktop-page-search-composer-slot inside #main-content shortly after first paint - the header shrinks 184px at the exact instant the slot grows 0 -> 184px. This is shared desktop search-chrome timing (the same composer-adoption mechanism applies to every non-standalone-home mode page), not something page-local to /documents/search, so per this task's stop condition the finding is recorded rather than patched here - a safe fix touches MasterSearchHeader/GlobalSearchShell's composer-slot contract in docs/search-chrome-behaviour.md, out of scope for this bundled low-risk visual PR. Queues an /issues update request (docs/outstanding-issues-inbox/) recording the full finding and next step for #308 rather than hand-editing the ledger. --- .../f86a3002-5019-4ae4-93fb-d01a05a7bae6.json | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 docs/outstanding-issues-inbox/f86a3002-5019-4ae4-93fb-d01a05a7bae6.json diff --git a/docs/outstanding-issues-inbox/f86a3002-5019-4ae4-93fb-d01a05a7bae6.json b/docs/outstanding-issues-inbox/f86a3002-5019-4ae4-93fb-d01a05a7bae6.json new file mode 100644 index 0000000000..c9edd6d9c2 --- /dev/null +++ b/docs/outstanding-issues-inbox/f86a3002-5019-4ae4-93fb-d01a05a7bae6.json @@ -0,0 +1,11 @@ +{ + "version": 1, + "id": "f86a3002-5019-4ae4-93fb-d01a05a7bae6", + "createdOn": "2026-08-14", + "action": "update", + "payload": { + "id": "#308", + "detail": "Desktop attribution done (the row's own Next step): Playwright + PerformanceObserver(layout-shift) against an offline production build, desktop emulation (viewport 1350x940, DPR 1, matching the Lighthouse desktop preset) — same method #147 used for mobile. Reproduced CLS 0.118 (baseline 0.1192626548872241), one dominant shift = ~99.98% of the total, single event at first-paint+~0.3-0.5s. Root cause: MasterSearchHeader's composer-adoption effect (master-search-header.tsx — desktopComposerPortalActive/isDesktopComposerSlotReady, gated on data-composer-slot-ready to avoid a React #418 hydration mismatch) portals the search composer from its header-inline hydration position into GlobalSearchShell's #desktop-page-search-composer-slot (inside #main-content) shortly after first paint. Rect-timeline evidence: header shrinks 184px (main-content top 256px -> 72px) at the exact instant the slot grows 0 -> 184px. This is shared desktop search-chrome composer-adoption timing — the same mechanism applies to every non-standalone-home mode page (shouldShowSearchComposer && !isStandaloneModeHome), not something page-local to /documents/search. Per this task's own stop condition (chrome-traced, not page-local) this is recorded rather than fixed: a safe fix means reserving the composer's settled height at the adoption boundary under the one-composer/hidden-means-zero-reserve contracts in docs/search-chrome-behaviour.md, out of scope for a bundled low-risk visual PR. Next: reserve slot height (or header composer-inline height) before hydration resolves so adoption does not reflow either container; re-measure with the same harness after. Stop: do not patch with a blanket min-height on #main-content or #desktop-page-search-composer-slot without reproducing the adoption-boundary fix — that would hide the shift without matching the header's corresponding size change, and could reintroduce a mismatched reserve of the kind #147 already had to fix once.", + "source": "session 2026-08-14, PR branch codex/visual-layout-polish (bundled with ledger #215); desktop CLS attribution script adapted from scripts/measure-cls-attribution.mjs (run offline, not committed)" + } +} From 7490ac090fc1577c72bbf5db943126b1ceb47770 Mon Sep 17 00:00:00 2001 From: BigSimmo <87357024+BigSimmo@users.noreply.github.com> Date: Sat, 15 Aug 2026 00:04:05 +0800 Subject: [PATCH 3/4] fix(issues): preserve desktop CLS guardrails --- .../f86a3002-5019-4ae4-93fb-d01a05a7bae6.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/outstanding-issues-inbox/f86a3002-5019-4ae4-93fb-d01a05a7bae6.json b/docs/outstanding-issues-inbox/f86a3002-5019-4ae4-93fb-d01a05a7bae6.json index c9edd6d9c2..e2008df85e 100644 --- a/docs/outstanding-issues-inbox/f86a3002-5019-4ae4-93fb-d01a05a7bae6.json +++ b/docs/outstanding-issues-inbox/f86a3002-5019-4ae4-93fb-d01a05a7bae6.json @@ -5,7 +5,7 @@ "action": "update", "payload": { "id": "#308", - "detail": "Desktop attribution done (the row's own Next step): Playwright + PerformanceObserver(layout-shift) against an offline production build, desktop emulation (viewport 1350x940, DPR 1, matching the Lighthouse desktop preset) — same method #147 used for mobile. Reproduced CLS 0.118 (baseline 0.1192626548872241), one dominant shift = ~99.98% of the total, single event at first-paint+~0.3-0.5s. Root cause: MasterSearchHeader's composer-adoption effect (master-search-header.tsx — desktopComposerPortalActive/isDesktopComposerSlotReady, gated on data-composer-slot-ready to avoid a React #418 hydration mismatch) portals the search composer from its header-inline hydration position into GlobalSearchShell's #desktop-page-search-composer-slot (inside #main-content) shortly after first paint. Rect-timeline evidence: header shrinks 184px (main-content top 256px -> 72px) at the exact instant the slot grows 0 -> 184px. This is shared desktop search-chrome composer-adoption timing — the same mechanism applies to every non-standalone-home mode page (shouldShowSearchComposer && !isStandaloneModeHome), not something page-local to /documents/search. Per this task's own stop condition (chrome-traced, not page-local) this is recorded rather than fixed: a safe fix means reserving the composer's settled height at the adoption boundary under the one-composer/hidden-means-zero-reserve contracts in docs/search-chrome-behaviour.md, out of scope for a bundled low-risk visual PR. Next: reserve slot height (or header composer-inline height) before hydration resolves so adoption does not reflow either container; re-measure with the same harness after. Stop: do not patch with a blanket min-height on #main-content or #desktop-page-search-composer-slot without reproducing the adoption-boundary fix — that would hide the shift without matching the header's corresponding size change, and could reintroduce a mismatched reserve of the kind #147 already had to fix once.", - "source": "session 2026-08-14, PR branch codex/visual-layout-polish (bundled with ledger #215); desktop CLS attribution script adapted from scripts/measure-cls-attribution.mjs (run offline, not committed)" + "detail": "Measured 2026-08-12 during the #147 close-out, twice, on the offline Lighthouse harness (Chromium 141): desktop /documents/search CLS **0.119**, against a committed baseline that also reads **0.119**. So this is long-standing and deterministic, not a regression — and it is above the 0.1 threshold. It sits outside #147's scope, which was mobile only, and it contradicts that row's claim that 'desktop passes everywhere: 0.016-0.097' — that range is stale. Companion desktop values from the same runs, all passing: /dsm 0.014, /forms 0.059-0.064, / 0.006, /therapy-compass 0.000. Desktop attribution completed 2026-08-14: a Playwright + PerformanceObserver(layout-shift) harness against an offline production build at 1350x940 DPR 1 recorded **0.118** CLS. This is a separate attribution measurement, not a replacement for the canonical 0.119 Lighthouse value. One first-paint+~0.3-0.5s event contributed ~99.98% of that harness total: MasterSearchHeader's composer-adoption effect portals the search composer into GlobalSearchShell's desktop slot, while the header shrinks 184px and the slot grows 0 -> 184px. This is shared desktop search-chrome timing, not page-local. Next: reserve the settled height at the adoption boundary under the one-composer/hidden-means-zero-reserve contracts, then re-measure with the same harness. Stop: do not raise the CLS budget; do not read local LCP or TBT from the loopback harness; and do not use a blanket min-height that hides the shift without matching the header reserve.", + "source": "Local offline verify:lighthouse runs 2026-08-12 (two runs, identical CLS); #147 close-out; lighthouse-budget.json. Attribution: session 2026-08-14, PR branch codex/visual-layout-polish; desktop CLS script adapted from scripts/measure-cls-attribution.mjs (offline, not committed)." } } From 681c16dbf436821bf1c50ed4ad8ee7d0f037a977 Mon Sep 17 00:00:00 2001 From: BigSimmo <87357024+BigSimmo@users.noreply.github.com> Date: Sat, 15 Aug 2026 00:04:52 +0800 Subject: [PATCH 4/4] docs(ledger): record PR 1949 review --- ...ff566a2b0f00c17f87c45206350cff5c6bf2f3b86690f27c5d7.record.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 docs/branch-review-records/6c6404a8a018cff566a2b0f00c17f87c45206350cff5c6bf2f3b86690f27c5d7.record.md diff --git a/docs/branch-review-records/6c6404a8a018cff566a2b0f00c17f87c45206350cff5c6bf2f3b86690f27c5d7.record.md b/docs/branch-review-records/6c6404a8a018cff566a2b0f00c17f87c45206350cff5c6bf2f3b86690f27c5d7.record.md new file mode 100644 index 0000000000..8beb6e1240 --- /dev/null +++ b/docs/branch-review-records/6c6404a8a018cff566a2b0f00c17f87c45206350cff5c6bf2f3b86690f27c5d7.record.md @@ -0,0 +1 @@ +| 2026-08-14 | codex/visual-layout-polish | 7490ac090fc1577c72bbf5db943126b1ceb47770 | PR #1949 CLS ledger corrective review and base-current verification | fixed the confirmed issue-update overwrite of canonical CLS measurement and stop conditions; no other high-confidence PR defect found | offline: JSON parse; ledger update semantic assertion; check-outstanding-issues; ledger-write-discipline self-test; git diff --check; manual adversarial pass |