Repository navigation
feat(checks): browser:check reads every page the way a visitor's browser does - #1650
Conversation
…ser does Sideways scroll, layout shift and early Intl were each found by hand on 2026-11-10, a page at a time. browser:check is that crawl, kept: it opens all 76 manifest pages in Chrome and reads four things on each. scroll no scroller wider than its box at 320, 360 and 390px shift cumulative layout shift at 1280 and 390px, under 4x CPU throttle intl no Intl call before the reader acts error no uncaught exception during load It replaces phone:check, which was the first of the four, and takes its CI job. Before each sweep it plants a 600px block, a 300px block pushed in above the content, a formatted number, a built formatter and a thrown error, and exits 2 if any goes unseen. config/browser-budget.json holds five exceptions with their reasons, and an entry a page no longer needs is a failure, so the file can only shrink. --base reads a deployment. That last flag found what a local run cannot. With real rows /around and /ledger scrolled sideways in production at every phone width, 103px and 3px out at 390px, while both passed locally on empty tables. Each table scrolls in its own box now; wrapped that way on the live pages, both read 0 at 360px. The rest of what it flagged is fixed here too: - 320px: /restore, /lens and five garage pages overflowed by 3 to 37px. - /garage/round-trip shifted 0.086 (0.192 at 390px in production). Its frame holds the window's height while the Markdown loads and the demo's output box holds its final height. - /restore names months and weekdays itself; the text matches en-US for all 131 restore points. With these fixes stashed and a stale budget planted, the check reports 10 failures and 2 stale entries. With them, 0 and 0. Gotcha 98 records the shift trap; 92 and 97 name the new check. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UnguFuTGB1AyfrTeixtbCT
Wire-size diff vs merge base
Brotli q11, the quality the edge serves. Every number here is deterministic: Client assetsNo change. 40 files, 245.02 KiB Brotli total. PagesTotal Brotli: 718.80 KiB → 718.95 KiB (+0.15 KiB, +0.0%) across 77 files, 11 changed. No single file moved by 0.13 KiB or more. Plus 11 files under the 0.13 KiB floor, net +0.15 KiB — usually content-hash churn in Worker bundle299.34 KiB → 299.50 KiB gzip (+0.16 KiB, +0.1%) Largest module deltas (raw bytes in bundle):
Dictionary transportFamily dictionary acquisition: no change, 14.50 KiB q11.
Head tags vs merge baseNo change. 77 documents, every title, description, canonical, robots, |
…opping 21px browser:check's first CI run read /access 0.000 and called its 0.03 shift budget stale, where 4 of 9 loads in the sandbox read 0.021. The shift depended on whether paint beat the script at the end of the page: that script fills an empty header strip above the graph with an SVG 1002 by 26, scaled to the pane, and the graph below dropped by its height. The strip reserves that aspect ratio while empty now, and 12 loads read 0.003 at most. The budget entry goes. The stale rule fires under half the limit, so a page sitting on the line (/lens/census, 0.011 against 0.01) cannot flap between failing and stale. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UnguFuTGB1AyfrTeixtbCT
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
aadhar-sh | 1ae47ff | Commit Preview URL Branch Preview URL |
Nov 10 2026, 08:02 PM |
#1635 and #1647 fixed what a hand crawl found, a page at a time. This keeps the crawl and fixes everything it flags today.
What changed
bun run browser:check(tools/check-browser.ts) opens all 76 manifest pages in Chrome and reads four things on each:scrollshiftintlerrorIt replaces
phone:check, which was the first of the four, and takes over its non-blocking CI job (nowbrowser check).config/browser-budget.jsonholds four exceptions, each with its reason. An entry a page no longer needs is itself a failure, so the file can only shrink.--base <url>reads a deployment in place of the local build.What
--base https://aadhar.shfound that a local run can't./aroundand/ledgerscroll sideways in production at every phone width (103px and 3px out at 390px). Both passed locally, where the harness's empty KV leaves their tables empty. Each table scrolls in its own box now.Everything else it flagged, fixed here:
/restore,/lens,/garage/blueprint,compression,dyno,masonry,octanemin-width: 0on a range input, tighter padding or wrapping under 340px/garage/round-trip/access/restoreWhy
Each defect class was invisible on a fast machine with a wide window, and each came back to "nobody opened the page the way a visitor does". The two production-only findings are the sharper version: a check with the wrong data passes.
Understanding check
browser:checknames that page and reading. Add a budget entry for a clean page and it reports the entry as stale.--baseexists and why three budget entries say "local fallback only"./garage/pretextread 0.056 in one sweep and 0.005 in six loads alone. A reading over the limit is taken a second time and judged on the lower one; a script that moves content after paint does it on every load, so it still fails./accessa 0.03 budget because it read 0.021 here; the first CI run read 0.000 there and called the budget stale. The page is fixed instead (second commit), and a budget now counts as stale only under half the limit, so a page on the line can't flap./accessbudget above./aroundand/ledgerDOM at 360px: main overflow 133px to 0 and 33px to 0, with the box scrolling./restore's hand-built dates matchtoLocaleDateString("en-US")for all 131 restore points./accessreads 0.003 at most in 12 loads./restoreshowed dates in the visitor's locale and shows en-US now./serendipity's Intl use (event times in the visitor's zone), which is real and stays. The other three entries are local-fallback shifts that production doesn't have.Validation
bun run browser:check: 76 pages, 0 failures, 0 stale budgets, every control caught.bun run lint,format:check,typecheck,derive:check,pages:check,check-wrangler: pass.bun run routes:check: 380 routes, 0 hard failures.bun run test: 1777 pass, 0 fail (Node 26).caltests pass.ci.yml: thephone-layoutjob becomesbrowser-check, still non-required withcontinue-on-error. Three contract tests that name the job and thenodescript follow./a/URL moves.🤖 Generated with Claude Code
https://claude.ai/code/session_01UnguFuTGB1AyfrTeixtbCT