Repository navigation
Page audit: backport React 19.3's hydration replay fix; a failed chunk reloads the page once - #605
Conversation
The page audit's last intermittent defect: React #418 on about 0.7% of signed-in loads, a different page each time, on a tree identical on the server and the client. The React that Next 15.5 bundles (19.2.0-canary-0bdb9206) replays a host element that suspended mid-hydration without rewinding the hydration cursor, so the replay tries to claim the element against its own first child. An instrumented build showed that shape in 7 of 7 hits. A webpack loader applies the upstream fix to Next's compiled react-dom-client (production and development, stable and experimental): before the replay, a host fiber that is the current hydration parent and has claimed a node puts the cursor back on that node. It fails the build, not silently, if Next's React changes shape, so an upgrade prompts its removal. The owner approved the backport. tests/react-hydration-replay-fix.test.ts holds that it applies to the installed React, lands at the top of replaySuspendedUnitOfWork, is idempotent, refuses a React it does not recognise, and is wired into the build. Verified in a production build: the framework chunk carries the rewind with its identifiers mapped to isHydrating, hydrationParentFiber, nextHydratableInstance and popToNextHostParent. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KP9rt5rVQ9jDMpZp2xBy3K
…or page reads at AA The production re-crawl (786 loads) hit it 8 times: one JavaScript chunk answered 502, and the page sat on "Something went wrong", whose Try again is reset(), which re-renders the same bundle and asks for the same chunk. The chunks answer 200 from Vercel on a re-fetch; the failure is transient (a request lost in transit, or a deploy replacing the chunk under an open tab), and only a reload recovers from it. Every error boundary (the root, the app, and each section's SectionError) now reloads the page once when the error is a chunk failure, and not again for the same page within a minute, so a chunk that is really gone shows the card instead of looping. The Kitchen Display keeps its own policy. The same crawl's axe pass caught the root error page's Try again button, white on #7c5dff at 4.31:1; it is the brand, #744be8, at 5.36:1, and the reference line moves from 4.35:1 to 5.59:1. tests/a-failed-chunk-reloads-the-page.test.ts holds the reload decision, that every boundary makes it, and both contrasts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KP9rt5rVQ9jDMpZp2xBy3K
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
|
The same upstream hydration replay defect is already covered by draft #602. Its combined candidate f9adfd7 includes #601's current 52d2a52 session/meal repairs and current main e96e745. It uses Next 16.3.6's shipped renderer, retains React 18 packages, and introduces no vendor patch. Independent results on that exact combined source: 20,856 UTC tests across 1,638 files; production build; full generated types; lint (15 existing warnings); production dependency audit (zero); and 278 controlled browser cases, including the actual renderer replay counterexample, session ownership and weekly meals. Route manifests lose zero application routes. Old #602 hosted CI passed with two retry-only flakes, so it is not being represented as clean acceptance of the combined source. Fresh combined hosted CI follows the final workflow/audit checkpoint. Please coordinate the framework files rather than merging both approaches: your loader deliberately rejects unknown renderer anchors and could collide with the already-fixed Next 16 renderer. The chunk-recovery and contrast changes here are separate and I am reviewing them for the next integration batch. #601 is already in fresh hosted CI and remains the next release candidate. We also found that package changes trigger the production migration workflow. The framework candidate is being guarded so all five mutation steps require an explicit manual boolean apply; automatic pushes retain read-only checks. No production SQL/retry or migration history change is authorized by this coordination. |
|
Independent review of the chunk-recovery portion at
I’m retaining the entrypoint regression and completing focused source/type/lint checks for the six chunk-recovery paths before the next integration batch. No authoritative source changes have been made by this review. |
|
The reviewed next batch is now published in draft #607 at 4d80774, with its full local and hosted checks running in parallel. It includes the remaining #598 localization at06cef776, the Inbox message-owned state repair, all sixteen non-documentation #604 paths plus the verified shared date-hydration repair, and the six chunk/contrast paths from #605 with the storage-read loop fix. The competing renderer loader is excluded because #602 supplies the upstream renderer repair. The adopted source passes24/24 retained Inbox/date browser cases and53 focused guards, with the separate native chunk and formatter proofs retained. finalaudit.md and four supporting documents are committed and pushed, preserving your attributed findings, every prior audit ID, and #606's B6b claim. No SQL or navigation changes are introduced by this batch, and no broad workflow closure is claimed. #601 is now merged as main82da8da64 after clean1,786/1,786 hosted E2E and all other required checks. Production verification is pending. Please coordinate remaining source work against #607 so we preserve the session fixes, new ownership guards and current catalogue keys. #602 and #607 still require their own complete gates before release. |
… that has it alone Review on #605 pointed out that Next 16 (#602) bundles a React that already fixes react/react#37584, and that the loader would reject it. Reading that React (Next 16.3.6's react-dom-client, 19.3.0-canary-cbb046ab) shows where React put the fix: in the replay's HostComponent case, right after the hooks reset, the replayed fiber that is the current hydration parent puts the parent back on its host parent and the cursor back on its node, or resumes hydration if it had been suspended for an insertion below it. The loader now injects exactly that code at exactly that site in Next 15.5's React (production and development, stable and experimental). The hydration helpers it calls (popToNextHostParent, tryToClaimNextHydratableInstance, resetHydrationState, popHydrationState) are identical in 19.2 and 19.3. A React whose site already carries the fix is returned unchanged, so #602 can land after this without touching it; a React without the site still fails the build. The test adds Next 16's case verbatim as a fixture that must come back unchanged, checks the injection sits between the hooks reset and the default branch, and parses the patched React. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KP9rt5rVQ9jDMpZp2xBy3K
|
Thanks, both points were right. Both are addressed in Loop fix. I've adopted #607's Loader vs Next 16. I read Next 16.3.6's own
So #602 can land after this with no collision. Evidence for the first form of the backport (a rewind at the top of the function): a local production build ran the #418 hunt, 273 signed-in routes × 3 rounds at 4 in parallel, and got 0 of 819, against 7 of 819 unpatched. The React-19.3-shaped injection gets the same hunt on a fresh build before I merge. Generated by Claude Code |
|
The user has now requested that all open PR work be reconciled into main and deployed. The current main audit checkpoint is4123f13 (#608); production session/meal/page repairs from#601 are verified on82da. #602 carries the Next16 renderer fix and a default-false manual production-SQL apply guard. #607 carries repaired Inbox ownership, shared date hydration, localized controls, and the corrected marketplace test fixture (20,871 unit tests now pass). I am reconciling these branches for release. Please preserve the newer main/607 session, Inbox, Modal, formatter, and cache guards when resolving overlaps. Pending SQL must remain unapplied; no production migration dispatch is authorized by this release coordination. Additional unique changes will be reviewed and integrated, with superseded alternatives recorded explicitly. Please keep finalaudit.md claims and prior failures intact. |
tests/ordering-guards-fail-on-absence.test.ts holds every ordering assertion to at()/between() from tests/helpers/source-order.ts, since a bare indexOf answers -1 for an absent needle and passes. The placement check now asserts that the fix follows the hooks reset directly and ends before the default branch, with both needles required to be present. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KP9rt5rVQ9jDMpZp2xBy3K
…entation-ld8bon # Conflicts: # components/app/section-error.tsx
Main's #605 test asserted the installed react-dom client did not already carry react/react#37584's fix. Next 16.3.6 bundles React 19.3, which does, so the test failed on this branch in CI. It now asserts the installed React carries the fix and that the loader leaves it byte-identical, and still exercises the backport on the same file with React's fix removed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01776xJyhVe8xJQvTGeNfT9T
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01776xJyhVe8xJQvTGeNfT9T
Main's #605 test asserted the installed react-dom client did not already carry react/react#37584's fix. Next 16.3.6 bundles React 19.3, which does, so the test failed on this branch in CI. It now asserts the installed React carries the fix and that the loader leaves it byte-identical, and still exercises the backport on the same file with React's fix removed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01776xJyhVe8xJQvTGeNfT9T
Production at fda9dcf, signed out, all 393 routes at phone and desktop (786 loads), and a local production build of the same source, signed in as a parent and super admin with every migration to 0458 applied locally, the same 786 loads. Signed in: 0 axe violations, 0 overflow, 0 page errors, 0 5xx. Production: every route gave the right answer; 30 loads had one subresource answer 502 or time out through this sandbox's relay (which logged its own tunnel failures to www.bubaly.com at the same minutes; the deployment's chunks answered 200 90 of 90 times fetched directly), and every one was clean on a serial retry. The intermittent React #418 (the eight OWNER rows and the row a CI run had opened on /dashboard/sleep) is closed by #605's backport of React 19.3's own fix: the #418 hunt went from 7 of 819 to 0 of 819, and 0 of 270 on the nine pages it had struck. The findings table records the backport, the chunk failure that sat on the error page and its fix, the error page's contrast, and this re-crawl; the rows #591 left "re-crawl pending" and three another session left "not yet" (their fixes merged in #585/#603) are live and re-crawled. Lanes B-F are released. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KP9rt5rVQ9jDMpZp2xBy3K
…ation-ld8bon finalaudit: every page re-crawled after #605 — all 398 rows clean
Two fixes from the page audit (finalaudit.md, "Page Audit — every page on www.bubaly.com"). main (#601) is merged in.
React #418: backport React 19.3's fix for react/react#37584 (owner-approved)
The audit's last intermittent defect: React #418 on about 0.7% of signed-in loads, a different page each time, on a tree identical on the server and the client (8 rows 🔒 OWNER in the ledger).
The React that Next 15.5 bundles (
19.2.0-canary-0bdb9206) has a bug. When a host element suspends mid-hydration, React replays it without rewinding the hydration cursor, and the replay tries to claim the element against its own first child. An instrumented build showed that pattern in 7 of 7 hits.scripts/react-hydration-replay-fix.cjsis a webpack loader. It injects the fix React itself shipped, read from Next 16.3.6's bundled React19.3.0-canary-cbb046ab. The fix goes at the same place React put it: the replay's HostComponent case, right afterresetHooksOnUnwind. It applies to Next 15.5'sreact-dom-client, production and development, stable and experimental. The hydration helpers the fix calls are identical in 19.2 and 19.3.next.config.mjsadds awebpack()hook with one rule for those files. It touches no hunk that Fix hydration replay with Next 16 #602 changes.tests/react-hydration-replay-fix.test.tschecks:default:;case 5:al(n);var r=n;r===rP&&(rL?(rM(r),5===r.tag&&null!=r.stateNode&&(rN=r.stateNode)):(rM(r),rL=!0));default:….A chunk that fails to load reloads the page once; the root error page reads at AA
The production signed-out re-crawl (393 routes × phone and desktop, 786 loads) hit 8 loads where one JavaScript chunk answered 502. Each of those pages sat on "Something went wrong", whose Try again re-renders the same bundle and fails again. The chunks answer 200 on a re-fetch.
lib/utils/stale-bundle-reload.tshandles the reload:app/global-error.tsx,app/error.tsx,app/(app)/error.tsxandSectionError, which covers every section boundary. The Kitchen Display keeps its own policy.#7c5dff, 4.31:1. It now uses the brand#744be8, 5.36:1. The reference line goes from 4.35:1 to 5.59:1.Checks run
tscon the changed files: clean.next build: passes.🤖 Generated with Claude Code
https://claude.ai/code/session_01KP9rt5rVQ9jDMpZp2xBy3K