Problem
PR #1788 fixes searchParams static-bailout correctness by buffering the prerender HTML stream in renderAppPageLifecycle() before finalising cache metadata and headers.
That is a correct local fix, but it is not the ideal long-term contract. The underlying sequencing problem is that some app-page cache metadata is only discovered once SSR consumes the HTML/RSC stream, while prerender headers and cache policy must be known before the response is returned.
The current workaround is effectively:
const bufferedHtml = await readStreamAsText(htmlStream)
htmlStream = createBufferedHtmlStream(bufferedHtml)
await settleCapturedRscRenderForCacheMetadata(...)
This is scoped to isPrerender === true, so it should not affect runtime request streaming, but it still materialises the full HTML output during prerender and could become a bad precedent if copied into runtime paths.
Desired shape
Replace implicit “consume the HTML stream to discover metadata” behaviour with an explicit readiness contract between the SSR handler and the app-page render lifecycle.
One possible shape:
type AppSsrRenderResult = {
htmlStream: ReadableStream<Uint8Array>
metadataReady: Promise<void>
capturedRscData: Promise<ArrayBuffer> | null
}
Then renderAppPageLifecycle() can await metadataReady during prerender before applying cache-life/header decisions, without buffering the complete HTML string.
Constraints
- Do not buffer runtime user responses.
- Preserve streaming behaviour for non-prerender app-page responses.
- Preserve correct prerender headers when cache metadata is discovered during SSR/RSC consumption.
- Preserve complete render observations for both HTML and captured RSC cache artifacts.
- Keep the ownership boundary clear: SSR should expose when render-side metadata effects have settled; app-page render lifecycle should not have to infer that by draining HTML.
Acceptance criteria
renderAppPageLifecycle() no longer needs to call readStreamAsText(htmlStream) solely to settle prerender metadata.
- The SSR/app-page boundary exposes an explicit metadata-settlement signal.
- Tests cover the current failure mode: metadata/cache-life discovered during HTML stream consumption still affects prerender cache headers.
- Tests prove runtime app-page streaming paths are not buffered.
- The allowed buffering locations, if any remain, are documented as prerender-only and not a general render lifecycle pattern.
Related
Follow-up from #1788. This should not block #1788; that PR should ship the scoped correctness fix first.
Problem
PR #1788 fixes
searchParamsstatic-bailout correctness by buffering the prerender HTML stream inrenderAppPageLifecycle()before finalising cache metadata and headers.That is a correct local fix, but it is not the ideal long-term contract. The underlying sequencing problem is that some app-page cache metadata is only discovered once SSR consumes the HTML/RSC stream, while prerender headers and cache policy must be known before the response is returned.
The current workaround is effectively:
This is scoped to
isPrerender === true, so it should not affect runtime request streaming, but it still materialises the full HTML output during prerender and could become a bad precedent if copied into runtime paths.Desired shape
Replace implicit “consume the HTML stream to discover metadata” behaviour with an explicit readiness contract between the SSR handler and the app-page render lifecycle.
One possible shape:
Then
renderAppPageLifecycle()can awaitmetadataReadyduring prerender before applying cache-life/header decisions, without buffering the complete HTML string.Constraints
Acceptance criteria
renderAppPageLifecycle()no longer needs to callreadStreamAsText(htmlStream)solely to settle prerender metadata.Related
Follow-up from #1788. This should not block #1788; that PR should ship the scoped correctness fix first.