Skip to content

feat(app-router): skip core cache writes without a negative searchParams proof - #3456

Draft
james-elicx wants to merge 3 commits into
isr-query/07-client-page-search-paramsfrom
isr-query/06-core-write-safety-net
Draft

james-elicx wants to merge 3 commits into
isr-query/07-client-page-search-paramsfrom
isr-query/06-core-write-safety-net

Conversation

@james-elicx

@james-elicx james-elicx commented Sep 25, 2026 •

Copy link
Copy Markdown
Member

Stacked on #3457. Third part of plan PR 1 (cache-candidate SSR mode): the safety net in core's writes. It sits on the client-page PR (#3457), so a static client page that never reads searchParams still has a proof and is still stored.

Problem

Core stores one HTML entry and one RSC entry per App page, and every query shares them. The read side already refuses to serve a stored entry to a query-bearing request unless its render observation proves searchParams went unread. The write side had no matching check, so a render that read the query could still be stored under the query-free key.

Change

Core's five request-time and regeneration writes now store a render only when its observation has a complete negative searchParams proof (hasQueryInvariantRenderProof, built on hasCompleteNegativeRequestApiProof):

  • the finalizer's HTML write and the RSC write made with it (both skip together);
  • the finalizer's RSC-only write;
  • the stale regeneration's HTML and RSC writes (both skip together).

Response headers don't change. The read side reuses the same helper.

The observation builders (createHtmlRenderObservation, createRscRenderObservation) and the regeneration result's observations are now required, because a write path that supplies no observation is a bug.

A regeneration that reads searchParams is no longer stored. It renders with an empty query, and Next.js treats a searchParams read as dynamic, so it never stores that render either.

Tests

  • tests/app-page-cache.test.ts: a render that read searchParams skips each write (HTML finalizer for either observation, RSC-only, regeneration for HTML, RSC, and an RSC-triggered regen), and the HTML finalizer's response headers match the stored case. Mutating the helper to always pass fails all of them.
  • tests/app-page-cache-render.test.ts: a static regeneration's real HTML and RSC observations carry the proof, so it's still stored.
  • tests/app-page-dispatch.test.ts: a stale regeneration that reads searchParams in the page or in metadata writes nothing.
  • The existing static-render store tests in app-page-render and app-page-dispatch still write with real observations.
  • The Response Store e2e (examples/response-store-demo) passes: 26 tests.

@james-elicx

Copy link
Copy Markdown
Member Author

/bigbonk review for issues

Please review exact head e1877bf00c2f2357273665b9ea1bbec81bbe01f9 without modifying or pushing the branch. Report all actionable findings within your 8-minute time limit.

@pkg-pr-new

pkg-pr-new Bot commented Sep 25, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

@vinext/cloudflare

npm i https://pkg.pr.new/@vinext/cloudflare@3456

create-vinext-app

npm i https://pkg.pr.new/create-vinext-app@3456

@vinext/types

npm i https://pkg.pr.new/@vinext/types@3456

vinext

npm i https://pkg.pr.new/vinext@3456

@cloudflare/workers-response-store

npm i https://pkg.pr.new/@cloudflare/workers-response-store@3456

commit: 41a9c1a

await expect(response.text()).resolves.toBe("<h1>fresh</h1>");
await proven.text();
await Promise.all(pendingCacheWrites);
expect(isrSet.mock.calls.map(([key]) => key)).toEqual(["html:/fresh", "rsc:/fresh"]);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

vp check fails here with TS2493 because vi.fn(async () => {}) infers a zero-argument mock, so each recorded call has tuple type [] and cannot be destructured as [key]. Please type the mock with AppPageCacheSetter (or give the callback the setter parameters) so the required check passes.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in cfffc4f. The mock is now typed as vi.fn<AppPageCacheSetter>(async () => {}), so its recorded calls destructure as [key].

@ask-bonk

ask-bonk Bot commented Sep 25, 2026

Copy link
Copy Markdown
Contributor

