fix(frontend): cache the session server snapshot (2 more 'known noise' entries were real) - #64
Merged
Merged
Conversation
getServerSnapshot returned Promise.resolve(null) from its body, minting a fresh promise on every call. useSyncExternalStore compares snapshots with Object.is and use() needs a promise identity it can resolve against a cache, so this single site produced both console errors the project had learned to ignore: The result of getServerSnapshot should be cached to avoid an infinite loop A component was suspended by an uncached promise React's own wording -- "to avoid an infinite loop" -- says this was never cosmetic. There is no server session to report (the cookie is read by the browser), so one resolved-null promise is the correct snapshot. Verified in real Chrome over CDP, landing page plus a client-side transition to a report: main emits 4 console errors, this branch emits 1 (the Base UI nativeButton warning, which #62 fixes). Also rewrites the known-noise list in .claude/skills/verify that hid both of these. Three of its four entries were real bugs; only the anonymous 401 on /me is genuinely inert. Baseline is now 1 expected entry, not 4. Adds the two process rules this session paid for: verify portal/layout/paint claims in the browser rather than vitest, and drive route changes through the app's own UI rather than Page.navigate.
Shaan-alpha
added a commit
that referenced
this pull request
Jul 31, 2026
Three of the four entries on the verify skill's known-noise console list were real bugs. Also removes a duplicated changelog bullet introduced when the withdrawn finding-2 line was edited out.
This was referenced Jul 31, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Came out of auditing the known-noise console list in
.claude/skills/verify— the list that had been hiding #62's a11y defect. Two more of its four entries turned out to be one real bug.Root cause — one line, two symptoms
getServerSnapshotreturnedPromise.resolve(null)from its body, minting a fresh promise on every call:useSyncExternalStorecompares snapshots withObject.is, anduse()needs a promise identity it can resolve against a cache. That single site produced both of these:React's own wording — "to avoid an infinite loop" — says this was never cosmetic. It had been on the ignore list since the skill was written.
There is no server session to report (the cookie is read by the browser), so a single module-level resolved-null promise is the correct snapshot.
getSnapshotwas already correctly cached via the module-levelcachedPromise; only the server path was wrong.use()appears exactly once in the codebase, which is why one fix clears both messages.Verified in a browser, both directions
Landing page plus a client-side transition to a report, console events grouped by message:
mainuncached promisegetServerSnapshot should be cachednativeButtonRewrites the list that hid this
.claude/skills/verifytold every future agent to treat four console errors as background noise and only "check the count didn't grow". Three of the four were real bugs. The list now:401on/meas genuinely inert, with the reason (an anonymous visitor has no session;fetchSessionFreshhandles it and returns null),It also gains the two process rules this session paid for the hard way:
<Activity>popover "leak" was chased and a fix written on jsdom evidence before Chrome showed the bug did not exist (see fix(frontend): badge trigger is not exposed as a button (audit finding 3) #62).Page.navigate. A full document load tears down client state and the App Router's<Activity>boundaries, so any test about back/forward or preserved state passes silently while proving nothing.No unit test, deliberately
The invariant is a promise's referential stability across React's SSR/hydration path.
getServerSnapshotis module-private, and reproducing the warning in vitest would mean a full server-render-plus-hydrate harness for a one-line constant — and happy-dom is exactly the environment I have just been burned trusting for this class of question. The guard is the CDP console baseline above, which the verify skill now states as a hard number rather than a vague "didn't grow".Verification
vitest run73 passed / 23 files,tsc --noEmitclean,eslint srcclean, plus the CDP runs above against both branches.Merge order
CI stays red on Backend until #60 merges. No file overlap with #59, #60, #61, #62 or #63.
CHANGELOG/PROGRESS_LOGentries for the batch are consolidated in #59.