Skip to content

fix(cache): compare tag revalidation timestamps - #2916

Open
JamesbbBriz wants to merge 7 commits into
cloudflare:mainfrom
JamesbbBriz:codex/fix-cache-tag-revalidation-timestamps
Open

fix(cache): compare tag revalidation timestamps#2916
JamesbbBriz wants to merge 7 commits into
cloudflare:mainfrom
JamesbbBriz:codex/fix-cache-tag-revalidation-timestamps

Conversation

@JamesbbBriz

@JamesbbBriz JamesbbBriz commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Summary

  • record request-local tag revalidations with timestamps instead of membership only
  • capture each cache fill's causal timestamp at the producer, before user work starts, then pass it through the cache adapter unchanged
  • persist and return producer timestamps in Memory and Cloudflare KV while keeping adapter-owned writtenAt for TTL accounting
  • apply the same ordering contract to use cache, unstable_cache, tagged fetch, App/Pages ISR, Route Handlers, and metadata routes
  • discard entries only when they predate the latest matching revalidation, including fills that straddle an invalidation
  • securely forward revalidated-tag state across internal Server Action redirect dispatches without exposing protocol headers to application code
  • preserve comma-containing tags losslessly in a separate authenticated vinext JSON header while retaining the Next.js comma-delimited header for ordinary-tag rolling compatibility

This follows the behavior introduced by vercel/next.js#96726 and commit 5da1c1ae03d2ee39c27a2d6d8807c573c46b37f9.

The separate JSON tag header is a deliberate vinext protocol extension: Next.js's comma-delimited wire format cannot represent a legal tag containing a comma. New vinext peers prefer the authenticated JSON header; the standard header remains available to older peers for ordinary tags. Older peers cannot preserve comma-containing tags.

Closes #2819

Tests

  • 17-file cache/ISR/action/router matrix passed, including the required isr-cache, fetch-cache, and kv-cache-handler coverage
  • focused producer-ordering tests prove App Route and metadata timestamps are captured before user handlers run
  • vp check passed for all 26 changed product/test files
  • git diff --check passed

Adversarial coverage includes invalidation during a fill and immediately before a new fill, repeated same-tag invalidation, all three public cache APIs, App/Pages foreground and background ISR writes, Route Handlers, metadata routes, two-read Server Action dedupe, custom-handler old/new timestamps, authenticated redirect forwarding, comma-containing and JSON-looking legacy tags, protocol-header filtering, soft/hard tags, and Memory/KV strict timestamp boundaries.

@JamesbbBriz

Copy link
Copy Markdown
Contributor Author

/bigbonk

@pkg-pr-new

pkg-pr-new Bot commented Aug 14, 2026

Copy link
Copy Markdown

Open in StackBlitz

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

commit: 729fdb7

@github-actions

github-actions Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Performance benchmarks

Compared 729fdb7 against base a3d1d1d 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 135.4 KB 136.3 KB ⚫ +0.6%
Client entry size (gzip) vinext 122.8 KB 123.6 KB ⚫ +0.7%
Dev server cold start vinext 3.07 s 3.05 s ⚫ -0.6%
Production build time vinext 3.38 s 3.39 s ⚫ +0.3%
RSC entry closure size (gzip) vinext 114.6 KB 115.6 KB ⚫ +0.8%
Server bundle size (gzip) vinext 194.8 KB 196.2 KB ⚫ +0.7%

View detailed results and traces

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

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dab5b34173

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/vinext/src/shims/cache-request-state.ts
@JamesbbBriz

Copy link
Copy Markdown
Contributor Author

/bigbonk

@JamesbbBriz

Copy link
Copy Markdown
Contributor Author

CI follow-up: fixed the integration failure by separating high-resolution mutation ordering (lastModified) from wall-clock TTL policy (writtenAt) in both Memory and KV handlers. Existing KV entries remain compatible via the lastModified fallback. Local verification: exact failed sequence 2/2, full features file 355/355, related 8-file matrix 1,903/1,903, scoped checks/diff-check, and independent Standards + blast-radius reviews pass. Waiting for CI; not requesting re-review yet.

@JamesbbBriz

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dbd28c1de2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/vinext/src/server/app-rsc-handler.ts Outdated
Comment thread packages/vinext/src/server/revalidated-tags.ts
@JamesbbBriz

JamesbbBriz commented Aug 15, 2026

Copy link
Copy Markdown
Contributor Author

@james-elicx I think this is ready for another look now. I fixed the latest ISR review comments, and CI is green. Thanks!

@NathanDrake2406

Copy link
Copy Markdown
Contributor

I think we should generate the timestamp and pass it through the adapter, then have it persist and return that instead

@JamesbbBriz

Copy link
Copy Markdown
Contributor Author

Updated in fe528e1. Cache producers now capture the timestamp before the fill starts and pass it through set(); Memory and KV persist and return it unchanged, while writtenAt remains adapter-owned for TTL accounting. I also carried the same boundary through App/Pages ISR, Route Handlers, metadata routes, use cache, unstable_cache, and tagged fetch, with ordering tests for both sides of an invalidation.

@JamesbbBriz

Copy link
Copy Markdown
Contributor Author

@james-elicx I've incorporated Nathan's adapter feedback and fixed the one stale seed-cache assertion caught by CI. The full check suite is green on 729fdb7 now. Thanks for the patience - whenever you have time, this should be ready for another look.

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.

Cache: discard only 'use cache' entries that predate a tag revalidation (timestamp-compare, not tag membership)

2 participants