Submitted 1 inline finding. Focused tests pass; vp check fails on the reported TypeScript error.

github run

@github-actions

github-actions Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

Performance benchmarks

Compared 41a9c1a against base 81608d3 using alternating same-runner rounds. Next.js was unchanged and skipped.

0 improved · 0 regressed · 6 within ±1.5%

Scenario Framework Baseline Current Change
Client bundle size (gzip) vinext 143.1 KB 143.4 KB ⚫ +0.2%
Client entry size (gzip) vinext 130.9 KB 131.5 KB ⚫ +0.4%
Dev server cold start vinext 3.43 s 3.38 s ⚫ -1.4%
Production build time vinext 3.93 s 3.91 s ⚫ -0.5%
RSC entry closure size (gzip) vinext 133.1 KB 133.2 KB ⚫ +0.1%
Server bundle size (gzip) vinext 233.9 KB 234.3 KB ⚫ +0.2%

View detailed results and traces

🟢 improvement · 🔴 regression · ⚫ change below 1.5% · paired base/head

@james-elicx
james-elicx force-pushed the isr-query/06-core-write-safety-net branch from e1877bf to cfffc4f Compare September 25, 2026 02:06
@james-elicx

Copy link
Copy Markdown
Member Author

/bigbonk review for issues

Please review exact head cfffc4febe5f283039e8c0467c29a8422fec5d66 without modifying or pushing the branch. Report all actionable findings within your 8-minute time limit.

@github-actions

Copy link
Copy Markdown
Contributor
Example Preview Production Original
app-router-cloudflare preview production
pages-router-cloudflare preview production
app-router-playground preview production original
realworld-api-rest preview production
nextra-docs-template preview production
benchmarks preview production
hackernews preview production original
response-store-demo preview production
workers-cache preview production
kv preview production
static-export preview production
web preview production

@ask-bonk

ask-bonk Bot commented Sep 25, 2026

Copy link
Copy Markdown
Contributor

LGTM!

github run

@james-elicx
james-elicx force-pushed the isr-query/06-core-write-safety-net branch from cfffc4f to c864935 Compare September 25, 2026 02:18
@james-elicx
james-elicx changed the base branch from isr-query/05-candidate-ssr-gates to isr-query/07-client-page-search-params September 25, 2026 02:18
@james-elicx
james-elicx force-pushed the isr-query/06-core-write-safety-net branch from c864935 to 7e47900 Compare September 25, 2026 03:08
@james-elicx

Copy link
Copy Markdown
Member Author

/bigbonk review for issues

Please review exact head 7e47900ab5062cfa04b3430ab50d7609fcd139b9 without modifying or pushing the branch. Report all actionable findings within your 8-minute time limit.

@ask-bonk

ask-bonk Bot commented Sep 25, 2026

Copy link
Copy Markdown
Contributor

LGTM!

github run

@james-elicx
james-elicx force-pushed the isr-query/06-core-write-safety-net branch from 7e47900 to d6e9d38 Compare September 25, 2026 03:28
@james-elicx

Copy link
Copy Markdown
Member Author

/bigbonk review for issues

Please review exact head d6e9d3800f0374a39421d744a6681b15bce37cdf without modifying or pushing the branch. Report all actionable findings within your 8-minute time limit.

@ask-bonk

ask-bonk Bot commented Sep 25, 2026

Copy link
Copy Markdown
Contributor

LGTM!

github run

@james-elicx
james-elicx force-pushed the isr-query/06-core-write-safety-net branch from d6e9d38 to 037b17b Compare September 25, 2026 04:12
@james-elicx

Copy link
Copy Markdown
Member Author

/bigbonk review for issues

Please review exact head 037b17b97c248ec7e3872d3fc9ac3cd649bd3d3f without modifying or pushing the branch. Report all actionable findings within your 8-minute time limit.

@ask-bonk

ask-bonk Bot commented Sep 25, 2026

Copy link
Copy Markdown
Contributor

LGTM!

github run

