Skip to content

fix(cache): gate CDN admission on probed routes - #3092

Open
james-elicx wants to merge 20 commits into
codex/cacheability-probe-protocolfrom
codex/cacheability-manifest-admission
Open

fix(cache): gate CDN admission on probed routes#3092
james-elicx wants to merge 20 commits into
codex/cacheability-probe-protocolfrom
codex/cacheability-manifest-admission

Conversation

@james-elicx

@james-elicx james-elicx commented Aug 26, 2026

Copy link
Copy Markdown
Member

Capability stack 4/9. Exact head: f50e5a1d7526ec067df7306085c5f05d253e457d. Base: #3091.

Full chain: #3108#3090#3091#3092#3103#3093#3094#3098#3113.

Summary

  • emit an inert cacheability-manifest ESM module in App Router Worker builds
  • admit exact manifest identities only after the ordinary response completes cleanly
  • preserve a safe no-manifest fallback by buffering one bounded cold response to EOF before applying its proven static policy
  • apply the same completed-response boundary to potentially cacheable App Route Handlers, matching Next.js response draining before static completion
  • convert late Route Handler stream errors into uncached 500 responses and observe dynamic request reads made during stream consumption
  • keep the Cloudflare adapter's provisional responses private until the outer admission boundary completes
  • preserve independently classified Pages Router responses when hybrid routing hands off outside the App-only admission layer
  • preserve every explicit handler-owned public or private cache policy on ordinary origin-managed requests, matching Next.js, while retaining adapter-owned fail-closed policy during CDN probe/admission
  • cap capture at 4 MiB per response and 16 MiB across concurrent isolate requests
  • replay captured chunks without allocating a second contiguous body

Fail-closed behavior

  • an identity absent from a present manifest is no-store
  • malformed, wrong-build, dynamic, contextual RSC, slow, oversized, incomplete, or middleware-eligible requests remain private
  • middleware has/missing conditions are evaluated by pathname eligibility, not only by the probe request's current headers
  • conditional redirects, rewrites, and response headers cannot become shared responses
  • framework-owned provisional no-store may be replaced after proof, while application/config/private policy remains an absolute veto
  • a final ordinary response is revalidated independently of the earlier probe
  • CDN purge is safe because every refill repeats completed-response admission

The manifest is a Worker module asset containing classification only—never response bodies. Origin-managed/KV adapters retain their existing streaming path.

Next.js reference

Next.js drains cacheable App Route Handler responses before resolving static generation (packages/next/src/server/route-modules/app-route/module.ts). The built-workerd regression here covers late stream request reads and late stream failure at that same completion boundary.

Review guide

  1. cacheability-manifest.ts validates the embedded artifact.
  2. cacheability-request.ts owns exact matching, capture limits, and admission.
  3. app-route-handler-execution.ts completes potentially cacheable Route Handler bodies before public admission.
  4. app-router-entry.ts gates obvious non-page requests before loading admission code.
  5. cdn-adapter.runtime.ts fails closed while classification is pending.
  6. The built-workerd suites prove App Page and Route Handler completion behavior.

This PR does not alter cache keys, response Vary, Worker entrypoints, or request routing. Existing framework and adapter Vary replacement semantics are unchanged.

Review size

Layer-only diff against this PR's base: 47 files, +2,723/-76.

Validation

  • current full-stack cumulative changed-file suites — 2,864/2,864
  • current full-stack PPR probe/admission/Pages built-workerd E2E — 8/8
  • current full-stack vp check and git diff --check
  • layer exact-head CI and deploy previews are green

@pkg-pr-new

pkg-pr-new Bot commented Aug 26, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@vinext/cloudflare@3092
npm i https://pkg.pr.new/create-vinext-app@3092
npm i https://pkg.pr.new/@vinext/types@3092
npm i https://pkg.pr.new/vinext@3092

commit: f50e5a1

@github-actions

github-actions Bot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Performance benchmarks

Compared f50e5a1 against base 1634073 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 142.2 KB 142.3 KB ⚫ +0.0%
Client entry size (gzip) vinext 129.5 KB 129.5 KB ⚫ -0.0%
Dev server cold start vinext 3.10 s 3.08 s ⚫ -0.5%
Production build time vinext 3.31 s 3.32 s ⚫ +0.2%
RSC entry closure size (gzip) vinext 117.5 KB 118.8 KB ⚫ +1.1%
Server bundle size (gzip) vinext 199.3 KB 202.1 KB ⚫ +1.4%

View detailed results and traces

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

@james-elicx
james-elicx force-pushed the codex/cacheability-manifest-admission branch from 266ed64 to 17fd250 Compare August 26, 2026 10:51
@github-actions

github-actions Bot commented Aug 26, 2026

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
workers-cache preview production
static-export preview production
web preview production

@james-elicx
james-elicx force-pushed the codex/cacheability-manifest-admission branch from 17fd250 to bf4c4aa Compare August 26, 2026 14:45
@james-elicx james-elicx reopened this Aug 26, 2026
@james-elicx
james-elicx force-pushed the codex/cacheability-manifest-admission branch from bf4c4aa to c4470f4 Compare August 26, 2026 17:09
@james-elicx
james-elicx force-pushed the codex/cacheability-manifest-admission branch from c4470f4 to c308688 Compare August 26, 2026 17:47
@james-elicx
james-elicx force-pushed the codex/cacheability-manifest-admission branch from c308688 to a968165 Compare August 26, 2026 18:29
@james-elicx
james-elicx force-pushed the codex/cacheability-manifest-admission branch from a968165 to 9b5d065 Compare August 26, 2026 19:33
@james-elicx
james-elicx force-pushed the codex/cacheability-manifest-admission branch 2 times, most recently from 0b0624c to 7866c95 Compare August 26, 2026 21:10
@james-elicx
james-elicx force-pushed the codex/cacheability-manifest-admission branch from 7866c95 to 3c43c25 Compare August 26, 2026 21:27
@james-elicx
james-elicx marked this pull request as ready for review August 26, 2026 22:08
@james-elicx
james-elicx force-pushed the codex/cacheability-manifest-admission branch from c771cb2 to a430639 Compare August 26, 2026 23:25
@james-elicx

Copy link
Copy Markdown
Member Author

/bigbonk review for issues. Hard time limit: 20 minutes; return all findings or a partial review by then.

@ask-bonk

ask-bonk Bot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

@james-elicx Bonk workflow was cancelled.

View workflow run · To retry, trigger Bonk again.

@james-elicx
james-elicx force-pushed the codex/cacheability-manifest-admission branch from 549601d to 92aa5ce Compare August 27, 2026 00:58
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