Filed by the repo:objectos seat (objectstack#9831) from a measurement taken during #261's workerd verification round (PR #263). The dev offered it for triage and deliberately did not file it, on the grounds that it had not measured the mechanism and "a card asserting a cause I have not measured would be worse than none." That judgement is right, and this card is written to preserve it: the observation is measured, the cause is not, and establishing the cause is the first task.
Measured
Under local preview — both raw wrangler dev and opennextjs-cloudflare preview — the prerendered docs page routes return 404:
/docs
/docs/build/automation/approvals
/zh-Hans/docs/build/automation/approvals
All three return the same 11455-byte Next 404 body.
This is pre-existing, and that is established by a control, not assumed. The same three routes 404 identically on base 94a4126 — before #261's async: true change — under both tools. So it is a property of this project's local preview, not something PR #263 introduced.
Routes that do work in local preview: /api/search, /llms.txt, /sitemap.xml, /og/*. Those are what made #261's workerd verification possible at all.
Why it is worth a card
It is the reason a verification gap exists that nothing else can close.
apps/docs deploys to Cloudflare Workers, and the Workers runtime is not the Node runtime — dynamic-import resolution, in particular, differs. Local preview is the only way to exercise the real runtime before merge, because the deploy step runs on main and needs credentials nobody has locally. With the page routes unreachable there, the largest surface the site serves — the docs pages themselves — can be verified under Node and never under workerd.
That bit precisely once already. #261's fix makes each page body a dynamic import. Its dev could prove under real workerd that the lazy thunks resolve (an ablation on the generated thunk took /api/search from 200/22890 B to 500/0 B, and a verified byte-identical restore brought it back), and could prove base and head byte-identical on every reachable route. It could not show a docs page rendering to HTML under workerd. That change shipped with its riskiest consumer verified only under Node — not through anyone's carelessness, but because the environment offers no way to do better.
Pairs naturally with #262: that card closes the loop on size going unmeasured before deploy, this one on behaviour going unmeasurable before deploy. Neither is the other's duplicate.
⛔ No cause is asserted here
Plausible directions — dynamicParams = false interacting with the preview's asset routing, the locale middleware, incremental-cache or prerender-manifest wiring under opennextjs-cloudflare — are guesses, none of them measured. Do not treat any of them as the finding.
First task is to establish the mechanism, and reporting a measured cause with no fix is a complete delivery. If the answer turns out to be "this is expected for prerendered routes under this preview tool and the supported path is X", that closes the card just as well as a fix, and it is worth more than a speculative patch.
Re-check
cd apps/docs && pnpm exec opennextjs-cloudflare build && pnpm exec opennextjs-cloudflare preview
# then, against the preview's port:
curl -s -o /dev/null -w '%{http_code} %{size_download}\n' http://localhost:PORT/docs
curl -s -o /dev/null -w '%{http_code} %{size_download}\n' http://localhost:PORT/api/search?query=approval
The second is the control: if /api/search also fails, the preview did not start and the reading is vacuous rather than negative. That distinction cost a discarded probe during #261's round — the first ablation returned 500/0 B only because the port was still held and the server never came up.
Related: #261 (the outage whose verification this limited), PR #263, #262 (the size half of the same gap).
Filed by the
repo:objectosseat (objectstack#9831) from a measurement taken during #261's workerd verification round (PR #263). The dev offered it for triage and deliberately did not file it, on the grounds that it had not measured the mechanism and "a card asserting a cause I have not measured would be worse than none." That judgement is right, and this card is written to preserve it: the observation is measured, the cause is not, and establishing the cause is the first task.Measured
Under local preview — both raw
wrangler devandopennextjs-cloudflare preview— the prerendered docs page routes return 404:/docs/docs/build/automation/approvals/zh-Hans/docs/build/automation/approvalsAll three return the same 11455-byte Next 404 body.
This is pre-existing, and that is established by a control, not assumed. The same three routes 404 identically on base
94a4126— before #261'sasync: truechange — under both tools. So it is a property of this project's local preview, not something PR #263 introduced.Routes that do work in local preview:
/api/search,/llms.txt,/sitemap.xml,/og/*. Those are what made #261's workerd verification possible at all.Why it is worth a card
It is the reason a verification gap exists that nothing else can close.
apps/docsdeploys to Cloudflare Workers, and the Workers runtime is not the Node runtime — dynamic-import resolution, in particular, differs. Local preview is the only way to exercise the real runtime before merge, because the deploy step runs onmainand needs credentials nobody has locally. With the page routes unreachable there, the largest surface the site serves — the docs pages themselves — can be verified under Node and never under workerd.That bit precisely once already. #261's fix makes each page body a dynamic import. Its dev could prove under real workerd that the lazy thunks resolve (an ablation on the generated thunk took
/api/searchfrom 200/22890 B to 500/0 B, and a verified byte-identical restore brought it back), and could prove base and head byte-identical on every reachable route. It could not show a docs page rendering to HTML under workerd. That change shipped with its riskiest consumer verified only under Node — not through anyone's carelessness, but because the environment offers no way to do better.Pairs naturally with #262: that card closes the loop on size going unmeasured before deploy, this one on behaviour going unmeasurable before deploy. Neither is the other's duplicate.
⛔ No cause is asserted here
Plausible directions —
dynamicParams = falseinteracting with the preview's asset routing, the locale middleware, incremental-cache or prerender-manifest wiring underopennextjs-cloudflare— are guesses, none of them measured. Do not treat any of them as the finding.First task is to establish the mechanism, and reporting a measured cause with no fix is a complete delivery. If the answer turns out to be "this is expected for prerendered routes under this preview tool and the supported path is X", that closes the card just as well as a fix, and it is worth more than a speculative patch.
Re-check
The second is the control: if
/api/searchalso fails, the preview did not start and the reading is vacuous rather than negative. That distinction cost a discarded probe during #261's round — the first ablation returned 500/0 B only because the port was still held and the server never came up.Related: #261 (the outage whose verification this limited), PR #263, #262 (the size half of the same gap).