@james-elicx
james-elicx force-pushed the isr-query/06-core-write-safety-net branch from 037b17b to f69afb4 Compare September 25, 2026 04:44
@ask-bonk

ask-bonk Bot commented Sep 25, 2026

Copy link
Copy Markdown
Contributor

LGTM!

github run

@james-elicx
james-elicx force-pushed the isr-query/06-core-write-safety-net branch from 99264c9 to e21ad6d Compare September 25, 2026 11:05
@james-elicx

Copy link
Copy Markdown
Member Author

/bigbonk review for issues

Please review exact head e21ad6d09053d38d82c791f3474e70c7e1b23618 without modifying or pushing the branch. Report all actionable findings within your 8-minute time limit.

@ask-bonk

ask-bonk Bot commented Sep 25, 2026

Copy link
Copy Markdown
Contributor

LGTM!

github run

@james-elicx
james-elicx force-pushed the isr-query/06-core-write-safety-net branch from e21ad6d to bcc0485 Compare September 25, 2026 11:48
@james-elicx

Copy link
Copy Markdown
Member Author

/bigbonk review for issues

Please review exact head bcc0485416286eaadedd8904f26889cf6b5e3c39 without modifying or pushing the branch. Report all actionable findings within your 8-minute time limit.

@ask-bonk

ask-bonk Bot commented Sep 25, 2026

Copy link
Copy Markdown
Contributor

LGTM!

github run

@james-elicx
james-elicx force-pushed the isr-query/06-core-write-safety-net branch from bcc0485 to 91fdf78 Compare September 25, 2026 12:28
@james-elicx

Copy link
Copy Markdown
Member Author

/bigbonk review for issues

Please review exact head 91fdf78d7ba1f1738084a5724292bcba078ffa90 without modifying or pushing the branch. Report all actionable findings within your 8-minute time limit.

@ask-bonk

ask-bonk Bot commented Sep 25, 2026

Copy link
Copy Markdown
Contributor

LGTM!

github run

@james-elicx
james-elicx force-pushed the isr-query/06-core-write-safety-net branch from 91fdf78 to 71d5de5 Compare September 25, 2026 13:18
@james-elicx

Copy link
Copy Markdown
Member Author

/bigbonk review for issues

Please review exact head 71d5de5135b02a25e17e0aab1e89a79aa75020c6 without modifying or pushing the branch. Report all actionable findings within your 8-minute time limit.

@ask-bonk

ask-bonk Bot commented Sep 25, 2026

Copy link
Copy Markdown
Contributor

LGTM!

github run

@james-elicx
james-elicx force-pushed the isr-query/06-core-write-safety-net branch from 71d5de5 to 161dc34 Compare September 25, 2026 13:54
@james-elicx

Copy link
Copy Markdown
Member Author

/bigbonk review for issues

Please review exact head 161dc34f7f0a7eb8ecbc85dd50bd2da59aef9750 without modifying or pushing the branch. Report all actionable findings within your 8-minute time limit.

@ask-bonk

ask-bonk Bot commented Sep 25, 2026

Copy link
Copy Markdown
Contributor

LGTM!

github run

@james-elicx
james-elicx force-pushed the isr-query/06-core-write-safety-net branch from 161dc34 to 49ceec8 Compare September 25, 2026 14:49
@james-elicx

Copy link
Copy Markdown
Member Author

/bigbonk review for issues

Please review exact head 49ceec81d5d0e58d992d7370c152338b29fe6d21 without modifying or pushing the branch. Report all actionable findings within your 8-minute time limit.

@ask-bonk

ask-bonk Bot commented Sep 25, 2026

Copy link
Copy Markdown
Contributor

LGTM!

github run

…ams proof

Every query shares an App page's HTML and RSC entries, so core's five
request-time and regeneration writes now store a render only when its
observation proves searchParams went unread. The observation builders
are required, since a write path without one is a bug.
@james-elicx
james-elicx force-pushed the isr-query/06-core-write-safety-net branch from 49ceec8 to 41a9c1a Compare September 25, 2026 15:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant