Conversation
Contributor
Tests PassedCommit: 78df9b6 |
gnoff
added a commit
that referenced
this pull request
Sep 20, 2026
Bring in the standalone closed-route revalidation fix from #98964 and use the same pre-cache admission boundary for the API-specific development matching result. Preserve the separate normal development render path and the selected specialized matcher policy in production. Extend the routing fixture to revalidate build-seeded and runtime-generated outputs beneath closed prefixes, invalidate a shared dynamic-tail shell without capturing either request value, and prove invalidating unlisted URLs never admits them. These API-only checks remain in this layer rather than the unflagged prerequisite. The new lifecycle checks and existing runtime-policy suite pass with fresh-native Turbopack and Webpack with Partial Prefetching disabled. The two previously identified percent-encoding failures remain unchanged; fully closed revalidation and expected routing-miss logging now pass.
gnoff
added this pull request to stack #98967
September 20, 2026 20:01
Determine whether a URL is admitted from the build manifest before looking up its ISR entry. A build-generated /closed/known must remain valid after revalidatePath expires its content or an external cache loses the entry; an unlisted URL must be rejected without a cache lookup or page render. Regenerate admitted fallback-false paths with a blocking render instead of treating their missing content as an unknown route. Cache contents no longer authorize otherwise closed paths during on-demand revalidation. This uses existing manifest metadata and does not change the adapter contract. Add real production fixtures covering repeated invalidation, catch-all and optional catch-all paths, time-based ISR, build- and runtime-rendered notFound results becoming available again, open routes first generated at runtime, and empty custom caches. Document, navigation, and bot requests verify that unlisted paths do not consult the route cache.
These suites exercise dynamicParams = false, which is unsupported with Cache Components. Exclude them from the CC test matrix rather than overriding that job's cached-navigation defaults in the fixtures. Verified with the CI test runner's selection mode: neither suite is selected by the CC manifest, while both remain selected in the normal production run. Runtime code and test assertions are unchanged.
gnoff
force-pushed
the
codex/closed-route-revalidation
branch
from
September 21, 2026 06:28
e6e5ae6 to
78df9b6
Compare
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.
Summary
The latest review follow-up (Server Action exemption and expanded fixtures) is verified locally but has not yet been pushed. The verification below distinguishes those local results from the published head.
Keep route admission independent of ISR cache contents. With Cache Components disabled, a route using
dynamicParams = falseandgenerateStaticParams()can currently return 200 for a build-generated URL, then incorrectly return 404 afterrevalidatePathexpires its cache entry. An empty external cache causes the same failure on the first request.For example, if the build generated
/products/known, that URL remains allowed after invalidation;/products/unlistedremains disallowed regardless of cache state. If a later build removes/products/known, it must immediately stop matching, even if an external cache still holds that URL's old response.The request handler now rejects unlisted closed URLs before looking up their ISR entries. This prevents both serving an old cache hit and generating a new response for a URL the current build does not admit. An admitted build path whose matched fallback is
falseregenerates using a blocking render when necessary.The two decisions stay separate: the manifest determines whether the URL may match, while the response generator chooses how to produce an admitted response. We do not share mutable fallback-mode state between those stages.
Preserved exceptions and adapter behavior
/products/[slug], not a concrete page URL. Action calls retain their existing exemption from page admission checks. A retained action must still work after the user navigates away from its closed route.cache entry required but not generatedbecause it returned no cache entry for a non-null cache key. The new adapter fixture reproduces this on the parent runtime.This uses the existing prerender manifest and does not change its format or the adapter contract. The most specific matched dynamic route continues to determine the policy for open URLs, so specialized matchers can admit an open suffix without admitting an unknown closed prefix.
Regression coverage
Real fixtures cover:
notFound(): an admitted URL can transition from 200 to 404 and back, including when its build render returned 404.These legacy
dynamicParamsfixtures are excluded from the Cache Components matrix because that configuration does not support the API.Stack
This is an unflagged correctness fix, placed after #98950 and before the parameter-matching API in #97393. It can land without committing to that API. The API's mixed-prefix and dynamic-tail lifecycle coverage belongs in the API layer.
Verification
git diff --checkpass.No live deployment verification. A separate
revalidate-if-generatedhang with an always-empty custom cache reproduces on both this PR and its parent; its diagnostic is retained for a separate follow-up, not included or silently skipped here.