You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
PPR capture: tags recorded after an await in async shell content miss the shell tag snapshot #676
A cacheTag() recorded only AFTER an await inside an async server component that renders into a PPR shell is not collected into the shell entry — revalidateTag() with that tag will not evict the shell. Synchronous recording (the canonical #648 form) works; the loss is silent and async-only.
Mechanism
The shell capture snapshots the derived context's _requestTags synchronously at collection time (shell-capture.ts — the collected = [...derivedCtx._requestTags] at the putShell site). React renders synchronous components before that snapshot, so their tags land; a tag recorded after an await (microtask or later) lands after the snapshot and is dropped. Pre-existing behavior: async cache()/"use cache" reads at capture share the same window (their propagated tags can also post-date the snapshot). The document cache does NOT share the edge — it buffers the full response body before collectRequestTags, so late tags are included there.
Documented as a known edge in packages/rangojs-router/docs/design/ppr-shell-resume.md ("A tag recorded only AFTER an await …", ~line 370), landed with the render-callable cacheTag() work (#648).
Fix direction
Defer the shell's tag snapshot to a render-complete barrier (the capture already has quiesce machinery — handles settled + Flight task-quiet; the tag snapshot can move behind the same gate), mirroring the document cache's buffer-then-collect ordering. The capture's write path already awaits quiesce before putShell, so the move is ordering-only — no new synchronization.
Acceptance
Unit (shell-capture suite): an async shell component recording a tag after an await → tag present on the stored ShellCacheEntry; an async "use cache" read at capture → its tags present.
The existing sync-tag tests and the hole/bake invariant tests stay green (a hole still cannot tag — masked loaders never execute regardless of snapshot timing).
e2e (dev + production, cloudflare-basic): extend ppr-tag-eviction.test.ts with an async-recorded tag eviction case.
Notes
Severity: low until async render-recorded shell tags become load-bearing — the sync form covers the canonical use, and data-driven eviction via "use cache" tags recorded on HIT reads is unaffected outside capture.
Activity
fix(ppr): collect shell tags at the putShell barrier so async-recorde…