Skip to content

[docs] Make v5 the default documentation version - #3714

Open
VaguelySerious wants to merge 5 commits into
mainfrom
peter/docs-v5-default
Open

[docs] Make v5 the default documentation version#3714
VaguelySerious wants to merge 5 commits into
mainfrom
peter/docs-v5-default

Conversation

@VaguelySerious

@VaguelySeriousVaguelySerious commented Aug 21, 2026

Copy link
Copy Markdown
Member

Makes v5 the default documentation version for the 5.0.0 GA, and catches the v5 content up with everything that landed on main since the v5 docs were last refreshed. Companion to #3090 (exit changeset pre mode) and #3091 (pin 4.x publishes to previous).

Version flip and routing

content/docs/v5 and content/worlds/v5 now serve unprefixed — /docs, /worlds, /cookbook — and v4 moves under a /v4 prefix. The versioned source config drives both route trees (the root tree always renders versionedSources.current), so this is a routePrefix move plus source re-binding, not a restructure. The only file moves are app/[lang]/v5/**app/[lang]/v4/**.

  • Version switcher: labels are v5 (Latest) / v4 (Maintenance); current: 'v5'.
  • Banner: pre-release-banner.tsxmaintenance-banner.tsx. v4 pages carry an amber notice (with dark-mode styling) whose "Go to Workflow 5 (Latest)" link deep-links to the same page on the current version; v4-only pages land on the nearest section index via the fallback redirects. v4 pages keep robots: noindex, follow.
  • Redirects (docs/next.config.ts): /v5/* → unprefixed equivalent (permanent; bare /v5 gets its own rule because :path* expands to an empty Location otherwise). The world-docs and api-reference restructure rules are mirrored onto /v4/docs/*, and every page that exists in only one tree has a version-switcher fallback (verified by diffing the two content trees).
  • Worlds routes: both the unprefixed and /v4 worlds routes pass an explicit version into the shared page components, whose semantics flipped with the switch — smoke checks (assertWorldVersionMarkers, assertServesDirectly('/worlds/turso')) now guard the pairing so the canonical /worlds/* pages can't silently serve the maintenance version or self-redirect-loop again.
  • Link lint (docs/scripts/lint.ts): the two-space model swaps with the URL space; redirect destinations resolve against the real HTTP space since redirects are matched before render-time href rewriting.
  • Intentional oddity: rewriteHrefForVersion pulls unprefixed hrefs on v4 pages into the /v4 view, so a /v5/... href is the only way for v4 content to point at a current page. Three such links are kept deliberately; the lint models this.

What moves with the flip

  • whats-new enters the v5 sidebar, first in the tree. [docs] v5 GA content: What's new, World upgrade guide, migration skills #3100 adds the page but leaves it out of content/docs/v5/meta.json, so until this lands it is reachable only by URL.
  • upgrading-to-v5 moves from app/[lang]/v5/worlds/ to app/[lang]/worlds/, following the rest of the v5 worlds routes.
  • Two cross-version links become expressible and are restored. While v4 is the unprefixed version, a v5 page cannot link to a v4 page at all: an unprefixed href on a v5 page is rewritten into the /v5 view. [docs] v5 GA content: What's new, World upgrade guide, migration skills #3100 therefore phrases both as pointers to the version picker. Here they go back to being links — the v4 docs entry point in the What's new callout, and the v4 version of the code-transform page.
  • editPath on the unprefixed docs route points at docs/content/docs/v5/{path}.

Catch-up with main

Swept the 53 commits that landed since the last content refresh, and added what the docs were missing. Most changesets in that window are fixes, internal, or already documented by their own PR; three things were not.

Spec 7, the sealed log (#3634, not merged, default for v5). Positions are handed out ahead of the commit instead of being claimed by the write that fills them, so concurrent writers never contend and a wide fan-out stops serializing. The cost is a position whose writer dies, which the backend closes with a noop event that replay steps over without delivering it and without advancing the deterministic clock.

  • upgrading-to-v5 › Spec versions is rewritten around mintedSpecVersion(). The accepted range widens back to two versions, because a deployment with WORKFLOW_SEALED_LOG=0 stamps the one below, and that makes both SPEC_VERSION_CURRENT and SPEC_VERSION_SUPPORTS_SLOT_IDENTITY literals by another name for declaring it — neither follows the setting. This replaces what [docs] v5 GA content: What's new, World upgrade guide, migration skills #3100 said for spec 6, which was that exactly one version is accepted.
  • A new "Sealed logs and noop events" subsection says what this costs an implementer, which for most is nothing: a World allocating each position at the commit cannot leave a hole, so it never seals and never emits a noop. The obligation belongs to a World that pre-assigns positions; the half that binds everyone is the reader's.
  • WORKFLOW_SEALED_LOG is documented in runtime-tuning, taken verbatim from Add support for 'noop' event type - spec version 7 #3634 so whichever lands second is a no-op merge. The deep reference sections that PR writes — in event-sourcing and the World allocation contract — are left to it, so this does not duplicate them.
  • The migration skill (v0.2.0) gets the same treatment, phrased as findings to report rather than edits to make.

events.createBatch (#3025). An optional World method appending an ordered list of events in one durable write with per-event outcomes. It was documented only as a changelog page and an env var, so the World reference had no mention of a method a World author has to decide about. Added to the interface snippet, to the Key Implementation Details as a contract note (atomicity per attempt, what a World must reject, the one legal same-entity pair), to the upgrade guide's optional surface, and to the skill.

runs.waitForTerminalStatus (#3570). Also missing from the upgrade guide and the skill. It is what makes await run.returnValue a long poll rather than an interval, which is user-facing, so What's new gets that as an entry.

What's new also gains the batched suspension write and the positions change under faster-and-cheaper runs, where they belong: neither has any API surface.

Not addressed.workflow.step.execute.duration, the OpenTelemetry histogram from #3526, has nowhere to go — the docs carry no metrics reference at all, and inventing one for a single metric is a bigger call than this sweep. Flagging rather than guessing.

Second catch-up: the WebSocket default and spec 7

Merged main again (13 commits). Four conflicts, all against #3704's writing-standards pass over the whole corpus, which rewrote the same paragraphs this branch had edited. Took main's normalized text wherever the difference was purely style, kept this branch's meaning where the two disagreed (the spec-7 paragraph main still had at spec 6, the /v4/... link the flip makes expressible, the batch-write contract note), and restyled this branch's own additions so no prose em dashes come back with it.

The WebSocket events transport is the default now.#3702 flipped it and updated worlds.mdx, vercel.mdx and runtime-tuning.mdx, but What's new still said "an opt-in WebSocket transport ... HTTP remains the default", which was the most wrong sentence left in the v5 docs. It now says what happens, that only the exact value http opts out so a typo fails toward the socket, and that tracing is unchanged because the client span is synthesized around the frame.

Spec 7 is settled.#3634 landed, then #3735 made the sealed log opt-in, then #3737 re-enabled it. The end state matches what this branch already documented, and the WORKFLOW_SEALED_LOG section I had taken verbatim merged as the no-op it was meant to be, modulo #3704's restyling. mintedSpecVersion(), the two-version accepted range, and the "if you allocate at the commit you are already compliant" framing all still hold.

Three World-developer notes, all from #3728. These are the ones a custom World cannot discover from its type errors:

  • Process-wide state has to live on globalThis. A module's top-level const/let is one instance per module instance, and a bundler compiles one copy per layer. The runtime caches the World object process-wide while module state it closes over stays layer-local, so anything a World reaches at request time has to be process-wide too. New contract note in the upgrade guide, plus a step of its own in the World skill (v0.3.0) with an intake item, a globalSingleton() example including what the shape version is for, an output-shape section, and a failure-checklist line. Documented by its casualty: the WS transport registered its channel in the route layer's registry and the write path read the instrumentation layer's empty one, so every event fell back to HTTP for the life of the process, with nothing logged and no test failing.
  • One World per process. The entrypoint's queue handler is built from getWorld() instead of getWorldHandlers(), so a stateful World stops getting duplicate connection pools and queue workers. The build-integration row that still pointed custom hosts at getWorldHandlers() is corrected: that export is the build-time view, not how a request-time handler is assembled.
  • A World's transport is its own business, except for the tracing. How a World ships events is unconstrained. What is constrained is that a non-HTTP transport still owes the per-event client span an HTTP write would emit, or the per-event view of a run silently disappears. Points at the Vercel World's span shape as the worked example.

Nothing needed for the remaining commits in the window: globalSingleton's own changeset and the sideEffects: false declaration are internal, the wait-continuation re-arm and the atomic step_created commit are fixes to behavior already documented, and the decrypt-control and trace-name changes are dashboard-side.

Verification

Link lint passes with 0 errors. pnpm build compiles, with /en/docs/whats-new prerendered under the unprefixed route, /[lang]/v4/docs/[[...slug]] serving the maintenance tree, and ƒ /[lang]/worlds/upgrading-to-v5.

Docs Preview

Links will be added from the workflow-docs preview once it deploys.

🤖 Generated with Claude Code

@vercel

vercelBot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated (UTC)
example-nextjs-workflow-turbopackReadyReadyPreview, v0Aug 25, 2026 8:40pm
example-nextjs-workflow-webpackReadyReadyPreview, v0Aug 25, 2026 8:40pm
example-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-astro-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-express-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-fastify-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-hono-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-nestjs-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-nitro-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-nuxt-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-python-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-sveltekit-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-tanstack-start-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-vite-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workflow-docsReadyReadyPreview, v0Aug 25, 2026 8:40pm
workflow-swc-playgroundBuildingBuildingPreview, v0Aug 25, 2026 8:40pm
workflow-tarballsReadyReadyPreview, v0Aug 25, 2026 8:40pm
workflow-webReadyReadyPreview, v0Aug 25, 2026 8:40pm

@changeset-bot

changeset-botBot commented Aug 21, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 8d9081b

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 0 packages

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions

github-actionsBot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Sim World

Simulated world deterministic testing for races. Traces

🟠 world-sim scenario book — 1 fail of 41 total

fence=per-spec

scenariooutcomeeventsvirtreplayviolations
smoke-no-stepscompleted30msok0
smoke-one-stepcompleted60msok0
hook-at-step-startedcompleted120msok0
hook-at-step-completedcompleted120msok0
hook-at-hook-createdcompleted120msok0
deadline-hook-winscompleted71.0hok0
deadline-expirescompleted71.0hok0
long-sleepcompleted1130.0dok0
hook-never-arrivesstalled30msskipped0
step-retries-twicecompleted102.0sok0
parallel-stepscompleted90msok0
hook-on-execution-statecompleted120msok0
peek-hook-before-branchcompleted120msok0
peek-hook-after-branchcompleted120msok0
peek-hook-at-registrationcompleted120msok0
race-hook-before-probecompleted120msok0
race-hook-after-probecompleted120msok0
race-duplicate-deliverycompleted130msok0
attr-hook-before-stepcompleted110msok0
attr-hook-after-stepcompleted110msok0
attr-from-step-bodycompleted130msok0
fork-hook-after-timeoutcompleted141.0mok0
fork-hook-before-timeoutcompleted141.0mok0
count-hook-after-timeoutcompleted171.0mok0
count-hook-before-timeoutcompleted201.0mok0
stale-read-step-count-forkcompleted201.0mok0
stale-read-equal-step-countscompleted141.0mok0
step-vs-step-forkcompleted120msok0
step-vs-step-fork-fencedcompleted120msok0
fence-catches-benign-directioncompleted125msok0
in-flight-before-decisioncompleted171.0mok0
in-flight-before-decision-countedcompleted171.0mok0
in-flight-after-decisioncompleted192.0mok0
stale-read-step-count-fork-fencedcompleted201.0mok0
fork-hook-winscompleted131.0mok0
fork-timeout-winscompleted131.0mok0
unclaimed-payload-under-forkcompleted171.0mok0
claimed-payload-under-forkcompleted171.0mok0
writers-independent-step-bodiescompleted120msok0
writers-scripted-tempocompleted120msok0
cancel-mid-stepcancelled70msskipped0

Full trace: world-sim.txt

VaguelySeriousand others added 2 commits August 21, 2026 12:50
Serves `content/docs/v5` and `content/worlds/v5` unprefixed at /docs,
/worlds and /cookbook, moves v4 under /v4, and puts What's new first in
the v5 sidebar.
The versioned source config drives both route trees (the root tree always
renders `versionedSources.current`), so this is a `routePrefix` move plus
source re-binding rather than a restructure. The only file moves are
`app/[lang]/v5/**` → `app/[lang]/v4/**`.
- Version switcher: `v5 (Latest)` / `v4 (Maintenance)`, `current: 'v5'`.
- `pre-release-banner.tsx` becomes `maintenance-banner.tsx`. v4 pages
carry an amber notice whose "Go to Workflow 5 (Latest)" link deep-links
to the same page on the current version, falling back to the nearest
section index for v4-only pages, and keep `robots: noindex, follow`.
- Redirects: `/v5/*` to the unprefixed equivalent (bare `/v5` needs its
own rule, since `:path*` expands to an empty Location). The world-docs
and api-reference restructure rules are mirrored onto `/v4/docs/*`, and
every page existing in only one tree gets a version-switcher fallback.
- Both worlds route trees pass an explicit version into the shared page
components, whose semantics flipped with the switch, so the smoke checks
now assert the pairing: a " · v4" title marker and noindex on the
maintenance routes, neither on the canonical ones, and a community world
serving directly rather than self-redirecting.
- The link lint's two URL spaces swap with the prefixes. Redirect
destinations resolve against the real HTTP space, since redirects are
matched before render-time href rewriting.
- The two `/v4/...` links this makes expressible are restored: a v5 page
cannot link to a v4 page while v4 is the unprefixed version.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sweep of everything that landed on main since the last content refresh,
plus the spec-7 sealed log from #3634, which is not merged but is the
default for v5.
Spec 7 changes what a World declares, so the upgrade guide's Spec
versions section is rewritten around `mintedSpecVersion()`. The accepted
range widens back to two versions, because a deployment with
`WORKFLOW_SEALED_LOG=0` stamps the one below, and both `SPEC_VERSION_CURRENT`
and `SPEC_VERSION_SUPPORTS_SLOT_IDENTITY` become literals by another name
for the purpose of declaring it: neither follows the setting. The new
section says what a sealed log costs an implementer, which for most is
nothing — a World allocating each position at the commit cannot leave a
hole, so it never seals and never writes a `noop`. The obligation belongs
to a World that pre-assigns positions, and the half that binds everyone
is the reader's.
`WORKFLOW_SEALED_LOG` is documented in runtime-tuning, taken verbatim
from #3634 so whichever lands second is a no-op merge. The deep
reference sections that PR writes, in event-sourcing and the World
allocation contract, are left to it.
Two optional World members shipped after the guide was written and were
missing everywhere:
- `events.createBatch` — in the World reference (interface and contract
note), the upgrade guide's optional surface, and the skill. Implementing
it is the declaration, so the note leads with atomicity per attempt and
what a World must reject.
- `runs.waitForTerminalStatus` — same three places. It is also what makes
`await run.returnValue` a long poll rather than an interval, which is
user-facing, so What's new gets it too.
What's new also gains the batched suspension write and the pre-assigned
positions behind it, both under faster-and-cheaper runs where they belong:
neither has any API surface.
Not addressed: `workflow.step.execute.duration`, the OpenTelemetry
histogram added in #3526, has nowhere to go. The docs have no metrics
reference at all, and inventing one for a single metric is a bigger call
than this sweep.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@github-actions

github-actionsBot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

🧪 E2E Test Results

Some tests failed

❌ Failed E2E Tests

▲ Vercel Production (8 failed)

python-node (8 failed):

  • promiseAllWorkflow | wrun_41M0XAGXS00GK4H9P4BRDADZPF | 🔍 observability
  • sleepingWorkflow | wrun_41M0XAHK4C0GN8PMSN1G5MJ54R | 🔍 observability
  • parallelSleepWorkflow | wrun_41M0XAHKR70GX6C8R38YRX9JZR | 🔍 observability
  • nullByteWorkflow | wrun_41M0XAHTBJ0GPJDS4V1JB075V8 | 🔍 observability
  • cancelRun - cancelling a running workflow | wrun_41M0XAPE6F0GWZ7WFMJS2WQSZ7 | 🔍 observability
  • cancelRun via CLI - cancelling a running workflow | wrun_41M0XAPJ5Y0GVZ8EPNJZZFBXBN | 🔍 observability
  • sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration | wrun_41M0XAPTHD0GRRQPJZEA3CS0X9 | 🔍 observability
  • resilient start: addTenWorkflow completes when run_created returns 500 | wrun_41M0XAQ8AD0GG3DEEMY8R682VV | 🔍 observability

🌐 Cross-language Conformance (9 failed)

python (9 failed):

  • deploymentId: 'latest' is a no-op in non-Vercel worlds | wrun_01M0XASD1GCVQ8X0DC4TD9QQ8K
  • promiseAllWorkflow | wrun_41M0XAGXS00GK4H9P4BRDADZPF
  • sleepingWorkflow | wrun_41M0XAHK4C0GN8PMSN1G5MJ54R
  • parallelSleepWorkflow | wrun_41M0XAHKR70GX6C8R38YRX9JZR
  • nullByteWorkflow | wrun_41M0XAHTBJ0GPJDS4V1JB075V8
  • cancelRun - cancelling a running workflow | wrun_41M0XAPE6F0GWZ7WFMJS2WQSZ7
  • cancelRun via CLI - cancelling a running workflow | wrun_41M0XAPJ5Y0GVZ8EPNJZZFBXBN
  • sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration | wrun_41M0XAPTHD0GRRQPJZEA3CS0X9
  • resilient start: addTenWorkflow completes when run_created returns 500 | wrun_41M0XAQ8AD0GG3DEEMY8R682VV

⚠️ Flaky E2E Tests (passed on retry)

These tests failed at least once and passed on a retry. A recurring entry here is a real race worth investigating.

  • addTenWorkflow (express)
  • cancelRun via CLI - cancelling a running workflow (nextjs-turbopack)
  • hookWithSleepWorkflow - hook payloads delivered correctly with concurrent sleep (nextjs-webpack)
  • promiseAllWorkflow (nuxt)
  • RetryableError respects custom retryAfter delay (nitro)

🛠 Infra Events (absorbed by the harness)

Platform anomalies the e2e harness detected and worked around (e.g. a run the queue never picked up, replaced by a fresh run). Clustered timestamps indicate a backend blip; a steady drip indicates a platform issue worth escalating.

35 infra events
  • cold-start-warmup · suite warmup (python) · at 20:42:37Z · abandoned wrun_41M0XAEJYH0GKQ4W94H3ETH1ZY · (+7 more)
  • run-pickup-stall · nullByteWorkflow (python) · at 20:42:53Z · abandoned wrun_41M0XAJ7Y50GK8N5JNCV12GV8E
  • run-pickup-stall · parallelSleepWorkflow (python) · at 20:42:53Z · abandoned wrun_41M0XAJ7Y20GSX8SWCTH5RVR9M
  • run-pickup-stall · promiseAllWorkflow (python) · at 20:42:53Z · abandoned wrun_41M0XAJ7XV0GG32EEKFRD3B8FS
  • run-pickup-stall · sleepingWorkflow (python) · at 20:42:54Z · abandoned wrun_41M0XAJ7Y20GSX8SWCTH5RVR9K
  • run-pickup-stall · cancelRun - cancelling a running workflow (python) · at 20:42:54Z · abandoned wrun_41M0XAJ8BJ0GJZX1BNBA4CH8W8
  • run-pickup-stall · cancelRun - cancelling a running workflow (python) · at 20:43:27Z · abandoned wrun_41M0XAK8KD0GGARJ5E9EAKDQA7
  • run-pickup-stall · parallelSleepWorkflow (python) · at 20:43:54Z · abandoned wrun_41M0XAM3J00GNDEKT3M4EV9A3B
  • run-pickup-stall · nullByteWorkflow (python) · at 20:43:54Z · abandoned wrun_41M0XAM3J50GY1Z4PYVB875JW2
  • run-pickup-stall · sleepingWorkflow (python) · at 20:43:55Z · abandoned wrun_41M0XAM3NR0GMY2WC43XC9WEEG
  • run-pickup-stall · promiseAllWorkflow (python) · at 20:43:55Z · abandoned wrun_41M0XAM3PT0GKQPBP2CXFAYS50
  • cold-start-warmup · suite warmup (tanstack-start) · at 20:44:26Z · abandoned wrun_01M0XAMQCG384J98J2DSD14DR1
  • run-pickup-stall · cancelRun via CLI - cancelling a running workflow (python) · at 20:44:45Z · abandoned wrun_41M0XAM8FN0GV4BFNTQPWFKM5X
  • cold-start-warmup · suite warmup (python) · at 20:45:16Z · abandoned wrun_01M0XAKEM09ZDGG4DKY24BNT4R · (+7 more)
  • run-pickup-stall · deploymentId: 'latest' is a no-op in non-Vercel worlds (python) · at 20:45:31Z · abandoned wrun_01M0XAQ3RETMHB830AKZR4WRR3
  • run-pickup-stall · promiseAllWorkflow (python) · at 20:45:31Z · abandoned wrun_01M0XAQ3RF7PEAZN9P8KWR413P
  • run-pickup-stall · parallelSleepWorkflow (python) · at 20:45:31Z · abandoned wrun_01M0XAQ3RP7BN47JKYJVR7W9SN
  • run-pickup-stall · sleepingWorkflow (python) · at 20:45:31Z · abandoned wrun_01M0XAQ3RNB63W8SCJMFB059TD
  • run-pickup-stall · nullByteWorkflow (python) · at 20:45:31Z · abandoned wrun_01M0XAQ3RRZXSHD6R9Y4Q7HMN3
  • run-pickup-stall · cancelRun via CLI - cancelling a running workflow (python) · at 20:46:27Z · abandoned wrun_41M0XAQ0C60GXEJ7JBYYKRXP7W
  • run-pickup-stall · sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration (python) · at 20:46:28Z · abandoned wrun_41M0XAPVEJ0GJSWRFAK9D97ABV
  • run-pickup-stall · deploymentId: 'latest' is a no-op in non-Vercel worlds (python) · at 20:46:31Z · abandoned wrun_01M0XARYC38T4GCYXDEWNVNMX3
  • run-pickup-stall · promiseAllWorkflow (python) · at 20:46:31Z · abandoned wrun_01M0XARYC52C67FSA4N73VC5D7
  • run-pickup-stall · sleepingWorkflow (python) · at 20:46:31Z · abandoned wrun_01M0XARYCDFV9BC8DR74AKYXE5
  • run-pickup-stall · parallelSleepWorkflow (python) · at 20:46:32Z · abandoned wrun_01M0XARYCK0DC47WQPD9BH1JVJ
  • run-pickup-stall · nullByteWorkflow (python) · at 20:46:32Z · abandoned wrun_01M0XARYCM1HBYVNK0S93X5J0W
  • run-pickup-stall · cancelRun - cancelling a running workflow (python) · at 20:47:32Z · abandoned wrun_01M0XATRZQVJRSD3M331XYF0RA
  • run-pickup-stall · cancelRun via CLI - cancelling a running workflow (python) · at 20:47:32Z · abandoned wrun_01M0XATRZZS9C3MF3DY87TKVW5
  • run-pickup-stall · sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration (python) · at 20:47:32Z · abandoned wrun_01M0XATS031XZTYSFHCRKFRY0Z
  • run-pickup-stall · cancelRun - cancelling a running workflow (python) · at 20:48:02Z · abandoned wrun_01M0XAVPAX8XNNRK46QNQJ2XK9
  • run-pickup-stall · cancelRun via CLI - cancelling a running workflow (python) · at 20:48:02Z · abandoned wrun_01M0XAVPBFHXMMMA4YG99N83D1
  • run-pickup-stall · sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration (python) · at 20:48:32Z · abandoned wrun_01M0XAWKK6KJ97YQH5T3M65MQN
  • run-pickup-stall · plainModuleDoneHook resumed via plain API route (o2flow shape) (nextjs-webpack) · at 20:51:44Z · abandoned wrun_01M0XB2FMN0D9JTJB906JH00C2
  • run-pickup-stall · hookWithSleepFinalStepWorkflow - step only on final payload (nextjs-webpack) · at 20:52:05Z · abandoned wrun_01M0XB34HFYH9Y559Y5VFH0QKY
  • run-pickup-stall · sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration (nextjs-webpack) · at 20:52:06Z · abandoned wrun_01M0XB34PXRGGCJBBBPNXBSAQW

E2E Test Summary

Summary
PassedFailedSkippedTotal
❌ ▲ Vercel Production357087424320
✅ 💻 Local Development392205584480
✅ 📦 Local Production392205584480
✅ 🐘 Local Postgres392205584480
✅ 🪟 Windows32000320
❌ 🌐 Cross-language Conformance09132141
✅ vercel-http-transport8170143960
✅ vercel-multi-region270027
✅ vercel-ws-transport553087640
Total1705317277819848
Details by Category

❌ ▲ Vercel Production

AppPassedFailedSkipped
✅ astro-node132028
✅ astro-quickjs132028
✅ example-node132028
✅ example-quickjs132028
✅ express-node132028
✅ express-quickjs132028
✅ fastify-node132028
✅ fastify-quickjs132028
✅ hono-node132028
✅ hono-quickjs132028
✅ nest-node132028
✅ nest-quickjs132028
✅ nextjs-turbopack-node15703
✅ nextjs-turbopack-quickjs15703
✅ nextjs-webpack-node15703
✅ nextjs-webpack-quickjs15703
✅ nitro-node132028
✅ nitro-quickjs132028
✅ nuxt-node132028
✅ nuxt-quickjs132028
❌ python-node08152
✅ sveltekit-node15109
✅ sveltekit-quickjs15109
✅ tanstack-start-node132028
✅ tanstack-start-quickjs132028
✅ vite-node132028
✅ vite-quickjs132028

✅ 💻 Local Development

AppPassedFailedSkipped
✅ astro-stable-node134026
✅ astro-stable-quickjs134026
✅ express-stable-node134026
✅ express-stable-quickjs134026
✅ fastify-stable-node134026
✅ fastify-stable-quickjs134026
✅ hono-stable-node134026
✅ hono-stable-quickjs134026
✅ nest-stable-node134026
✅ nest-stable-quickjs134026
✅ nextjs-turbopack-canary-node141019
✅ nextjs-turbopack-canary-quickjs141019
✅ nextjs-turbopack-stable-node16000
✅ nextjs-turbopack-stable-quickjs16000
✅ nextjs-webpack-canary-node141019
✅ nextjs-webpack-canary-quickjs141019
✅ nextjs-webpack-stable-node16000
✅ nextjs-webpack-stable-quickjs16000
✅ nitro-stable-node134026
✅ nitro-stable-quickjs134026
✅ nuxt-stable-node134026
✅ nuxt-stable-quickjs134026
✅ sveltekit-stable-node15307
✅ sveltekit-stable-quickjs15307
✅ tanstack-start-node134026
✅ tanstack-start-quickjs134026
✅ vite-stable-node134026
✅ vite-stable-quickjs134026

✅ 📦 Local Production

AppPassedFailedSkipped
✅ astro-stable-node134026
✅ astro-stable-quickjs134026
✅ express-stable-node134026
✅ express-stable-quickjs134026
✅ fastify-stable-node134026
✅ fastify-stable-quickjs134026
✅ hono-stable-node134026
✅ hono-stable-quickjs134026
✅ nest-stable-node134026
✅ nest-stable-quickjs134026
✅ nextjs-turbopack-canary-node141019
✅ nextjs-turbopack-canary-quickjs141019
✅ nextjs-turbopack-stable-node16000
✅ nextjs-turbopack-stable-quickjs16000
✅ nextjs-webpack-canary-node141019
✅ nextjs-webpack-canary-quickjs141019
✅ nextjs-webpack-stable-node16000
✅ nextjs-webpack-stable-quickjs16000
✅ nitro-stable-node134026
✅ nitro-stable-quickjs134026
✅ nuxt-stable-node134026
✅ nuxt-stable-quickjs134026
✅ sveltekit-stable-node15307
✅ sveltekit-stable-quickjs15307
✅ tanstack-start-node134026
✅ tanstack-start-quickjs134026
✅ vite-stable-node134026
✅ vite-stable-quickjs134026

✅ 🐘 Local Postgres

AppPassedFailedSkipped
✅ astro-stable-node134026
✅ astro-stable-quickjs134026
✅ express-stable-node134026
✅ express-stable-quickjs134026
✅ fastify-stable-node134026
✅ fastify-stable-quickjs134026
✅ hono-stable-node134026
✅ hono-stable-quickjs134026
✅ nest-stable-node134026
✅ nest-stable-quickjs134026
✅ nextjs-turbopack-canary-node141019
✅ nextjs-turbopack-canary-quickjs141019
✅ nextjs-turbopack-stable-node16000
✅ nextjs-turbopack-stable-quickjs16000
✅ nextjs-webpack-canary-node141019
✅ nextjs-webpack-canary-quickjs141019
✅ nextjs-webpack-stable-node16000
✅ nextjs-webpack-stable-quickjs16000
✅ nitro-stable-node134026
✅ nitro-stable-quickjs134026
✅ nuxt-stable-node134026
✅ nuxt-stable-quickjs134026
✅ sveltekit-stable-node15307
✅ sveltekit-stable-quickjs15307
✅ tanstack-start-node134026
✅ tanstack-start-quickjs134026
✅ vite-stable-node134026
✅ vite-stable-quickjs134026

✅ 🪟 Windows

AppPassedFailedSkipped
✅ nextjs-turbopack-node16000
✅ nextjs-turbopack-quickjs16000

❌ 🌐 Cross-language Conformance

AppPassedFailedSkipped
❌ python09132

✅ vercel-http-transport

AppPassedFailedSkipped
✅ example132028
✅ express132028
✅ hono132028
✅ nextjs-turbopack15703
✅ nitro132028
✅ vite132028

✅ vercel-multi-region

AppPassedFailedSkipped
✅ nextjs-turbopack2700

✅ vercel-ws-transport

AppPassedFailedSkipped
✅ example132028
✅ express132028
✅ nextjs-turbopack15703
✅ vite132028

📋 View full workflow run

#3779 fixed the app migration skill, whose description ended with
`mode: 'client'`. The colon-space made the plain scalar parse as a nested
mapping, and the skills CLI dropped the file: `Found 5 skills`, and
`--skill migrating-workflow-v4-to-v5` answered `No matching skills
found`, which is the command whats-new.mdx tells readers to run.
The World skill's description has no colon-space today, so it parses.
It is also 590 characters of backticked identifiers, and any future
edit naming a field with its value reintroduces the break. Fold it the
same way now, while the value is known good. Verified with the yaml
package that the folded scalar is byte-identical, and with
`skills add . --skill migrating-world-v4-to-v5` that the CLI still
finds all six.
Signed-off-by: Peter Wielander <peter.wielander@vercel.com>
@github-actions

Copy link
Copy Markdown
Contributor
FrameworkFlow routeStep reg.Framework output
hono200.9 KiB (±0)40.5 KiB (±0)1.76 MiB (±0)
nextjs-turbopack206.3 KiB (±0)439 B (±0)762.8 KiB (±0)
About these numbers

Sizes are gzip; parentheses show the change against main.
Flow route and Step reg. gate this job, on raw bytes rather than the gzip shown, at max(2%, 50.0 KiB). Framework output is informational.

8d9081b · run

Sign up for freeto 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.

1 participant

@VaguelySerious
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
[docs] Make v5 the default documentation version by VaguelySerious · Pull Request #3714 · vercel/workflow · GitHub
Skip to content

[docs] Make v5 the default documentation version - #3714

Open
VaguelySerious wants to merge 5 commits into
mainfrom
peter/docs-v5-default
Open

[docs] Make v5 the default documentation version#3714
VaguelySerious wants to merge 5 commits into
mainfrom
peter/docs-v5-default

Conversation

@VaguelySerious

@VaguelySeriousVaguelySerious commented Aug 21, 2026

Copy link
Copy Markdown
Member

Makes v5 the default documentation version for the 5.0.0 GA, and catches the v5 content up with everything that landed on main since the v5 docs were last refreshed. Companion to #3090 (exit changeset pre mode) and #3091 (pin 4.x publishes to previous).

Version flip and routing

content/docs/v5 and content/worlds/v5 now serve unprefixed — /docs, /worlds, /cookbook — and v4 moves under a /v4 prefix. The versioned source config drives both route trees (the root tree always renders versionedSources.current), so this is a routePrefix move plus source re-binding, not a restructure. The only file moves are app/[lang]/v5/**app/[lang]/v4/**.

  • Version switcher: labels are v5 (Latest) / v4 (Maintenance); current: 'v5'.
  • Banner: pre-release-banner.tsxmaintenance-banner.tsx. v4 pages carry an amber notice (with dark-mode styling) whose "Go to Workflow 5 (Latest)" link deep-links to the same page on the current version; v4-only pages land on the nearest section index via the fallback redirects. v4 pages keep robots: noindex, follow.
  • Redirects (docs/next.config.ts): /v5/* → unprefixed equivalent (permanent; bare /v5 gets its own rule because :path* expands to an empty Location otherwise). The world-docs and api-reference restructure rules are mirrored onto /v4/docs/*, and every page that exists in only one tree has a version-switcher fallback (verified by diffing the two content trees).
  • Worlds routes: both the unprefixed and /v4 worlds routes pass an explicit version into the shared page components, whose semantics flipped with the switch — smoke checks (assertWorldVersionMarkers, assertServesDirectly('/worlds/turso')) now guard the pairing so the canonical /worlds/* pages can't silently serve the maintenance version or self-redirect-loop again.
  • Link lint (docs/scripts/lint.ts): the two-space model swaps with the URL space; redirect destinations resolve against the real HTTP space since redirects are matched before render-time href rewriting.
  • Intentional oddity: rewriteHrefForVersion pulls unprefixed hrefs on v4 pages into the /v4 view, so a /v5/... href is the only way for v4 content to point at a current page. Three such links are kept deliberately; the lint models this.

What moves with the flip

  • whats-new enters the v5 sidebar, first in the tree. [docs] v5 GA content: What's new, World upgrade guide, migration skills #3100 adds the page but leaves it out of content/docs/v5/meta.json, so until this lands it is reachable only by URL.
  • upgrading-to-v5 moves from app/[lang]/v5/worlds/ to app/[lang]/worlds/, following the rest of the v5 worlds routes.
  • Two cross-version links become expressible and are restored. While v4 is the unprefixed version, a v5 page cannot link to a v4 page at all: an unprefixed href on a v5 page is rewritten into the /v5 view. [docs] v5 GA content: What's new, World upgrade guide, migration skills #3100 therefore phrases both as pointers to the version picker. Here they go back to being links — the v4 docs entry point in the What's new callout, and the v4 version of the code-transform page.
  • editPath on the unprefixed docs route points at docs/content/docs/v5/{path}.

Catch-up with main

Swept the 53 commits that landed since the last content refresh, and added what the docs were missing. Most changesets in that window are fixes, internal, or already documented by their own PR; three things were not.

Spec 7, the sealed log (#3634, not merged, default for v5). Positions are handed out ahead of the commit instead of being claimed by the write that fills them, so concurrent writers never contend and a wide fan-out stops serializing. The cost is a position whose writer dies, which the backend closes with a noop event that replay steps over without delivering it and without advancing the deterministic clock.

  • upgrading-to-v5 › Spec versions is rewritten around mintedSpecVersion(). The accepted range widens back to two versions, because a deployment with WORKFLOW_SEALED_LOG=0 stamps the one below, and that makes both SPEC_VERSION_CURRENT and SPEC_VERSION_SUPPORTS_SLOT_IDENTITY literals by another name for declaring it — neither follows the setting. This replaces what [docs] v5 GA content: What's new, World upgrade guide, migration skills #3100 said for spec 6, which was that exactly one version is accepted.
  • A new "Sealed logs and noop events" subsection says what this costs an implementer, which for most is nothing: a World allocating each position at the commit cannot leave a hole, so it never seals and never emits a noop. The obligation belongs to a World that pre-assigns positions; the half that binds everyone is the reader's.
  • WORKFLOW_SEALED_LOG is documented in runtime-tuning, taken verbatim from Add support for 'noop' event type - spec version 7 #3634 so whichever lands second is a no-op merge. The deep reference sections that PR writes — in event-sourcing and the World allocation contract — are left to it, so this does not duplicate them.
  • The migration skill (v0.2.0) gets the same treatment, phrased as findings to report rather than edits to make.

events.createBatch (#3025). An optional World method appending an ordered list of events in one durable write with per-event outcomes. It was documented only as a changelog page and an env var, so the World reference had no mention of a method a World author has to decide about. Added to the interface snippet, to the Key Implementation Details as a contract note (atomicity per attempt, what a World must reject, the one legal same-entity pair), to the upgrade guide's optional surface, and to the skill.

runs.waitForTerminalStatus (#3570). Also missing from the upgrade guide and the skill. It is what makes await run.returnValue a long poll rather than an interval, which is user-facing, so What's new gets that as an entry.

What's new also gains the batched suspension write and the positions change under faster-and-cheaper runs, where they belong: neither has any API surface.

Not addressed.workflow.step.execute.duration, the OpenTelemetry histogram from #3526, has nowhere to go — the docs carry no metrics reference at all, and inventing one for a single metric is a bigger call than this sweep. Flagging rather than guessing.

Second catch-up: the WebSocket default and spec 7

Merged main again (13 commits). Four conflicts, all against #3704's writing-standards pass over the whole corpus, which rewrote the same paragraphs this branch had edited. Took main's normalized text wherever the difference was purely style, kept this branch's meaning where the two disagreed (the spec-7 paragraph main still had at spec 6, the /v4/... link the flip makes expressible, the batch-write contract note), and restyled this branch's own additions so no prose em dashes come back with it.

The WebSocket events transport is the default now.#3702 flipped it and updated worlds.mdx, vercel.mdx and runtime-tuning.mdx, but What's new still said "an opt-in WebSocket transport ... HTTP remains the default", which was the most wrong sentence left in the v5 docs. It now says what happens, that only the exact value http opts out so a typo fails toward the socket, and that tracing is unchanged because the client span is synthesized around the frame.

Spec 7 is settled.#3634 landed, then #3735 made the sealed log opt-in, then #3737 re-enabled it. The end state matches what this branch already documented, and the WORKFLOW_SEALED_LOG section I had taken verbatim merged as the no-op it was meant to be, modulo #3704's restyling. mintedSpecVersion(), the two-version accepted range, and the "if you allocate at the commit you are already compliant" framing all still hold.

Three World-developer notes, all from #3728. These are the ones a custom World cannot discover from its type errors:

  • Process-wide state has to live on globalThis. A module's top-level const/let is one instance per module instance, and a bundler compiles one copy per layer. The runtime caches the World object process-wide while module state it closes over stays layer-local, so anything a World reaches at request time has to be process-wide too. New contract note in the upgrade guide, plus a step of its own in the World skill (v0.3.0) with an intake item, a globalSingleton() example including what the shape version is for, an output-shape section, and a failure-checklist line. Documented by its casualty: the WS transport registered its channel in the route layer's registry and the write path read the instrumentation layer's empty one, so every event fell back to HTTP for the life of the process, with nothing logged and no test failing.
  • One World per process. The entrypoint's queue handler is built from getWorld() instead of getWorldHandlers(), so a stateful World stops getting duplicate connection pools and queue workers. The build-integration row that still pointed custom hosts at getWorldHandlers() is corrected: that export is the build-time view, not how a request-time handler is assembled.
  • A World's transport is its own business, except for the tracing. How a World ships events is unconstrained. What is constrained is that a non-HTTP transport still owes the per-event client span an HTTP write would emit, or the per-event view of a run silently disappears. Points at the Vercel World's span shape as the worked example.

Nothing needed for the remaining commits in the window: globalSingleton's own changeset and the sideEffects: false declaration are internal, the wait-continuation re-arm and the atomic step_created commit are fixes to behavior already documented, and the decrypt-control and trace-name changes are dashboard-side.

Verification

Link lint passes with 0 errors. pnpm build compiles, with /en/docs/whats-new prerendered under the unprefixed route, /[lang]/v4/docs/[[...slug]] serving the maintenance tree, and ƒ /[lang]/worlds/upgrading-to-v5.

Docs Preview

Links will be added from the workflow-docs preview once it deploys.

🤖 Generated with Claude Code

@vercel

vercelBot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated (UTC)
example-nextjs-workflow-turbopackReadyReadyPreview, v0Aug 25, 2026 8:40pm
example-nextjs-workflow-webpackReadyReadyPreview, v0Aug 25, 2026 8:40pm
example-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-astro-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-express-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-fastify-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-hono-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-nestjs-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-nitro-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-nuxt-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-python-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-sveltekit-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-tanstack-start-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-vite-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workflow-docsReadyReadyPreview, v0Aug 25, 2026 8:40pm
workflow-swc-playgroundBuildingBuildingPreview, v0Aug 25, 2026 8:40pm
workflow-tarballsReadyReadyPreview, v0Aug 25, 2026 8:40pm
workflow-webReadyReadyPreview, v0Aug 25, 2026 8:40pm

@changeset-bot

changeset-botBot commented Aug 21, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 8d9081b

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 0 packages

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions

github-actionsBot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Sim World

Simulated world deterministic testing for races. Traces

🟠 world-sim scenario book — 1 fail of 41 total

fence=per-spec

scenariooutcomeeventsvirtreplayviolations
smoke-no-stepscompleted30msok0
smoke-one-stepcompleted60msok0
hook-at-step-startedcompleted120msok0
hook-at-step-completedcompleted120msok0
hook-at-hook-createdcompleted120msok0
deadline-hook-winscompleted71.0hok0
deadline-expirescompleted71.0hok0
long-sleepcompleted1130.0dok0
hook-never-arrivesstalled30msskipped0
step-retries-twicecompleted102.0sok0
parallel-stepscompleted90msok0
hook-on-execution-statecompleted120msok0
peek-hook-before-branchcompleted120msok0
peek-hook-after-branchcompleted120msok0
peek-hook-at-registrationcompleted120msok0
race-hook-before-probecompleted120msok0
race-hook-after-probecompleted120msok0
race-duplicate-deliverycompleted130msok0
attr-hook-before-stepcompleted110msok0
attr-hook-after-stepcompleted110msok0
attr-from-step-bodycompleted130msok0
fork-hook-after-timeoutcompleted141.0mok0
fork-hook-before-timeoutcompleted141.0mok0
count-hook-after-timeoutcompleted171.0mok0
count-hook-before-timeoutcompleted201.0mok0
stale-read-step-count-forkcompleted201.0mok0
stale-read-equal-step-countscompleted141.0mok0
step-vs-step-forkcompleted120msok0
step-vs-step-fork-fencedcompleted120msok0
fence-catches-benign-directioncompleted125msok0
in-flight-before-decisioncompleted171.0mok0
in-flight-before-decision-countedcompleted171.0mok0
in-flight-after-decisioncompleted192.0mok0
stale-read-step-count-fork-fencedcompleted201.0mok0
fork-hook-winscompleted131.0mok0
fork-timeout-winscompleted131.0mok0
unclaimed-payload-under-forkcompleted171.0mok0
claimed-payload-under-forkcompleted171.0mok0
writers-independent-step-bodiescompleted120msok0
writers-scripted-tempocompleted120msok0
cancel-mid-stepcancelled70msskipped0

Full trace: world-sim.txt

VaguelySeriousand others added 2 commits August 21, 2026 12:50
Serves `content/docs/v5` and `content/worlds/v5` unprefixed at /docs,
/worlds and /cookbook, moves v4 under /v4, and puts What's new first in
the v5 sidebar.
The versioned source config drives both route trees (the root tree always
renders `versionedSources.current`), so this is a `routePrefix` move plus
source re-binding rather than a restructure. The only file moves are
`app/[lang]/v5/**` → `app/[lang]/v4/**`.
- Version switcher: `v5 (Latest)` / `v4 (Maintenance)`, `current: 'v5'`.
- `pre-release-banner.tsx` becomes `maintenance-banner.tsx`. v4 pages
carry an amber notice whose "Go to Workflow 5 (Latest)" link deep-links
to the same page on the current version, falling back to the nearest
section index for v4-only pages, and keep `robots: noindex, follow`.
- Redirects: `/v5/*` to the unprefixed equivalent (bare `/v5` needs its
own rule, since `:path*` expands to an empty Location). The world-docs
and api-reference restructure rules are mirrored onto `/v4/docs/*`, and
every page existing in only one tree gets a version-switcher fallback.
- Both worlds route trees pass an explicit version into the shared page
components, whose semantics flipped with the switch, so the smoke checks
now assert the pairing: a " · v4" title marker and noindex on the
maintenance routes, neither on the canonical ones, and a community world
serving directly rather than self-redirecting.
- The link lint's two URL spaces swap with the prefixes. Redirect
destinations resolve against the real HTTP space, since redirects are
matched before render-time href rewriting.
- The two `/v4/...` links this makes expressible are restored: a v5 page
cannot link to a v4 page while v4 is the unprefixed version.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sweep of everything that landed on main since the last content refresh,
plus the spec-7 sealed log from #3634, which is not merged but is the
default for v5.
Spec 7 changes what a World declares, so the upgrade guide's Spec
versions section is rewritten around `mintedSpecVersion()`. The accepted
range widens back to two versions, because a deployment with
`WORKFLOW_SEALED_LOG=0` stamps the one below, and both `SPEC_VERSION_CURRENT`
and `SPEC_VERSION_SUPPORTS_SLOT_IDENTITY` become literals by another name
for the purpose of declaring it: neither follows the setting. The new
section says what a sealed log costs an implementer, which for most is
nothing — a World allocating each position at the commit cannot leave a
hole, so it never seals and never writes a `noop`. The obligation belongs
to a World that pre-assigns positions, and the half that binds everyone
is the reader's.
`WORKFLOW_SEALED_LOG` is documented in runtime-tuning, taken verbatim
from #3634 so whichever lands second is a no-op merge. The deep
reference sections that PR writes, in event-sourcing and the World
allocation contract, are left to it.
Two optional World members shipped after the guide was written and were
missing everywhere:
- `events.createBatch` — in the World reference (interface and contract
note), the upgrade guide's optional surface, and the skill. Implementing
it is the declaration, so the note leads with atomicity per attempt and
what a World must reject.
- `runs.waitForTerminalStatus` — same three places. It is also what makes
`await run.returnValue` a long poll rather than an interval, which is
user-facing, so What's new gets it too.
What's new also gains the batched suspension write and the pre-assigned
positions behind it, both under faster-and-cheaper runs where they belong:
neither has any API surface.
Not addressed: `workflow.step.execute.duration`, the OpenTelemetry
histogram added in #3526, has nowhere to go. The docs have no metrics
reference at all, and inventing one for a single metric is a bigger call
than this sweep.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@github-actions

github-actionsBot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

🧪 E2E Test Results

Some tests failed

❌ Failed E2E Tests

▲ Vercel Production (8 failed)

python-node (8 failed):

  • promiseAllWorkflow | wrun_41M0XAGXS00GK4H9P4BRDADZPF | 🔍 observability
  • sleepingWorkflow | wrun_41M0XAHK4C0GN8PMSN1G5MJ54R | 🔍 observability
  • parallelSleepWorkflow | wrun_41M0XAHKR70GX6C8R38YRX9JZR | 🔍 observability
  • nullByteWorkflow | wrun_41M0XAHTBJ0GPJDS4V1JB075V8 | 🔍 observability
  • cancelRun - cancelling a running workflow | wrun_41M0XAPE6F0GWZ7WFMJS2WQSZ7 | 🔍 observability
  • cancelRun via CLI - cancelling a running workflow | wrun_41M0XAPJ5Y0GVZ8EPNJZZFBXBN | 🔍 observability
  • sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration | wrun_41M0XAPTHD0GRRQPJZEA3CS0X9 | 🔍 observability
  • resilient start: addTenWorkflow completes when run_created returns 500 | wrun_41M0XAQ8AD0GG3DEEMY8R682VV | 🔍 observability

🌐 Cross-language Conformance (9 failed)

python (9 failed):

  • deploymentId: 'latest' is a no-op in non-Vercel worlds | wrun_01M0XASD1GCVQ8X0DC4TD9QQ8K
  • promiseAllWorkflow | wrun_41M0XAGXS00GK4H9P4BRDADZPF
  • sleepingWorkflow | wrun_41M0XAHK4C0GN8PMSN1G5MJ54R
  • parallelSleepWorkflow | wrun_41M0XAHKR70GX6C8R38YRX9JZR
  • nullByteWorkflow | wrun_41M0XAHTBJ0GPJDS4V1JB075V8
  • cancelRun - cancelling a running workflow | wrun_41M0XAPE6F0GWZ7WFMJS2WQSZ7
  • cancelRun via CLI - cancelling a running workflow | wrun_41M0XAPJ5Y0GVZ8EPNJZZFBXBN
  • sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration | wrun_41M0XAPTHD0GRRQPJZEA3CS0X9
  • resilient start: addTenWorkflow completes when run_created returns 500 | wrun_41M0XAQ8AD0GG3DEEMY8R682VV

⚠️ Flaky E2E Tests (passed on retry)

These tests failed at least once and passed on a retry. A recurring entry here is a real race worth investigating.

  • addTenWorkflow (express)
  • cancelRun via CLI - cancelling a running workflow (nextjs-turbopack)
  • hookWithSleepWorkflow - hook payloads delivered correctly with concurrent sleep (nextjs-webpack)
  • promiseAllWorkflow (nuxt)
  • RetryableError respects custom retryAfter delay (nitro)

🛠 Infra Events (absorbed by the harness)

Platform anomalies the e2e harness detected and worked around (e.g. a run the queue never picked up, replaced by a fresh run). Clustered timestamps indicate a backend blip; a steady drip indicates a platform issue worth escalating.

35 infra events
  • cold-start-warmup · suite warmup (python) · at 20:42:37Z · abandoned wrun_41M0XAEJYH0GKQ4W94H3ETH1ZY · (+7 more)
  • run-pickup-stall · nullByteWorkflow (python) · at 20:42:53Z · abandoned wrun_41M0XAJ7Y50GK8N5JNCV12GV8E
  • run-pickup-stall · parallelSleepWorkflow (python) · at 20:42:53Z · abandoned wrun_41M0XAJ7Y20GSX8SWCTH5RVR9M
  • run-pickup-stall · promiseAllWorkflow (python) · at 20:42:53Z · abandoned wrun_41M0XAJ7XV0GG32EEKFRD3B8FS
  • run-pickup-stall · sleepingWorkflow (python) · at 20:42:54Z · abandoned wrun_41M0XAJ7Y20GSX8SWCTH5RVR9K
  • run-pickup-stall · cancelRun - cancelling a running workflow (python) · at 20:42:54Z · abandoned wrun_41M0XAJ8BJ0GJZX1BNBA4CH8W8
  • run-pickup-stall · cancelRun - cancelling a running workflow (python) · at 20:43:27Z · abandoned wrun_41M0XAK8KD0GGARJ5E9EAKDQA7
  • run-pickup-stall · parallelSleepWorkflow (python) · at 20:43:54Z · abandoned wrun_41M0XAM3J00GNDEKT3M4EV9A3B
  • run-pickup-stall · nullByteWorkflow (python) · at 20:43:54Z · abandoned wrun_41M0XAM3J50GY1Z4PYVB875JW2
  • run-pickup-stall · sleepingWorkflow (python) · at 20:43:55Z · abandoned wrun_41M0XAM3NR0GMY2WC43XC9WEEG
  • run-pickup-stall · promiseAllWorkflow (python) · at 20:43:55Z · abandoned wrun_41M0XAM3PT0GKQPBP2CXFAYS50
  • cold-start-warmup · suite warmup (tanstack-start) · at 20:44:26Z · abandoned wrun_01M0XAMQCG384J98J2DSD14DR1
  • run-pickup-stall · cancelRun via CLI - cancelling a running workflow (python) · at 20:44:45Z · abandoned wrun_41M0XAM8FN0GV4BFNTQPWFKM5X
  • cold-start-warmup · suite warmup (python) · at 20:45:16Z · abandoned wrun_01M0XAKEM09ZDGG4DKY24BNT4R · (+7 more)
  • run-pickup-stall · deploymentId: 'latest' is a no-op in non-Vercel worlds (python) · at 20:45:31Z · abandoned wrun_01M0XAQ3RETMHB830AKZR4WRR3
  • run-pickup-stall · promiseAllWorkflow (python) · at 20:45:31Z · abandoned wrun_01M0XAQ3RF7PEAZN9P8KWR413P
  • run-pickup-stall · parallelSleepWorkflow (python) · at 20:45:31Z · abandoned wrun_01M0XAQ3RP7BN47JKYJVR7W9SN
  • run-pickup-stall · sleepingWorkflow (python) · at 20:45:31Z · abandoned wrun_01M0XAQ3RNB63W8SCJMFB059TD
  • run-pickup-stall · nullByteWorkflow (python) · at 20:45:31Z · abandoned wrun_01M0XAQ3RRZXSHD6R9Y4Q7HMN3
  • run-pickup-stall · cancelRun via CLI - cancelling a running workflow (python) · at 20:46:27Z · abandoned wrun_41M0XAQ0C60GXEJ7JBYYKRXP7W
  • run-pickup-stall · sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration (python) · at 20:46:28Z · abandoned wrun_41M0XAPVEJ0GJSWRFAK9D97ABV
  • run-pickup-stall · deploymentId: 'latest' is a no-op in non-Vercel worlds (python) · at 20:46:31Z · abandoned wrun_01M0XARYC38T4GCYXDEWNVNMX3
  • run-pickup-stall · promiseAllWorkflow (python) · at 20:46:31Z · abandoned wrun_01M0XARYC52C67FSA4N73VC5D7
  • run-pickup-stall · sleepingWorkflow (python) · at 20:46:31Z · abandoned wrun_01M0XARYCDFV9BC8DR74AKYXE5
  • run-pickup-stall · parallelSleepWorkflow (python) · at 20:46:32Z · abandoned wrun_01M0XARYCK0DC47WQPD9BH1JVJ
  • run-pickup-stall · nullByteWorkflow (python) · at 20:46:32Z · abandoned wrun_01M0XARYCM1HBYVNK0S93X5J0W
  • run-pickup-stall · cancelRun - cancelling a running workflow (python) · at 20:47:32Z · abandoned wrun_01M0XATRZQVJRSD3M331XYF0RA
  • run-pickup-stall · cancelRun via CLI - cancelling a running workflow (python) · at 20:47:32Z · abandoned wrun_01M0XATRZZS9C3MF3DY87TKVW5
  • run-pickup-stall · sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration (python) · at 20:47:32Z · abandoned wrun_01M0XATS031XZTYSFHCRKFRY0Z
  • run-pickup-stall · cancelRun - cancelling a running workflow (python) · at 20:48:02Z · abandoned wrun_01M0XAVPAX8XNNRK46QNQJ2XK9
  • run-pickup-stall · cancelRun via CLI - cancelling a running workflow (python) · at 20:48:02Z · abandoned wrun_01M0XAVPBFHXMMMA4YG99N83D1
  • run-pickup-stall · sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration (python) · at 20:48:32Z · abandoned wrun_01M0XAWKK6KJ97YQH5T3M65MQN
  • run-pickup-stall · plainModuleDoneHook resumed via plain API route (o2flow shape) (nextjs-webpack) · at 20:51:44Z · abandoned wrun_01M0XB2FMN0D9JTJB906JH00C2
  • run-pickup-stall · hookWithSleepFinalStepWorkflow - step only on final payload (nextjs-webpack) · at 20:52:05Z · abandoned wrun_01M0XB34HFYH9Y559Y5VFH0QKY
  • run-pickup-stall · sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration (nextjs-webpack) · at 20:52:06Z · abandoned wrun_01M0XB34PXRGGCJBBBPNXBSAQW

E2E Test Summary

Summary
PassedFailedSkippedTotal
❌ ▲ Vercel Production357087424320
✅ 💻 Local Development392205584480
✅ 📦 Local Production392205584480
✅ 🐘 Local Postgres392205584480
✅ 🪟 Windows32000320
❌ 🌐 Cross-language Conformance09132141
✅ vercel-http-transport8170143960
✅ vercel-multi-region270027
✅ vercel-ws-transport553087640
Total1705317277819848
Details by Category

❌ ▲ Vercel Production

AppPassedFailedSkipped
✅ astro-node132028
✅ astro-quickjs132028
✅ example-node132028
✅ example-quickjs132028
✅ express-node132028
✅ express-quickjs132028
✅ fastify-node132028
✅ fastify-quickjs132028
✅ hono-node132028
✅ hono-quickjs132028
✅ nest-node132028
✅ nest-quickjs132028
✅ nextjs-turbopack-node15703
✅ nextjs-turbopack-quickjs15703
✅ nextjs-webpack-node15703
✅ nextjs-webpack-quickjs15703
✅ nitro-node132028
✅ nitro-quickjs132028
✅ nuxt-node132028
✅ nuxt-quickjs132028
❌ python-node08152
✅ sveltekit-node15109
✅ sveltekit-quickjs15109
✅ tanstack-start-node132028
✅ tanstack-start-quickjs132028
✅ vite-node132028
✅ vite-quickjs132028

✅ 💻 Local Development

AppPassedFailedSkipped
✅ astro-stable-node134026
✅ astro-stable-quickjs134026
✅ express-stable-node134026
✅ express-stable-quickjs134026
✅ fastify-stable-node134026
✅ fastify-stable-quickjs134026
✅ hono-stable-node134026
✅ hono-stable-quickjs134026
✅ nest-stable-node134026
✅ nest-stable-quickjs134026
✅ nextjs-turbopack-canary-node141019
✅ nextjs-turbopack-canary-quickjs141019
✅ nextjs-turbopack-stable-node16000
✅ nextjs-turbopack-stable-quickjs16000
✅ nextjs-webpack-canary-node141019
✅ nextjs-webpack-canary-quickjs141019
✅ nextjs-webpack-stable-node16000
✅ nextjs-webpack-stable-quickjs16000
✅ nitro-stable-node134026
✅ nitro-stable-quickjs134026
✅ nuxt-stable-node134026
✅ nuxt-stable-quickjs134026
✅ sveltekit-stable-node15307
✅ sveltekit-stable-quickjs15307
✅ tanstack-start-node134026
✅ tanstack-start-quickjs134026
✅ vite-stable-node134026
✅ vite-stable-quickjs134026

✅ 📦 Local Production

AppPassedFailedSkipped
✅ astro-stable-node134026
✅ astro-stable-quickjs134026
✅ express-stable-node134026
✅ express-stable-quickjs134026
✅ fastify-stable-node134026
✅ fastify-stable-quickjs134026
✅ hono-stable-node134026
✅ hono-stable-quickjs134026
✅ nest-stable-node134026
✅ nest-stable-quickjs134026
✅ nextjs-turbopack-canary-node141019
✅ nextjs-turbopack-canary-quickjs141019
✅ nextjs-turbopack-stable-node16000
✅ nextjs-turbopack-stable-quickjs16000
✅ nextjs-webpack-canary-node141019
✅ nextjs-webpack-canary-quickjs141019
✅ nextjs-webpack-stable-node16000
✅ nextjs-webpack-stable-quickjs16000
✅ nitro-stable-node134026
✅ nitro-stable-quickjs134026
✅ nuxt-stable-node134026
✅ nuxt-stable-quickjs134026
✅ sveltekit-stable-node15307
✅ sveltekit-stable-quickjs15307
✅ tanstack-start-node134026
✅ tanstack-start-quickjs134026
✅ vite-stable-node134026
✅ vite-stable-quickjs134026

✅ 🐘 Local Postgres

AppPassedFailedSkipped
✅ astro-stable-node134026
✅ astro-stable-quickjs134026
✅ express-stable-node134026
✅ express-stable-quickjs134026
✅ fastify-stable-node134026
✅ fastify-stable-quickjs134026
✅ hono-stable-node134026
✅ hono-stable-quickjs134026
✅ nest-stable-node134026
✅ nest-stable-quickjs134026
✅ nextjs-turbopack-canary-node141019
✅ nextjs-turbopack-canary-quickjs141019
✅ nextjs-turbopack-stable-node16000
✅ nextjs-turbopack-stable-quickjs16000
✅ nextjs-webpack-canary-node141019
✅ nextjs-webpack-canary-quickjs141019
✅ nextjs-webpack-stable-node16000
✅ nextjs-webpack-stable-quickjs16000
✅ nitro-stable-node134026
✅ nitro-stable-quickjs134026
✅ nuxt-stable-node134026
✅ nuxt-stable-quickjs134026
✅ sveltekit-stable-node15307
✅ sveltekit-stable-quickjs15307
✅ tanstack-start-node134026
✅ tanstack-start-quickjs134026
✅ vite-stable-node134026
✅ vite-stable-quickjs134026

✅ 🪟 Windows

AppPassedFailedSkipped
✅ nextjs-turbopack-node16000
✅ nextjs-turbopack-quickjs16000

❌ 🌐 Cross-language Conformance

AppPassedFailedSkipped
❌ python09132

✅ vercel-http-transport

AppPassedFailedSkipped
✅ example132028
✅ express132028
✅ hono132028
✅ nextjs-turbopack15703
✅ nitro132028
✅ vite132028

✅ vercel-multi-region

AppPassedFailedSkipped
✅ nextjs-turbopack2700

✅ vercel-ws-transport

AppPassedFailedSkipped
✅ example132028
✅ express132028
✅ nextjs-turbopack15703
✅ vite132028

📋 View full workflow run

#3779 fixed the app migration skill, whose description ended with
`mode: 'client'`. The colon-space made the plain scalar parse as a nested
mapping, and the skills CLI dropped the file: `Found 5 skills`, and
`--skill migrating-workflow-v4-to-v5` answered `No matching skills
found`, which is the command whats-new.mdx tells readers to run.
The World skill's description has no colon-space today, so it parses.
It is also 590 characters of backticked identifiers, and any future
edit naming a field with its value reintroduces the break. Fold it the
same way now, while the value is known good. Verified with the yaml
package that the folded scalar is byte-identical, and with
`skills add . --skill migrating-world-v4-to-v5` that the CLI still
finds all six.
Signed-off-by: Peter Wielander <peter.wielander@vercel.com>
@github-actions

Copy link
Copy Markdown
Contributor
FrameworkFlow routeStep reg.Framework output
hono200.9 KiB (±0)40.5 KiB (±0)1.76 MiB (±0)
nextjs-turbopack206.3 KiB (±0)439 B (±0)762.8 KiB (±0)
About these numbers

Sizes are gzip; parentheses show the change against main.
Flow route and Step reg. gate this job, on raw bytes rather than the gzip shown, at max(2%, 50.0 KiB). Framework output is informational.

8d9081b · run

Sign up for freeto 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.

1 participant

@VaguelySerious
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' [docs] Make v5 the default documentation version by VaguelySerious · Pull Request #3714 · vercel/workflow · GitHub
Skip to content

[docs] Make v5 the default documentation version - #3714

Open
VaguelySerious wants to merge 5 commits into
mainfrom
peter/docs-v5-default
Open

[docs] Make v5 the default documentation version#3714
VaguelySerious wants to merge 5 commits into
mainfrom
peter/docs-v5-default

Conversation

@VaguelySerious

@VaguelySeriousVaguelySerious commented Aug 21, 2026

Copy link
Copy Markdown
Member

Makes v5 the default documentation version for the 5.0.0 GA, and catches the v5 content up with everything that landed on main since the v5 docs were last refreshed. Companion to #3090 (exit changeset pre mode) and #3091 (pin 4.x publishes to previous).

Version flip and routing

content/docs/v5 and content/worlds/v5 now serve unprefixed — /docs, /worlds, /cookbook — and v4 moves under a /v4 prefix. The versioned source config drives both route trees (the root tree always renders versionedSources.current), so this is a routePrefix move plus source re-binding, not a restructure. The only file moves are app/[lang]/v5/**app/[lang]/v4/**.

  • Version switcher: labels are v5 (Latest) / v4 (Maintenance); current: 'v5'.
  • Banner: pre-release-banner.tsxmaintenance-banner.tsx. v4 pages carry an amber notice (with dark-mode styling) whose "Go to Workflow 5 (Latest)" link deep-links to the same page on the current version; v4-only pages land on the nearest section index via the fallback redirects. v4 pages keep robots: noindex, follow.
  • Redirects (docs/next.config.ts): /v5/* → unprefixed equivalent (permanent; bare /v5 gets its own rule because :path* expands to an empty Location otherwise). The world-docs and api-reference restructure rules are mirrored onto /v4/docs/*, and every page that exists in only one tree has a version-switcher fallback (verified by diffing the two content trees).
  • Worlds routes: both the unprefixed and /v4 worlds routes pass an explicit version into the shared page components, whose semantics flipped with the switch — smoke checks (assertWorldVersionMarkers, assertServesDirectly('/worlds/turso')) now guard the pairing so the canonical /worlds/* pages can't silently serve the maintenance version or self-redirect-loop again.
  • Link lint (docs/scripts/lint.ts): the two-space model swaps with the URL space; redirect destinations resolve against the real HTTP space since redirects are matched before render-time href rewriting.
  • Intentional oddity: rewriteHrefForVersion pulls unprefixed hrefs on v4 pages into the /v4 view, so a /v5/... href is the only way for v4 content to point at a current page. Three such links are kept deliberately; the lint models this.

What moves with the flip

  • whats-new enters the v5 sidebar, first in the tree. [docs] v5 GA content: What's new, World upgrade guide, migration skills #3100 adds the page but leaves it out of content/docs/v5/meta.json, so until this lands it is reachable only by URL.
  • upgrading-to-v5 moves from app/[lang]/v5/worlds/ to app/[lang]/worlds/, following the rest of the v5 worlds routes.
  • Two cross-version links become expressible and are restored. While v4 is the unprefixed version, a v5 page cannot link to a v4 page at all: an unprefixed href on a v5 page is rewritten into the /v5 view. [docs] v5 GA content: What's new, World upgrade guide, migration skills #3100 therefore phrases both as pointers to the version picker. Here they go back to being links — the v4 docs entry point in the What's new callout, and the v4 version of the code-transform page.
  • editPath on the unprefixed docs route points at docs/content/docs/v5/{path}.

Catch-up with main

Swept the 53 commits that landed since the last content refresh, and added what the docs were missing. Most changesets in that window are fixes, internal, or already documented by their own PR; three things were not.

Spec 7, the sealed log (#3634, not merged, default for v5). Positions are handed out ahead of the commit instead of being claimed by the write that fills them, so concurrent writers never contend and a wide fan-out stops serializing. The cost is a position whose writer dies, which the backend closes with a noop event that replay steps over without delivering it and without advancing the deterministic clock.

  • upgrading-to-v5 › Spec versions is rewritten around mintedSpecVersion(). The accepted range widens back to two versions, because a deployment with WORKFLOW_SEALED_LOG=0 stamps the one below, and that makes both SPEC_VERSION_CURRENT and SPEC_VERSION_SUPPORTS_SLOT_IDENTITY literals by another name for declaring it — neither follows the setting. This replaces what [docs] v5 GA content: What's new, World upgrade guide, migration skills #3100 said for spec 6, which was that exactly one version is accepted.
  • A new "Sealed logs and noop events" subsection says what this costs an implementer, which for most is nothing: a World allocating each position at the commit cannot leave a hole, so it never seals and never emits a noop. The obligation belongs to a World that pre-assigns positions; the half that binds everyone is the reader's.
  • WORKFLOW_SEALED_LOG is documented in runtime-tuning, taken verbatim from Add support for 'noop' event type - spec version 7 #3634 so whichever lands second is a no-op merge. The deep reference sections that PR writes — in event-sourcing and the World allocation contract — are left to it, so this does not duplicate them.
  • The migration skill (v0.2.0) gets the same treatment, phrased as findings to report rather than edits to make.

events.createBatch (#3025). An optional World method appending an ordered list of events in one durable write with per-event outcomes. It was documented only as a changelog page and an env var, so the World reference had no mention of a method a World author has to decide about. Added to the interface snippet, to the Key Implementation Details as a contract note (atomicity per attempt, what a World must reject, the one legal same-entity pair), to the upgrade guide's optional surface, and to the skill.

runs.waitForTerminalStatus (#3570). Also missing from the upgrade guide and the skill. It is what makes await run.returnValue a long poll rather than an interval, which is user-facing, so What's new gets that as an entry.

What's new also gains the batched suspension write and the positions change under faster-and-cheaper runs, where they belong: neither has any API surface.

Not addressed.workflow.step.execute.duration, the OpenTelemetry histogram from #3526, has nowhere to go — the docs carry no metrics reference at all, and inventing one for a single metric is a bigger call than this sweep. Flagging rather than guessing.

Second catch-up: the WebSocket default and spec 7

Merged main again (13 commits). Four conflicts, all against #3704's writing-standards pass over the whole corpus, which rewrote the same paragraphs this branch had edited. Took main's normalized text wherever the difference was purely style, kept this branch's meaning where the two disagreed (the spec-7 paragraph main still had at spec 6, the /v4/... link the flip makes expressible, the batch-write contract note), and restyled this branch's own additions so no prose em dashes come back with it.

The WebSocket events transport is the default now.#3702 flipped it and updated worlds.mdx, vercel.mdx and runtime-tuning.mdx, but What's new still said "an opt-in WebSocket transport ... HTTP remains the default", which was the most wrong sentence left in the v5 docs. It now says what happens, that only the exact value http opts out so a typo fails toward the socket, and that tracing is unchanged because the client span is synthesized around the frame.

Spec 7 is settled.#3634 landed, then #3735 made the sealed log opt-in, then #3737 re-enabled it. The end state matches what this branch already documented, and the WORKFLOW_SEALED_LOG section I had taken verbatim merged as the no-op it was meant to be, modulo #3704's restyling. mintedSpecVersion(), the two-version accepted range, and the "if you allocate at the commit you are already compliant" framing all still hold.

Three World-developer notes, all from #3728. These are the ones a custom World cannot discover from its type errors:

  • Process-wide state has to live on globalThis. A module's top-level const/let is one instance per module instance, and a bundler compiles one copy per layer. The runtime caches the World object process-wide while module state it closes over stays layer-local, so anything a World reaches at request time has to be process-wide too. New contract note in the upgrade guide, plus a step of its own in the World skill (v0.3.0) with an intake item, a globalSingleton() example including what the shape version is for, an output-shape section, and a failure-checklist line. Documented by its casualty: the WS transport registered its channel in the route layer's registry and the write path read the instrumentation layer's empty one, so every event fell back to HTTP for the life of the process, with nothing logged and no test failing.
  • One World per process. The entrypoint's queue handler is built from getWorld() instead of getWorldHandlers(), so a stateful World stops getting duplicate connection pools and queue workers. The build-integration row that still pointed custom hosts at getWorldHandlers() is corrected: that export is the build-time view, not how a request-time handler is assembled.
  • A World's transport is its own business, except for the tracing. How a World ships events is unconstrained. What is constrained is that a non-HTTP transport still owes the per-event client span an HTTP write would emit, or the per-event view of a run silently disappears. Points at the Vercel World's span shape as the worked example.

Nothing needed for the remaining commits in the window: globalSingleton's own changeset and the sideEffects: false declaration are internal, the wait-continuation re-arm and the atomic step_created commit are fixes to behavior already documented, and the decrypt-control and trace-name changes are dashboard-side.

Verification

Link lint passes with 0 errors. pnpm build compiles, with /en/docs/whats-new prerendered under the unprefixed route, /[lang]/v4/docs/[[...slug]] serving the maintenance tree, and ƒ /[lang]/worlds/upgrading-to-v5.

Docs Preview

Links will be added from the workflow-docs preview once it deploys.

🤖 Generated with Claude Code

@vercel

vercelBot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated (UTC)
example-nextjs-workflow-turbopackReadyReadyPreview, v0Aug 25, 2026 8:40pm
example-nextjs-workflow-webpackReadyReadyPreview, v0Aug 25, 2026 8:40pm
example-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-astro-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-express-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-fastify-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-hono-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-nestjs-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-nitro-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-nuxt-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-python-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-sveltekit-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-tanstack-start-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-vite-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workflow-docsReadyReadyPreview, v0Aug 25, 2026 8:40pm
workflow-swc-playgroundBuildingBuildingPreview, v0Aug 25, 2026 8:40pm
workflow-tarballsReadyReadyPreview, v0Aug 25, 2026 8:40pm
workflow-webReadyReadyPreview, v0Aug 25, 2026 8:40pm

@changeset-bot

changeset-botBot commented Aug 21, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 8d9081b

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 0 packages

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions

github-actionsBot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Sim World

Simulated world deterministic testing for races. Traces

🟠 world-sim scenario book — 1 fail of 41 total

fence=per-spec

scenariooutcomeeventsvirtreplayviolations
smoke-no-stepscompleted30msok0
smoke-one-stepcompleted60msok0
hook-at-step-startedcompleted120msok0
hook-at-step-completedcompleted120msok0
hook-at-hook-createdcompleted120msok0
deadline-hook-winscompleted71.0hok0
deadline-expirescompleted71.0hok0
long-sleepcompleted1130.0dok0
hook-never-arrivesstalled30msskipped0
step-retries-twicecompleted102.0sok0
parallel-stepscompleted90msok0
hook-on-execution-statecompleted120msok0
peek-hook-before-branchcompleted120msok0
peek-hook-after-branchcompleted120msok0
peek-hook-at-registrationcompleted120msok0
race-hook-before-probecompleted120msok0
race-hook-after-probecompleted120msok0
race-duplicate-deliverycompleted130msok0
attr-hook-before-stepcompleted110msok0
attr-hook-after-stepcompleted110msok0
attr-from-step-bodycompleted130msok0
fork-hook-after-timeoutcompleted141.0mok0
fork-hook-before-timeoutcompleted141.0mok0
count-hook-after-timeoutcompleted171.0mok0
count-hook-before-timeoutcompleted201.0mok0
stale-read-step-count-forkcompleted201.0mok0
stale-read-equal-step-countscompleted141.0mok0
step-vs-step-forkcompleted120msok0
step-vs-step-fork-fencedcompleted120msok0
fence-catches-benign-directioncompleted125msok0
in-flight-before-decisioncompleted171.0mok0
in-flight-before-decision-countedcompleted171.0mok0
in-flight-after-decisioncompleted192.0mok0
stale-read-step-count-fork-fencedcompleted201.0mok0
fork-hook-winscompleted131.0mok0
fork-timeout-winscompleted131.0mok0
unclaimed-payload-under-forkcompleted171.0mok0
claimed-payload-under-forkcompleted171.0mok0
writers-independent-step-bodiescompleted120msok0
writers-scripted-tempocompleted120msok0
cancel-mid-stepcancelled70msskipped0

Full trace: world-sim.txt

VaguelySeriousand others added 2 commits August 21, 2026 12:50
Serves `content/docs/v5` and `content/worlds/v5` unprefixed at /docs,
/worlds and /cookbook, moves v4 under /v4, and puts What's new first in
the v5 sidebar.
The versioned source config drives both route trees (the root tree always
renders `versionedSources.current`), so this is a `routePrefix` move plus
source re-binding rather than a restructure. The only file moves are
`app/[lang]/v5/**` → `app/[lang]/v4/**`.
- Version switcher: `v5 (Latest)` / `v4 (Maintenance)`, `current: 'v5'`.
- `pre-release-banner.tsx` becomes `maintenance-banner.tsx`. v4 pages
carry an amber notice whose "Go to Workflow 5 (Latest)" link deep-links
to the same page on the current version, falling back to the nearest
section index for v4-only pages, and keep `robots: noindex, follow`.
- Redirects: `/v5/*` to the unprefixed equivalent (bare `/v5` needs its
own rule, since `:path*` expands to an empty Location). The world-docs
and api-reference restructure rules are mirrored onto `/v4/docs/*`, and
every page existing in only one tree gets a version-switcher fallback.
- Both worlds route trees pass an explicit version into the shared page
components, whose semantics flipped with the switch, so the smoke checks
now assert the pairing: a " · v4" title marker and noindex on the
maintenance routes, neither on the canonical ones, and a community world
serving directly rather than self-redirecting.
- The link lint's two URL spaces swap with the prefixes. Redirect
destinations resolve against the real HTTP space, since redirects are
matched before render-time href rewriting.
- The two `/v4/...` links this makes expressible are restored: a v5 page
cannot link to a v4 page while v4 is the unprefixed version.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sweep of everything that landed on main since the last content refresh,
plus the spec-7 sealed log from #3634, which is not merged but is the
default for v5.
Spec 7 changes what a World declares, so the upgrade guide's Spec
versions section is rewritten around `mintedSpecVersion()`. The accepted
range widens back to two versions, because a deployment with
`WORKFLOW_SEALED_LOG=0` stamps the one below, and both `SPEC_VERSION_CURRENT`
and `SPEC_VERSION_SUPPORTS_SLOT_IDENTITY` become literals by another name
for the purpose of declaring it: neither follows the setting. The new
section says what a sealed log costs an implementer, which for most is
nothing — a World allocating each position at the commit cannot leave a
hole, so it never seals and never writes a `noop`. The obligation belongs
to a World that pre-assigns positions, and the half that binds everyone
is the reader's.
`WORKFLOW_SEALED_LOG` is documented in runtime-tuning, taken verbatim
from #3634 so whichever lands second is a no-op merge. The deep
reference sections that PR writes, in event-sourcing and the World
allocation contract, are left to it.
Two optional World members shipped after the guide was written and were
missing everywhere:
- `events.createBatch` — in the World reference (interface and contract
note), the upgrade guide's optional surface, and the skill. Implementing
it is the declaration, so the note leads with atomicity per attempt and
what a World must reject.
- `runs.waitForTerminalStatus` — same three places. It is also what makes
`await run.returnValue` a long poll rather than an interval, which is
user-facing, so What's new gets it too.
What's new also gains the batched suspension write and the pre-assigned
positions behind it, both under faster-and-cheaper runs where they belong:
neither has any API surface.
Not addressed: `workflow.step.execute.duration`, the OpenTelemetry
histogram added in #3526, has nowhere to go. The docs have no metrics
reference at all, and inventing one for a single metric is a bigger call
than this sweep.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@github-actions

github-actionsBot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

🧪 E2E Test Results

Some tests failed

❌ Failed E2E Tests

▲ Vercel Production (8 failed)

python-node (8 failed):

  • promiseAllWorkflow | wrun_41M0XAGXS00GK4H9P4BRDADZPF | 🔍 observability
  • sleepingWorkflow | wrun_41M0XAHK4C0GN8PMSN1G5MJ54R | 🔍 observability
  • parallelSleepWorkflow | wrun_41M0XAHKR70GX6C8R38YRX9JZR | 🔍 observability
  • nullByteWorkflow | wrun_41M0XAHTBJ0GPJDS4V1JB075V8 | 🔍 observability
  • cancelRun - cancelling a running workflow | wrun_41M0XAPE6F0GWZ7WFMJS2WQSZ7 | 🔍 observability
  • cancelRun via CLI - cancelling a running workflow | wrun_41M0XAPJ5Y0GVZ8EPNJZZFBXBN | 🔍 observability
  • sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration | wrun_41M0XAPTHD0GRRQPJZEA3CS0X9 | 🔍 observability
  • resilient start: addTenWorkflow completes when run_created returns 500 | wrun_41M0XAQ8AD0GG3DEEMY8R682VV | 🔍 observability

🌐 Cross-language Conformance (9 failed)

python (9 failed):

  • deploymentId: 'latest' is a no-op in non-Vercel worlds | wrun_01M0XASD1GCVQ8X0DC4TD9QQ8K
  • promiseAllWorkflow | wrun_41M0XAGXS00GK4H9P4BRDADZPF
  • sleepingWorkflow | wrun_41M0XAHK4C0GN8PMSN1G5MJ54R
  • parallelSleepWorkflow | wrun_41M0XAHKR70GX6C8R38YRX9JZR
  • nullByteWorkflow | wrun_41M0XAHTBJ0GPJDS4V1JB075V8
  • cancelRun - cancelling a running workflow | wrun_41M0XAPE6F0GWZ7WFMJS2WQSZ7
  • cancelRun via CLI - cancelling a running workflow | wrun_41M0XAPJ5Y0GVZ8EPNJZZFBXBN
  • sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration | wrun_41M0XAPTHD0GRRQPJZEA3CS0X9
  • resilient start: addTenWorkflow completes when run_created returns 500 | wrun_41M0XAQ8AD0GG3DEEMY8R682VV

⚠️ Flaky E2E Tests (passed on retry)

These tests failed at least once and passed on a retry. A recurring entry here is a real race worth investigating.

  • addTenWorkflow (express)
  • cancelRun via CLI - cancelling a running workflow (nextjs-turbopack)
  • hookWithSleepWorkflow - hook payloads delivered correctly with concurrent sleep (nextjs-webpack)
  • promiseAllWorkflow (nuxt)
  • RetryableError respects custom retryAfter delay (nitro)

🛠 Infra Events (absorbed by the harness)

Platform anomalies the e2e harness detected and worked around (e.g. a run the queue never picked up, replaced by a fresh run). Clustered timestamps indicate a backend blip; a steady drip indicates a platform issue worth escalating.

35 infra events
  • cold-start-warmup · suite warmup (python) · at 20:42:37Z · abandoned wrun_41M0XAEJYH0GKQ4W94H3ETH1ZY · (+7 more)
  • run-pickup-stall · nullByteWorkflow (python) · at 20:42:53Z · abandoned wrun_41M0XAJ7Y50GK8N5JNCV12GV8E
  • run-pickup-stall · parallelSleepWorkflow (python) · at 20:42:53Z · abandoned wrun_41M0XAJ7Y20GSX8SWCTH5RVR9M
  • run-pickup-stall · promiseAllWorkflow (python) · at 20:42:53Z · abandoned wrun_41M0XAJ7XV0GG32EEKFRD3B8FS
  • run-pickup-stall · sleepingWorkflow (python) · at 20:42:54Z · abandoned wrun_41M0XAJ7Y20GSX8SWCTH5RVR9K
  • run-pickup-stall · cancelRun - cancelling a running workflow (python) · at 20:42:54Z · abandoned wrun_41M0XAJ8BJ0GJZX1BNBA4CH8W8
  • run-pickup-stall · cancelRun - cancelling a running workflow (python) · at 20:43:27Z · abandoned wrun_41M0XAK8KD0GGARJ5E9EAKDQA7
  • run-pickup-stall · parallelSleepWorkflow (python) · at 20:43:54Z · abandoned wrun_41M0XAM3J00GNDEKT3M4EV9A3B
  • run-pickup-stall · nullByteWorkflow (python) · at 20:43:54Z · abandoned wrun_41M0XAM3J50GY1Z4PYVB875JW2
  • run-pickup-stall · sleepingWorkflow (python) · at 20:43:55Z · abandoned wrun_41M0XAM3NR0GMY2WC43XC9WEEG
  • run-pickup-stall · promiseAllWorkflow (python) · at 20:43:55Z · abandoned wrun_41M0XAM3PT0GKQPBP2CXFAYS50
  • cold-start-warmup · suite warmup (tanstack-start) · at 20:44:26Z · abandoned wrun_01M0XAMQCG384J98J2DSD14DR1
  • run-pickup-stall · cancelRun via CLI - cancelling a running workflow (python) · at 20:44:45Z · abandoned wrun_41M0XAM8FN0GV4BFNTQPWFKM5X
  • cold-start-warmup · suite warmup (python) · at 20:45:16Z · abandoned wrun_01M0XAKEM09ZDGG4DKY24BNT4R · (+7 more)
  • run-pickup-stall · deploymentId: 'latest' is a no-op in non-Vercel worlds (python) · at 20:45:31Z · abandoned wrun_01M0XAQ3RETMHB830AKZR4WRR3
  • run-pickup-stall · promiseAllWorkflow (python) · at 20:45:31Z · abandoned wrun_01M0XAQ3RF7PEAZN9P8KWR413P
  • run-pickup-stall · parallelSleepWorkflow (python) · at 20:45:31Z · abandoned wrun_01M0XAQ3RP7BN47JKYJVR7W9SN
  • run-pickup-stall · sleepingWorkflow (python) · at 20:45:31Z · abandoned wrun_01M0XAQ3RNB63W8SCJMFB059TD
  • run-pickup-stall · nullByteWorkflow (python) · at 20:45:31Z · abandoned wrun_01M0XAQ3RRZXSHD6R9Y4Q7HMN3
  • run-pickup-stall · cancelRun via CLI - cancelling a running workflow (python) · at 20:46:27Z · abandoned wrun_41M0XAQ0C60GXEJ7JBYYKRXP7W
  • run-pickup-stall · sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration (python) · at 20:46:28Z · abandoned wrun_41M0XAPVEJ0GJSWRFAK9D97ABV
  • run-pickup-stall · deploymentId: 'latest' is a no-op in non-Vercel worlds (python) · at 20:46:31Z · abandoned wrun_01M0XARYC38T4GCYXDEWNVNMX3
  • run-pickup-stall · promiseAllWorkflow (python) · at 20:46:31Z · abandoned wrun_01M0XARYC52C67FSA4N73VC5D7
  • run-pickup-stall · sleepingWorkflow (python) · at 20:46:31Z · abandoned wrun_01M0XARYCDFV9BC8DR74AKYXE5
  • run-pickup-stall · parallelSleepWorkflow (python) · at 20:46:32Z · abandoned wrun_01M0XARYCK0DC47WQPD9BH1JVJ
  • run-pickup-stall · nullByteWorkflow (python) · at 20:46:32Z · abandoned wrun_01M0XARYCM1HBYVNK0S93X5J0W
  • run-pickup-stall · cancelRun - cancelling a running workflow (python) · at 20:47:32Z · abandoned wrun_01M0XATRZQVJRSD3M331XYF0RA
  • run-pickup-stall · cancelRun via CLI - cancelling a running workflow (python) · at 20:47:32Z · abandoned wrun_01M0XATRZZS9C3MF3DY87TKVW5
  • run-pickup-stall · sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration (python) · at 20:47:32Z · abandoned wrun_01M0XATS031XZTYSFHCRKFRY0Z
  • run-pickup-stall · cancelRun - cancelling a running workflow (python) · at 20:48:02Z · abandoned wrun_01M0XAVPAX8XNNRK46QNQJ2XK9
  • run-pickup-stall · cancelRun via CLI - cancelling a running workflow (python) · at 20:48:02Z · abandoned wrun_01M0XAVPBFHXMMMA4YG99N83D1
  • run-pickup-stall · sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration (python) · at 20:48:32Z · abandoned wrun_01M0XAWKK6KJ97YQH5T3M65MQN
  • run-pickup-stall · plainModuleDoneHook resumed via plain API route (o2flow shape) (nextjs-webpack) · at 20:51:44Z · abandoned wrun_01M0XB2FMN0D9JTJB906JH00C2
  • run-pickup-stall · hookWithSleepFinalStepWorkflow - step only on final payload (nextjs-webpack) · at 20:52:05Z · abandoned wrun_01M0XB34HFYH9Y559Y5VFH0QKY
  • run-pickup-stall · sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration (nextjs-webpack) · at 20:52:06Z · abandoned wrun_01M0XB34PXRGGCJBBBPNXBSAQW

E2E Test Summary

Summary
PassedFailedSkippedTotal
❌ ▲ Vercel Production357087424320
✅ 💻 Local Development392205584480
✅ 📦 Local Production392205584480
✅ 🐘 Local Postgres392205584480
✅ 🪟 Windows32000320
❌ 🌐 Cross-language Conformance09132141
✅ vercel-http-transport8170143960
✅ vercel-multi-region270027
✅ vercel-ws-transport553087640
Total1705317277819848
Details by Category

❌ ▲ Vercel Production

AppPassedFailedSkipped
✅ astro-node132028
✅ astro-quickjs132028
✅ example-node132028
✅ example-quickjs132028
✅ express-node132028
✅ express-quickjs132028
✅ fastify-node132028
✅ fastify-quickjs132028
✅ hono-node132028
✅ hono-quickjs132028
✅ nest-node132028
✅ nest-quickjs132028
✅ nextjs-turbopack-node15703
✅ nextjs-turbopack-quickjs15703
✅ nextjs-webpack-node15703
✅ nextjs-webpack-quickjs15703
✅ nitro-node132028
✅ nitro-quickjs132028
✅ nuxt-node132028
✅ nuxt-quickjs132028
❌ python-node08152
✅ sveltekit-node15109
✅ sveltekit-quickjs15109
✅ tanstack-start-node132028
✅ tanstack-start-quickjs132028
✅ vite-node132028
✅ vite-quickjs132028

✅ 💻 Local Development

AppPassedFailedSkipped
✅ astro-stable-node134026
✅ astro-stable-quickjs134026
✅ express-stable-node134026
✅ express-stable-quickjs134026
✅ fastify-stable-node134026
✅ fastify-stable-quickjs134026
✅ hono-stable-node134026
✅ hono-stable-quickjs134026
✅ nest-stable-node134026
✅ nest-stable-quickjs134026
✅ nextjs-turbopack-canary-node141019
✅ nextjs-turbopack-canary-quickjs141019
✅ nextjs-turbopack-stable-node16000
✅ nextjs-turbopack-stable-quickjs16000
✅ nextjs-webpack-canary-node141019
✅ nextjs-webpack-canary-quickjs141019
✅ nextjs-webpack-stable-node16000
✅ nextjs-webpack-stable-quickjs16000
✅ nitro-stable-node134026
✅ nitro-stable-quickjs134026
✅ nuxt-stable-node134026
✅ nuxt-stable-quickjs134026
✅ sveltekit-stable-node15307
✅ sveltekit-stable-quickjs15307
✅ tanstack-start-node134026
✅ tanstack-start-quickjs134026
✅ vite-stable-node134026
✅ vite-stable-quickjs134026

✅ 📦 Local Production

AppPassedFailedSkipped
✅ astro-stable-node134026
✅ astro-stable-quickjs134026
✅ express-stable-node134026
✅ express-stable-quickjs134026
✅ fastify-stable-node134026
✅ fastify-stable-quickjs134026
✅ hono-stable-node134026
✅ hono-stable-quickjs134026
✅ nest-stable-node134026
✅ nest-stable-quickjs134026
✅ nextjs-turbopack-canary-node141019
✅ nextjs-turbopack-canary-quickjs141019
✅ nextjs-turbopack-stable-node16000
✅ nextjs-turbopack-stable-quickjs16000
✅ nextjs-webpack-canary-node141019
✅ nextjs-webpack-canary-quickjs141019
✅ nextjs-webpack-stable-node16000
✅ nextjs-webpack-stable-quickjs16000
✅ nitro-stable-node134026
✅ nitro-stable-quickjs134026
✅ nuxt-stable-node134026
✅ nuxt-stable-quickjs134026
✅ sveltekit-stable-node15307
✅ sveltekit-stable-quickjs15307
✅ tanstack-start-node134026
✅ tanstack-start-quickjs134026
✅ vite-stable-node134026
✅ vite-stable-quickjs134026

✅ 🐘 Local Postgres

AppPassedFailedSkipped
✅ astro-stable-node134026
✅ astro-stable-quickjs134026
✅ express-stable-node134026
✅ express-stable-quickjs134026
✅ fastify-stable-node134026
✅ fastify-stable-quickjs134026
✅ hono-stable-node134026
✅ hono-stable-quickjs134026
✅ nest-stable-node134026
✅ nest-stable-quickjs134026
✅ nextjs-turbopack-canary-node141019
✅ nextjs-turbopack-canary-quickjs141019
✅ nextjs-turbopack-stable-node16000
✅ nextjs-turbopack-stable-quickjs16000
✅ nextjs-webpack-canary-node141019
✅ nextjs-webpack-canary-quickjs141019
✅ nextjs-webpack-stable-node16000
✅ nextjs-webpack-stable-quickjs16000
✅ nitro-stable-node134026
✅ nitro-stable-quickjs134026
✅ nuxt-stable-node134026
✅ nuxt-stable-quickjs134026
✅ sveltekit-stable-node15307
✅ sveltekit-stable-quickjs15307
✅ tanstack-start-node134026
✅ tanstack-start-quickjs134026
✅ vite-stable-node134026
✅ vite-stable-quickjs134026

✅ 🪟 Windows

AppPassedFailedSkipped
✅ nextjs-turbopack-node16000
✅ nextjs-turbopack-quickjs16000

❌ 🌐 Cross-language Conformance

AppPassedFailedSkipped
❌ python09132

✅ vercel-http-transport

AppPassedFailedSkipped
✅ example132028
✅ express132028
✅ hono132028
✅ nextjs-turbopack15703
✅ nitro132028
✅ vite132028

✅ vercel-multi-region

AppPassedFailedSkipped
✅ nextjs-turbopack2700

✅ vercel-ws-transport

AppPassedFailedSkipped
✅ example132028
✅ express132028
✅ nextjs-turbopack15703
✅ vite132028

📋 View full workflow run

#3779 fixed the app migration skill, whose description ended with
`mode: 'client'`. The colon-space made the plain scalar parse as a nested
mapping, and the skills CLI dropped the file: `Found 5 skills`, and
`--skill migrating-workflow-v4-to-v5` answered `No matching skills
found`, which is the command whats-new.mdx tells readers to run.
The World skill's description has no colon-space today, so it parses.
It is also 590 characters of backticked identifiers, and any future
edit naming a field with its value reintroduces the break. Fold it the
same way now, while the value is known good. Verified with the yaml
package that the folded scalar is byte-identical, and with
`skills add . --skill migrating-world-v4-to-v5` that the CLI still
finds all six.
Signed-off-by: Peter Wielander <peter.wielander@vercel.com>
@github-actions

Copy link
Copy Markdown
Contributor
FrameworkFlow routeStep reg.Framework output
hono200.9 KiB (±0)40.5 KiB (±0)1.76 MiB (±0)
nextjs-turbopack206.3 KiB (±0)439 B (±0)762.8 KiB (±0)
About these numbers

Sizes are gzip; parentheses show the change against main.
Flow route and Step reg. gate this job, on raw bytes rather than the gzip shown, at max(2%, 50.0 KiB). Framework output is informational.

8d9081b · run

Sign up for freeto 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.

1 participant

@VaguelySerious
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' [docs] Make v5 the default documentation version by VaguelySerious · Pull Request #3714 · vercel/workflow · GitHub
Skip to content

[docs] Make v5 the default documentation version - #3714

Open
VaguelySerious wants to merge 5 commits into
mainfrom
peter/docs-v5-default
Open

[docs] Make v5 the default documentation version#3714
VaguelySerious wants to merge 5 commits into
mainfrom
peter/docs-v5-default

Conversation

@VaguelySerious

@VaguelySeriousVaguelySerious commented Aug 21, 2026

Copy link
Copy Markdown
Member

Makes v5 the default documentation version for the 5.0.0 GA, and catches the v5 content up with everything that landed on main since the v5 docs were last refreshed. Companion to #3090 (exit changeset pre mode) and #3091 (pin 4.x publishes to previous).

Version flip and routing

content/docs/v5 and content/worlds/v5 now serve unprefixed — /docs, /worlds, /cookbook — and v4 moves under a /v4 prefix. The versioned source config drives both route trees (the root tree always renders versionedSources.current), so this is a routePrefix move plus source re-binding, not a restructure. The only file moves are app/[lang]/v5/**app/[lang]/v4/**.

  • Version switcher: labels are v5 (Latest) / v4 (Maintenance); current: 'v5'.
  • Banner: pre-release-banner.tsxmaintenance-banner.tsx. v4 pages carry an amber notice (with dark-mode styling) whose "Go to Workflow 5 (Latest)" link deep-links to the same page on the current version; v4-only pages land on the nearest section index via the fallback redirects. v4 pages keep robots: noindex, follow.
  • Redirects (docs/next.config.ts): /v5/* → unprefixed equivalent (permanent; bare /v5 gets its own rule because :path* expands to an empty Location otherwise). The world-docs and api-reference restructure rules are mirrored onto /v4/docs/*, and every page that exists in only one tree has a version-switcher fallback (verified by diffing the two content trees).
  • Worlds routes: both the unprefixed and /v4 worlds routes pass an explicit version into the shared page components, whose semantics flipped with the switch — smoke checks (assertWorldVersionMarkers, assertServesDirectly('/worlds/turso')) now guard the pairing so the canonical /worlds/* pages can't silently serve the maintenance version or self-redirect-loop again.
  • Link lint (docs/scripts/lint.ts): the two-space model swaps with the URL space; redirect destinations resolve against the real HTTP space since redirects are matched before render-time href rewriting.
  • Intentional oddity: rewriteHrefForVersion pulls unprefixed hrefs on v4 pages into the /v4 view, so a /v5/... href is the only way for v4 content to point at a current page. Three such links are kept deliberately; the lint models this.

What moves with the flip

  • whats-new enters the v5 sidebar, first in the tree. [docs] v5 GA content: What's new, World upgrade guide, migration skills #3100 adds the page but leaves it out of content/docs/v5/meta.json, so until this lands it is reachable only by URL.
  • upgrading-to-v5 moves from app/[lang]/v5/worlds/ to app/[lang]/worlds/, following the rest of the v5 worlds routes.
  • Two cross-version links become expressible and are restored. While v4 is the unprefixed version, a v5 page cannot link to a v4 page at all: an unprefixed href on a v5 page is rewritten into the /v5 view. [docs] v5 GA content: What's new, World upgrade guide, migration skills #3100 therefore phrases both as pointers to the version picker. Here they go back to being links — the v4 docs entry point in the What's new callout, and the v4 version of the code-transform page.
  • editPath on the unprefixed docs route points at docs/content/docs/v5/{path}.

Catch-up with main

Swept the 53 commits that landed since the last content refresh, and added what the docs were missing. Most changesets in that window are fixes, internal, or already documented by their own PR; three things were not.

Spec 7, the sealed log (#3634, not merged, default for v5). Positions are handed out ahead of the commit instead of being claimed by the write that fills them, so concurrent writers never contend and a wide fan-out stops serializing. The cost is a position whose writer dies, which the backend closes with a noop event that replay steps over without delivering it and without advancing the deterministic clock.

  • upgrading-to-v5 › Spec versions is rewritten around mintedSpecVersion(). The accepted range widens back to two versions, because a deployment with WORKFLOW_SEALED_LOG=0 stamps the one below, and that makes both SPEC_VERSION_CURRENT and SPEC_VERSION_SUPPORTS_SLOT_IDENTITY literals by another name for declaring it — neither follows the setting. This replaces what [docs] v5 GA content: What's new, World upgrade guide, migration skills #3100 said for spec 6, which was that exactly one version is accepted.
  • A new "Sealed logs and noop events" subsection says what this costs an implementer, which for most is nothing: a World allocating each position at the commit cannot leave a hole, so it never seals and never emits a noop. The obligation belongs to a World that pre-assigns positions; the half that binds everyone is the reader's.
  • WORKFLOW_SEALED_LOG is documented in runtime-tuning, taken verbatim from Add support for 'noop' event type - spec version 7 #3634 so whichever lands second is a no-op merge. The deep reference sections that PR writes — in event-sourcing and the World allocation contract — are left to it, so this does not duplicate them.
  • The migration skill (v0.2.0) gets the same treatment, phrased as findings to report rather than edits to make.

events.createBatch (#3025). An optional World method appending an ordered list of events in one durable write with per-event outcomes. It was documented only as a changelog page and an env var, so the World reference had no mention of a method a World author has to decide about. Added to the interface snippet, to the Key Implementation Details as a contract note (atomicity per attempt, what a World must reject, the one legal same-entity pair), to the upgrade guide's optional surface, and to the skill.

runs.waitForTerminalStatus (#3570). Also missing from the upgrade guide and the skill. It is what makes await run.returnValue a long poll rather than an interval, which is user-facing, so What's new gets that as an entry.

What's new also gains the batched suspension write and the positions change under faster-and-cheaper runs, where they belong: neither has any API surface.

Not addressed.workflow.step.execute.duration, the OpenTelemetry histogram from #3526, has nowhere to go — the docs carry no metrics reference at all, and inventing one for a single metric is a bigger call than this sweep. Flagging rather than guessing.

Second catch-up: the WebSocket default and spec 7

Merged main again (13 commits). Four conflicts, all against #3704's writing-standards pass over the whole corpus, which rewrote the same paragraphs this branch had edited. Took main's normalized text wherever the difference was purely style, kept this branch's meaning where the two disagreed (the spec-7 paragraph main still had at spec 6, the /v4/... link the flip makes expressible, the batch-write contract note), and restyled this branch's own additions so no prose em dashes come back with it.

The WebSocket events transport is the default now.#3702 flipped it and updated worlds.mdx, vercel.mdx and runtime-tuning.mdx, but What's new still said "an opt-in WebSocket transport ... HTTP remains the default", which was the most wrong sentence left in the v5 docs. It now says what happens, that only the exact value http opts out so a typo fails toward the socket, and that tracing is unchanged because the client span is synthesized around the frame.

Spec 7 is settled.#3634 landed, then #3735 made the sealed log opt-in, then #3737 re-enabled it. The end state matches what this branch already documented, and the WORKFLOW_SEALED_LOG section I had taken verbatim merged as the no-op it was meant to be, modulo #3704's restyling. mintedSpecVersion(), the two-version accepted range, and the "if you allocate at the commit you are already compliant" framing all still hold.

Three World-developer notes, all from #3728. These are the ones a custom World cannot discover from its type errors:

  • Process-wide state has to live on globalThis. A module's top-level const/let is one instance per module instance, and a bundler compiles one copy per layer. The runtime caches the World object process-wide while module state it closes over stays layer-local, so anything a World reaches at request time has to be process-wide too. New contract note in the upgrade guide, plus a step of its own in the World skill (v0.3.0) with an intake item, a globalSingleton() example including what the shape version is for, an output-shape section, and a failure-checklist line. Documented by its casualty: the WS transport registered its channel in the route layer's registry and the write path read the instrumentation layer's empty one, so every event fell back to HTTP for the life of the process, with nothing logged and no test failing.
  • One World per process. The entrypoint's queue handler is built from getWorld() instead of getWorldHandlers(), so a stateful World stops getting duplicate connection pools and queue workers. The build-integration row that still pointed custom hosts at getWorldHandlers() is corrected: that export is the build-time view, not how a request-time handler is assembled.
  • A World's transport is its own business, except for the tracing. How a World ships events is unconstrained. What is constrained is that a non-HTTP transport still owes the per-event client span an HTTP write would emit, or the per-event view of a run silently disappears. Points at the Vercel World's span shape as the worked example.

Nothing needed for the remaining commits in the window: globalSingleton's own changeset and the sideEffects: false declaration are internal, the wait-continuation re-arm and the atomic step_created commit are fixes to behavior already documented, and the decrypt-control and trace-name changes are dashboard-side.

Verification

Link lint passes with 0 errors. pnpm build compiles, with /en/docs/whats-new prerendered under the unprefixed route, /[lang]/v4/docs/[[...slug]] serving the maintenance tree, and ƒ /[lang]/worlds/upgrading-to-v5.

Docs Preview

Links will be added from the workflow-docs preview once it deploys.

🤖 Generated with Claude Code

@vercel

vercelBot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated (UTC)
example-nextjs-workflow-turbopackReadyReadyPreview, v0Aug 25, 2026 8:40pm
example-nextjs-workflow-webpackReadyReadyPreview, v0Aug 25, 2026 8:40pm
example-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-astro-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-express-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-fastify-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-hono-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-nestjs-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-nitro-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-nuxt-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-python-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-sveltekit-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-tanstack-start-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-vite-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workflow-docsReadyReadyPreview, v0Aug 25, 2026 8:40pm
workflow-swc-playgroundBuildingBuildingPreview, v0Aug 25, 2026 8:40pm
workflow-tarballsReadyReadyPreview, v0Aug 25, 2026 8:40pm
workflow-webReadyReadyPreview, v0Aug 25, 2026 8:40pm

@changeset-bot

changeset-botBot commented Aug 21, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 8d9081b

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 0 packages

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions

github-actionsBot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Sim World

Simulated world deterministic testing for races. Traces

🟠 world-sim scenario book — 1 fail of 41 total

fence=per-spec

scenariooutcomeeventsvirtreplayviolations
smoke-no-stepscompleted30msok0
smoke-one-stepcompleted60msok0
hook-at-step-startedcompleted120msok0
hook-at-step-completedcompleted120msok0
hook-at-hook-createdcompleted120msok0
deadline-hook-winscompleted71.0hok0
deadline-expirescompleted71.0hok0
long-sleepcompleted1130.0dok0
hook-never-arrivesstalled30msskipped0
step-retries-twicecompleted102.0sok0
parallel-stepscompleted90msok0
hook-on-execution-statecompleted120msok0
peek-hook-before-branchcompleted120msok0
peek-hook-after-branchcompleted120msok0
peek-hook-at-registrationcompleted120msok0
race-hook-before-probecompleted120msok0
race-hook-after-probecompleted120msok0
race-duplicate-deliverycompleted130msok0
attr-hook-before-stepcompleted110msok0
attr-hook-after-stepcompleted110msok0
attr-from-step-bodycompleted130msok0
fork-hook-after-timeoutcompleted141.0mok0
fork-hook-before-timeoutcompleted141.0mok0
count-hook-after-timeoutcompleted171.0mok0
count-hook-before-timeoutcompleted201.0mok0
stale-read-step-count-forkcompleted201.0mok0
stale-read-equal-step-countscompleted141.0mok0
step-vs-step-forkcompleted120msok0
step-vs-step-fork-fencedcompleted120msok0
fence-catches-benign-directioncompleted125msok0
in-flight-before-decisioncompleted171.0mok0
in-flight-before-decision-countedcompleted171.0mok0
in-flight-after-decisioncompleted192.0mok0
stale-read-step-count-fork-fencedcompleted201.0mok0
fork-hook-winscompleted131.0mok0
fork-timeout-winscompleted131.0mok0
unclaimed-payload-under-forkcompleted171.0mok0
claimed-payload-under-forkcompleted171.0mok0
writers-independent-step-bodiescompleted120msok0
writers-scripted-tempocompleted120msok0
cancel-mid-stepcancelled70msskipped0

Full trace: world-sim.txt

VaguelySeriousand others added 2 commits August 21, 2026 12:50
Serves `content/docs/v5` and `content/worlds/v5` unprefixed at /docs,
/worlds and /cookbook, moves v4 under /v4, and puts What's new first in
the v5 sidebar.
The versioned source config drives both route trees (the root tree always
renders `versionedSources.current`), so this is a `routePrefix` move plus
source re-binding rather than a restructure. The only file moves are
`app/[lang]/v5/**` → `app/[lang]/v4/**`.
- Version switcher: `v5 (Latest)` / `v4 (Maintenance)`, `current: 'v5'`.
- `pre-release-banner.tsx` becomes `maintenance-banner.tsx`. v4 pages
carry an amber notice whose "Go to Workflow 5 (Latest)" link deep-links
to the same page on the current version, falling back to the nearest
section index for v4-only pages, and keep `robots: noindex, follow`.
- Redirects: `/v5/*` to the unprefixed equivalent (bare `/v5` needs its
own rule, since `:path*` expands to an empty Location). The world-docs
and api-reference restructure rules are mirrored onto `/v4/docs/*`, and
every page existing in only one tree gets a version-switcher fallback.
- Both worlds route trees pass an explicit version into the shared page
components, whose semantics flipped with the switch, so the smoke checks
now assert the pairing: a " · v4" title marker and noindex on the
maintenance routes, neither on the canonical ones, and a community world
serving directly rather than self-redirecting.
- The link lint's two URL spaces swap with the prefixes. Redirect
destinations resolve against the real HTTP space, since redirects are
matched before render-time href rewriting.
- The two `/v4/...` links this makes expressible are restored: a v5 page
cannot link to a v4 page while v4 is the unprefixed version.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sweep of everything that landed on main since the last content refresh,
plus the spec-7 sealed log from #3634, which is not merged but is the
default for v5.
Spec 7 changes what a World declares, so the upgrade guide's Spec
versions section is rewritten around `mintedSpecVersion()`. The accepted
range widens back to two versions, because a deployment with
`WORKFLOW_SEALED_LOG=0` stamps the one below, and both `SPEC_VERSION_CURRENT`
and `SPEC_VERSION_SUPPORTS_SLOT_IDENTITY` become literals by another name
for the purpose of declaring it: neither follows the setting. The new
section says what a sealed log costs an implementer, which for most is
nothing — a World allocating each position at the commit cannot leave a
hole, so it never seals and never writes a `noop`. The obligation belongs
to a World that pre-assigns positions, and the half that binds everyone
is the reader's.
`WORKFLOW_SEALED_LOG` is documented in runtime-tuning, taken verbatim
from #3634 so whichever lands second is a no-op merge. The deep
reference sections that PR writes, in event-sourcing and the World
allocation contract, are left to it.
Two optional World members shipped after the guide was written and were
missing everywhere:
- `events.createBatch` — in the World reference (interface and contract
note), the upgrade guide's optional surface, and the skill. Implementing
it is the declaration, so the note leads with atomicity per attempt and
what a World must reject.
- `runs.waitForTerminalStatus` — same three places. It is also what makes
`await run.returnValue` a long poll rather than an interval, which is
user-facing, so What's new gets it too.
What's new also gains the batched suspension write and the pre-assigned
positions behind it, both under faster-and-cheaper runs where they belong:
neither has any API surface.
Not addressed: `workflow.step.execute.duration`, the OpenTelemetry
histogram added in #3526, has nowhere to go. The docs have no metrics
reference at all, and inventing one for a single metric is a bigger call
than this sweep.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@github-actions

github-actionsBot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

🧪 E2E Test Results

Some tests failed

❌ Failed E2E Tests

▲ Vercel Production (8 failed)

python-node (8 failed):

  • promiseAllWorkflow | wrun_41M0XAGXS00GK4H9P4BRDADZPF | 🔍 observability
  • sleepingWorkflow | wrun_41M0XAHK4C0GN8PMSN1G5MJ54R | 🔍 observability
  • parallelSleepWorkflow | wrun_41M0XAHKR70GX6C8R38YRX9JZR | 🔍 observability
  • nullByteWorkflow | wrun_41M0XAHTBJ0GPJDS4V1JB075V8 | 🔍 observability
  • cancelRun - cancelling a running workflow | wrun_41M0XAPE6F0GWZ7WFMJS2WQSZ7 | 🔍 observability
  • cancelRun via CLI - cancelling a running workflow | wrun_41M0XAPJ5Y0GVZ8EPNJZZFBXBN | 🔍 observability
  • sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration | wrun_41M0XAPTHD0GRRQPJZEA3CS0X9 | 🔍 observability
  • resilient start: addTenWorkflow completes when run_created returns 500 | wrun_41M0XAQ8AD0GG3DEEMY8R682VV | 🔍 observability

🌐 Cross-language Conformance (9 failed)

python (9 failed):

  • deploymentId: 'latest' is a no-op in non-Vercel worlds | wrun_01M0XASD1GCVQ8X0DC4TD9QQ8K
  • promiseAllWorkflow | wrun_41M0XAGXS00GK4H9P4BRDADZPF
  • sleepingWorkflow | wrun_41M0XAHK4C0GN8PMSN1G5MJ54R
  • parallelSleepWorkflow | wrun_41M0XAHKR70GX6C8R38YRX9JZR
  • nullByteWorkflow | wrun_41M0XAHTBJ0GPJDS4V1JB075V8
  • cancelRun - cancelling a running workflow | wrun_41M0XAPE6F0GWZ7WFMJS2WQSZ7
  • cancelRun via CLI - cancelling a running workflow | wrun_41M0XAPJ5Y0GVZ8EPNJZZFBXBN
  • sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration | wrun_41M0XAPTHD0GRRQPJZEA3CS0X9
  • resilient start: addTenWorkflow completes when run_created returns 500 | wrun_41M0XAQ8AD0GG3DEEMY8R682VV

⚠️ Flaky E2E Tests (passed on retry)

These tests failed at least once and passed on a retry. A recurring entry here is a real race worth investigating.

  • addTenWorkflow (express)
  • cancelRun via CLI - cancelling a running workflow (nextjs-turbopack)
  • hookWithSleepWorkflow - hook payloads delivered correctly with concurrent sleep (nextjs-webpack)
  • promiseAllWorkflow (nuxt)
  • RetryableError respects custom retryAfter delay (nitro)

🛠 Infra Events (absorbed by the harness)

Platform anomalies the e2e harness detected and worked around (e.g. a run the queue never picked up, replaced by a fresh run). Clustered timestamps indicate a backend blip; a steady drip indicates a platform issue worth escalating.

35 infra events
  • cold-start-warmup · suite warmup (python) · at 20:42:37Z · abandoned wrun_41M0XAEJYH0GKQ4W94H3ETH1ZY · (+7 more)
  • run-pickup-stall · nullByteWorkflow (python) · at 20:42:53Z · abandoned wrun_41M0XAJ7Y50GK8N5JNCV12GV8E
  • run-pickup-stall · parallelSleepWorkflow (python) · at 20:42:53Z · abandoned wrun_41M0XAJ7Y20GSX8SWCTH5RVR9M
  • run-pickup-stall · promiseAllWorkflow (python) · at 20:42:53Z · abandoned wrun_41M0XAJ7XV0GG32EEKFRD3B8FS
  • run-pickup-stall · sleepingWorkflow (python) · at 20:42:54Z · abandoned wrun_41M0XAJ7Y20GSX8SWCTH5RVR9K
  • run-pickup-stall · cancelRun - cancelling a running workflow (python) · at 20:42:54Z · abandoned wrun_41M0XAJ8BJ0GJZX1BNBA4CH8W8
  • run-pickup-stall · cancelRun - cancelling a running workflow (python) · at 20:43:27Z · abandoned wrun_41M0XAK8KD0GGARJ5E9EAKDQA7
  • run-pickup-stall · parallelSleepWorkflow (python) · at 20:43:54Z · abandoned wrun_41M0XAM3J00GNDEKT3M4EV9A3B
  • run-pickup-stall · nullByteWorkflow (python) · at 20:43:54Z · abandoned wrun_41M0XAM3J50GY1Z4PYVB875JW2
  • run-pickup-stall · sleepingWorkflow (python) · at 20:43:55Z · abandoned wrun_41M0XAM3NR0GMY2WC43XC9WEEG
  • run-pickup-stall · promiseAllWorkflow (python) · at 20:43:55Z · abandoned wrun_41M0XAM3PT0GKQPBP2CXFAYS50
  • cold-start-warmup · suite warmup (tanstack-start) · at 20:44:26Z · abandoned wrun_01M0XAMQCG384J98J2DSD14DR1
  • run-pickup-stall · cancelRun via CLI - cancelling a running workflow (python) · at 20:44:45Z · abandoned wrun_41M0XAM8FN0GV4BFNTQPWFKM5X
  • cold-start-warmup · suite warmup (python) · at 20:45:16Z · abandoned wrun_01M0XAKEM09ZDGG4DKY24BNT4R · (+7 more)
  • run-pickup-stall · deploymentId: 'latest' is a no-op in non-Vercel worlds (python) · at 20:45:31Z · abandoned wrun_01M0XAQ3RETMHB830AKZR4WRR3
  • run-pickup-stall · promiseAllWorkflow (python) · at 20:45:31Z · abandoned wrun_01M0XAQ3RF7PEAZN9P8KWR413P
  • run-pickup-stall · parallelSleepWorkflow (python) · at 20:45:31Z · abandoned wrun_01M0XAQ3RP7BN47JKYJVR7W9SN
  • run-pickup-stall · sleepingWorkflow (python) · at 20:45:31Z · abandoned wrun_01M0XAQ3RNB63W8SCJMFB059TD
  • run-pickup-stall · nullByteWorkflow (python) · at 20:45:31Z · abandoned wrun_01M0XAQ3RRZXSHD6R9Y4Q7HMN3
  • run-pickup-stall · cancelRun via CLI - cancelling a running workflow (python) · at 20:46:27Z · abandoned wrun_41M0XAQ0C60GXEJ7JBYYKRXP7W
  • run-pickup-stall · sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration (python) · at 20:46:28Z · abandoned wrun_41M0XAPVEJ0GJSWRFAK9D97ABV
  • run-pickup-stall · deploymentId: 'latest' is a no-op in non-Vercel worlds (python) · at 20:46:31Z · abandoned wrun_01M0XARYC38T4GCYXDEWNVNMX3
  • run-pickup-stall · promiseAllWorkflow (python) · at 20:46:31Z · abandoned wrun_01M0XARYC52C67FSA4N73VC5D7
  • run-pickup-stall · sleepingWorkflow (python) · at 20:46:31Z · abandoned wrun_01M0XARYCDFV9BC8DR74AKYXE5
  • run-pickup-stall · parallelSleepWorkflow (python) · at 20:46:32Z · abandoned wrun_01M0XARYCK0DC47WQPD9BH1JVJ
  • run-pickup-stall · nullByteWorkflow (python) · at 20:46:32Z · abandoned wrun_01M0XARYCM1HBYVNK0S93X5J0W
  • run-pickup-stall · cancelRun - cancelling a running workflow (python) · at 20:47:32Z · abandoned wrun_01M0XATRZQVJRSD3M331XYF0RA
  • run-pickup-stall · cancelRun via CLI - cancelling a running workflow (python) · at 20:47:32Z · abandoned wrun_01M0XATRZZS9C3MF3DY87TKVW5
  • run-pickup-stall · sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration (python) · at 20:47:32Z · abandoned wrun_01M0XATS031XZTYSFHCRKFRY0Z
  • run-pickup-stall · cancelRun - cancelling a running workflow (python) · at 20:48:02Z · abandoned wrun_01M0XAVPAX8XNNRK46QNQJ2XK9
  • run-pickup-stall · cancelRun via CLI - cancelling a running workflow (python) · at 20:48:02Z · abandoned wrun_01M0XAVPBFHXMMMA4YG99N83D1
  • run-pickup-stall · sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration (python) · at 20:48:32Z · abandoned wrun_01M0XAWKK6KJ97YQH5T3M65MQN
  • run-pickup-stall · plainModuleDoneHook resumed via plain API route (o2flow shape) (nextjs-webpack) · at 20:51:44Z · abandoned wrun_01M0XB2FMN0D9JTJB906JH00C2
  • run-pickup-stall · hookWithSleepFinalStepWorkflow - step only on final payload (nextjs-webpack) · at 20:52:05Z · abandoned wrun_01M0XB34HFYH9Y559Y5VFH0QKY
  • run-pickup-stall · sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration (nextjs-webpack) · at 20:52:06Z · abandoned wrun_01M0XB34PXRGGCJBBBPNXBSAQW

E2E Test Summary

Summary
PassedFailedSkippedTotal
❌ ▲ Vercel Production357087424320
✅ 💻 Local Development392205584480
✅ 📦 Local Production392205584480
✅ 🐘 Local Postgres392205584480
✅ 🪟 Windows32000320
❌ 🌐 Cross-language Conformance09132141
✅ vercel-http-transport8170143960
✅ vercel-multi-region270027
✅ vercel-ws-transport553087640
Total1705317277819848
Details by Category

❌ ▲ Vercel Production

AppPassedFailedSkipped
✅ astro-node132028
✅ astro-quickjs132028
✅ example-node132028
✅ example-quickjs132028
✅ express-node132028
✅ express-quickjs132028
✅ fastify-node132028
✅ fastify-quickjs132028
✅ hono-node132028
✅ hono-quickjs132028
✅ nest-node132028
✅ nest-quickjs132028
✅ nextjs-turbopack-node15703
✅ nextjs-turbopack-quickjs15703
✅ nextjs-webpack-node15703
✅ nextjs-webpack-quickjs15703
✅ nitro-node132028
✅ nitro-quickjs132028
✅ nuxt-node132028
✅ nuxt-quickjs132028
❌ python-node08152
✅ sveltekit-node15109
✅ sveltekit-quickjs15109
✅ tanstack-start-node132028
✅ tanstack-start-quickjs132028
✅ vite-node132028
✅ vite-quickjs132028

✅ 💻 Local Development

AppPassedFailedSkipped
✅ astro-stable-node134026
✅ astro-stable-quickjs134026
✅ express-stable-node134026
✅ express-stable-quickjs134026
✅ fastify-stable-node134026
✅ fastify-stable-quickjs134026
✅ hono-stable-node134026
✅ hono-stable-quickjs134026
✅ nest-stable-node134026
✅ nest-stable-quickjs134026
✅ nextjs-turbopack-canary-node141019
✅ nextjs-turbopack-canary-quickjs141019
✅ nextjs-turbopack-stable-node16000
✅ nextjs-turbopack-stable-quickjs16000
✅ nextjs-webpack-canary-node141019
✅ nextjs-webpack-canary-quickjs141019
✅ nextjs-webpack-stable-node16000
✅ nextjs-webpack-stable-quickjs16000
✅ nitro-stable-node134026
✅ nitro-stable-quickjs134026
✅ nuxt-stable-node134026
✅ nuxt-stable-quickjs134026
✅ sveltekit-stable-node15307
✅ sveltekit-stable-quickjs15307
✅ tanstack-start-node134026
✅ tanstack-start-quickjs134026
✅ vite-stable-node134026
✅ vite-stable-quickjs134026

✅ 📦 Local Production

AppPassedFailedSkipped
✅ astro-stable-node134026
✅ astro-stable-quickjs134026
✅ express-stable-node134026
✅ express-stable-quickjs134026
✅ fastify-stable-node134026
✅ fastify-stable-quickjs134026
✅ hono-stable-node134026
✅ hono-stable-quickjs134026
✅ nest-stable-node134026
✅ nest-stable-quickjs134026
✅ nextjs-turbopack-canary-node141019
✅ nextjs-turbopack-canary-quickjs141019
✅ nextjs-turbopack-stable-node16000
✅ nextjs-turbopack-stable-quickjs16000
✅ nextjs-webpack-canary-node141019
✅ nextjs-webpack-canary-quickjs141019
✅ nextjs-webpack-stable-node16000
✅ nextjs-webpack-stable-quickjs16000
✅ nitro-stable-node134026
✅ nitro-stable-quickjs134026
✅ nuxt-stable-node134026
✅ nuxt-stable-quickjs134026
✅ sveltekit-stable-node15307
✅ sveltekit-stable-quickjs15307
✅ tanstack-start-node134026
✅ tanstack-start-quickjs134026
✅ vite-stable-node134026
✅ vite-stable-quickjs134026

✅ 🐘 Local Postgres

AppPassedFailedSkipped
✅ astro-stable-node134026
✅ astro-stable-quickjs134026
✅ express-stable-node134026
✅ express-stable-quickjs134026
✅ fastify-stable-node134026
✅ fastify-stable-quickjs134026
✅ hono-stable-node134026
✅ hono-stable-quickjs134026
✅ nest-stable-node134026
✅ nest-stable-quickjs134026
✅ nextjs-turbopack-canary-node141019
✅ nextjs-turbopack-canary-quickjs141019
✅ nextjs-turbopack-stable-node16000
✅ nextjs-turbopack-stable-quickjs16000
✅ nextjs-webpack-canary-node141019
✅ nextjs-webpack-canary-quickjs141019
✅ nextjs-webpack-stable-node16000
✅ nextjs-webpack-stable-quickjs16000
✅ nitro-stable-node134026
✅ nitro-stable-quickjs134026
✅ nuxt-stable-node134026
✅ nuxt-stable-quickjs134026
✅ sveltekit-stable-node15307
✅ sveltekit-stable-quickjs15307
✅ tanstack-start-node134026
✅ tanstack-start-quickjs134026
✅ vite-stable-node134026
✅ vite-stable-quickjs134026

✅ 🪟 Windows

AppPassedFailedSkipped
✅ nextjs-turbopack-node16000
✅ nextjs-turbopack-quickjs16000

❌ 🌐 Cross-language Conformance

AppPassedFailedSkipped
❌ python09132

✅ vercel-http-transport

AppPassedFailedSkipped
✅ example132028
✅ express132028
✅ hono132028
✅ nextjs-turbopack15703
✅ nitro132028
✅ vite132028

✅ vercel-multi-region

AppPassedFailedSkipped
✅ nextjs-turbopack2700

✅ vercel-ws-transport

AppPassedFailedSkipped
✅ example132028
✅ express132028
✅ nextjs-turbopack15703
✅ vite132028

📋 View full workflow run

#3779 fixed the app migration skill, whose description ended with
`mode: 'client'`. The colon-space made the plain scalar parse as a nested
mapping, and the skills CLI dropped the file: `Found 5 skills`, and
`--skill migrating-workflow-v4-to-v5` answered `No matching skills
found`, which is the command whats-new.mdx tells readers to run.
The World skill's description has no colon-space today, so it parses.
It is also 590 characters of backticked identifiers, and any future
edit naming a field with its value reintroduces the break. Fold it the
same way now, while the value is known good. Verified with the yaml
package that the folded scalar is byte-identical, and with
`skills add . --skill migrating-world-v4-to-v5` that the CLI still
finds all six.
Signed-off-by: Peter Wielander <peter.wielander@vercel.com>
@github-actions

Copy link
Copy Markdown
Contributor
FrameworkFlow routeStep reg.Framework output
hono200.9 KiB (±0)40.5 KiB (±0)1.76 MiB (±0)
nextjs-turbopack206.3 KiB (±0)439 B (±0)762.8 KiB (±0)
About these numbers

Sizes are gzip; parentheses show the change against main.
Flow route and Step reg. gate this job, on raw bytes rather than the gzip shown, at max(2%, 50.0 KiB). Framework output is informational.

8d9081b · run

Sign up for freeto 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.

1 participant

@VaguelySerious
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' [docs] Make v5 the default documentation version by VaguelySerious · Pull Request #3714 · vercel/workflow · GitHub
Skip to content

[docs] Make v5 the default documentation version - #3714

Open
VaguelySerious wants to merge 5 commits into
mainfrom
peter/docs-v5-default
Open

[docs] Make v5 the default documentation version#3714
VaguelySerious wants to merge 5 commits into
mainfrom
peter/docs-v5-default

Conversation

@VaguelySerious

@VaguelySeriousVaguelySerious commented Aug 21, 2026

Copy link
Copy Markdown
Member

Makes v5 the default documentation version for the 5.0.0 GA, and catches the v5 content up with everything that landed on main since the v5 docs were last refreshed. Companion to #3090 (exit changeset pre mode) and #3091 (pin 4.x publishes to previous).

Version flip and routing

content/docs/v5 and content/worlds/v5 now serve unprefixed — /docs, /worlds, /cookbook — and v4 moves under a /v4 prefix. The versioned source config drives both route trees (the root tree always renders versionedSources.current), so this is a routePrefix move plus source re-binding, not a restructure. The only file moves are app/[lang]/v5/**app/[lang]/v4/**.

  • Version switcher: labels are v5 (Latest) / v4 (Maintenance); current: 'v5'.
  • Banner: pre-release-banner.tsxmaintenance-banner.tsx. v4 pages carry an amber notice (with dark-mode styling) whose "Go to Workflow 5 (Latest)" link deep-links to the same page on the current version; v4-only pages land on the nearest section index via the fallback redirects. v4 pages keep robots: noindex, follow.
  • Redirects (docs/next.config.ts): /v5/* → unprefixed equivalent (permanent; bare /v5 gets its own rule because :path* expands to an empty Location otherwise). The world-docs and api-reference restructure rules are mirrored onto /v4/docs/*, and every page that exists in only one tree has a version-switcher fallback (verified by diffing the two content trees).
  • Worlds routes: both the unprefixed and /v4 worlds routes pass an explicit version into the shared page components, whose semantics flipped with the switch — smoke checks (assertWorldVersionMarkers, assertServesDirectly('/worlds/turso')) now guard the pairing so the canonical /worlds/* pages can't silently serve the maintenance version or self-redirect-loop again.
  • Link lint (docs/scripts/lint.ts): the two-space model swaps with the URL space; redirect destinations resolve against the real HTTP space since redirects are matched before render-time href rewriting.
  • Intentional oddity: rewriteHrefForVersion pulls unprefixed hrefs on v4 pages into the /v4 view, so a /v5/... href is the only way for v4 content to point at a current page. Three such links are kept deliberately; the lint models this.

What moves with the flip

  • whats-new enters the v5 sidebar, first in the tree. [docs] v5 GA content: What's new, World upgrade guide, migration skills #3100 adds the page but leaves it out of content/docs/v5/meta.json, so until this lands it is reachable only by URL.
  • upgrading-to-v5 moves from app/[lang]/v5/worlds/ to app/[lang]/worlds/, following the rest of the v5 worlds routes.
  • Two cross-version links become expressible and are restored. While v4 is the unprefixed version, a v5 page cannot link to a v4 page at all: an unprefixed href on a v5 page is rewritten into the /v5 view. [docs] v5 GA content: What's new, World upgrade guide, migration skills #3100 therefore phrases both as pointers to the version picker. Here they go back to being links — the v4 docs entry point in the What's new callout, and the v4 version of the code-transform page.
  • editPath on the unprefixed docs route points at docs/content/docs/v5/{path}.

Catch-up with main

Swept the 53 commits that landed since the last content refresh, and added what the docs were missing. Most changesets in that window are fixes, internal, or already documented by their own PR; three things were not.

Spec 7, the sealed log (#3634, not merged, default for v5). Positions are handed out ahead of the commit instead of being claimed by the write that fills them, so concurrent writers never contend and a wide fan-out stops serializing. The cost is a position whose writer dies, which the backend closes with a noop event that replay steps over without delivering it and without advancing the deterministic clock.

  • upgrading-to-v5 › Spec versions is rewritten around mintedSpecVersion(). The accepted range widens back to two versions, because a deployment with WORKFLOW_SEALED_LOG=0 stamps the one below, and that makes both SPEC_VERSION_CURRENT and SPEC_VERSION_SUPPORTS_SLOT_IDENTITY literals by another name for declaring it — neither follows the setting. This replaces what [docs] v5 GA content: What's new, World upgrade guide, migration skills #3100 said for spec 6, which was that exactly one version is accepted.
  • A new "Sealed logs and noop events" subsection says what this costs an implementer, which for most is nothing: a World allocating each position at the commit cannot leave a hole, so it never seals and never emits a noop. The obligation belongs to a World that pre-assigns positions; the half that binds everyone is the reader's.
  • WORKFLOW_SEALED_LOG is documented in runtime-tuning, taken verbatim from Add support for 'noop' event type - spec version 7 #3634 so whichever lands second is a no-op merge. The deep reference sections that PR writes — in event-sourcing and the World allocation contract — are left to it, so this does not duplicate them.
  • The migration skill (v0.2.0) gets the same treatment, phrased as findings to report rather than edits to make.

events.createBatch (#3025). An optional World method appending an ordered list of events in one durable write with per-event outcomes. It was documented only as a changelog page and an env var, so the World reference had no mention of a method a World author has to decide about. Added to the interface snippet, to the Key Implementation Details as a contract note (atomicity per attempt, what a World must reject, the one legal same-entity pair), to the upgrade guide's optional surface, and to the skill.

runs.waitForTerminalStatus (#3570). Also missing from the upgrade guide and the skill. It is what makes await run.returnValue a long poll rather than an interval, which is user-facing, so What's new gets that as an entry.

What's new also gains the batched suspension write and the positions change under faster-and-cheaper runs, where they belong: neither has any API surface.

Not addressed.workflow.step.execute.duration, the OpenTelemetry histogram from #3526, has nowhere to go — the docs carry no metrics reference at all, and inventing one for a single metric is a bigger call than this sweep. Flagging rather than guessing.

Second catch-up: the WebSocket default and spec 7

Merged main again (13 commits). Four conflicts, all against #3704's writing-standards pass over the whole corpus, which rewrote the same paragraphs this branch had edited. Took main's normalized text wherever the difference was purely style, kept this branch's meaning where the two disagreed (the spec-7 paragraph main still had at spec 6, the /v4/... link the flip makes expressible, the batch-write contract note), and restyled this branch's own additions so no prose em dashes come back with it.

The WebSocket events transport is the default now.#3702 flipped it and updated worlds.mdx, vercel.mdx and runtime-tuning.mdx, but What's new still said "an opt-in WebSocket transport ... HTTP remains the default", which was the most wrong sentence left in the v5 docs. It now says what happens, that only the exact value http opts out so a typo fails toward the socket, and that tracing is unchanged because the client span is synthesized around the frame.

Spec 7 is settled.#3634 landed, then #3735 made the sealed log opt-in, then #3737 re-enabled it. The end state matches what this branch already documented, and the WORKFLOW_SEALED_LOG section I had taken verbatim merged as the no-op it was meant to be, modulo #3704's restyling. mintedSpecVersion(), the two-version accepted range, and the "if you allocate at the commit you are already compliant" framing all still hold.

Three World-developer notes, all from #3728. These are the ones a custom World cannot discover from its type errors:

  • Process-wide state has to live on globalThis. A module's top-level const/let is one instance per module instance, and a bundler compiles one copy per layer. The runtime caches the World object process-wide while module state it closes over stays layer-local, so anything a World reaches at request time has to be process-wide too. New contract note in the upgrade guide, plus a step of its own in the World skill (v0.3.0) with an intake item, a globalSingleton() example including what the shape version is for, an output-shape section, and a failure-checklist line. Documented by its casualty: the WS transport registered its channel in the route layer's registry and the write path read the instrumentation layer's empty one, so every event fell back to HTTP for the life of the process, with nothing logged and no test failing.
  • One World per process. The entrypoint's queue handler is built from getWorld() instead of getWorldHandlers(), so a stateful World stops getting duplicate connection pools and queue workers. The build-integration row that still pointed custom hosts at getWorldHandlers() is corrected: that export is the build-time view, not how a request-time handler is assembled.
  • A World's transport is its own business, except for the tracing. How a World ships events is unconstrained. What is constrained is that a non-HTTP transport still owes the per-event client span an HTTP write would emit, or the per-event view of a run silently disappears. Points at the Vercel World's span shape as the worked example.

Nothing needed for the remaining commits in the window: globalSingleton's own changeset and the sideEffects: false declaration are internal, the wait-continuation re-arm and the atomic step_created commit are fixes to behavior already documented, and the decrypt-control and trace-name changes are dashboard-side.

Verification

Link lint passes with 0 errors. pnpm build compiles, with /en/docs/whats-new prerendered under the unprefixed route, /[lang]/v4/docs/[[...slug]] serving the maintenance tree, and ƒ /[lang]/worlds/upgrading-to-v5.

Docs Preview

Links will be added from the workflow-docs preview once it deploys.

🤖 Generated with Claude Code

@vercel

vercelBot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated (UTC)
example-nextjs-workflow-turbopackReadyReadyPreview, v0Aug 25, 2026 8:40pm
example-nextjs-workflow-webpackReadyReadyPreview, v0Aug 25, 2026 8:40pm
example-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-astro-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-express-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-fastify-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-hono-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-nestjs-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-nitro-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-nuxt-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-python-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-sveltekit-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-tanstack-start-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-vite-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workflow-docsReadyReadyPreview, v0Aug 25, 2026 8:40pm
workflow-swc-playgroundBuildingBuildingPreview, v0Aug 25, 2026 8:40pm
workflow-tarballsReadyReadyPreview, v0Aug 25, 2026 8:40pm
workflow-webReadyReadyPreview, v0Aug 25, 2026 8:40pm

@changeset-bot

changeset-botBot commented Aug 21, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 8d9081b

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 0 packages

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions

github-actionsBot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Sim World

Simulated world deterministic testing for races. Traces

🟠 world-sim scenario book — 1 fail of 41 total

fence=per-spec

scenariooutcomeeventsvirtreplayviolations
smoke-no-stepscompleted30msok0
smoke-one-stepcompleted60msok0
hook-at-step-startedcompleted120msok0
hook-at-step-completedcompleted120msok0
hook-at-hook-createdcompleted120msok0
deadline-hook-winscompleted71.0hok0
deadline-expirescompleted71.0hok0
long-sleepcompleted1130.0dok0
hook-never-arrivesstalled30msskipped0
step-retries-twicecompleted102.0sok0
parallel-stepscompleted90msok0
hook-on-execution-statecompleted120msok0
peek-hook-before-branchcompleted120msok0
peek-hook-after-branchcompleted120msok0
peek-hook-at-registrationcompleted120msok0
race-hook-before-probecompleted120msok0
race-hook-after-probecompleted120msok0
race-duplicate-deliverycompleted130msok0
attr-hook-before-stepcompleted110msok0
attr-hook-after-stepcompleted110msok0
attr-from-step-bodycompleted130msok0
fork-hook-after-timeoutcompleted141.0mok0
fork-hook-before-timeoutcompleted141.0mok0
count-hook-after-timeoutcompleted171.0mok0
count-hook-before-timeoutcompleted201.0mok0
stale-read-step-count-forkcompleted201.0mok0
stale-read-equal-step-countscompleted141.0mok0
step-vs-step-forkcompleted120msok0
step-vs-step-fork-fencedcompleted120msok0
fence-catches-benign-directioncompleted125msok0
in-flight-before-decisioncompleted171.0mok0
in-flight-before-decision-countedcompleted171.0mok0
in-flight-after-decisioncompleted192.0mok0
stale-read-step-count-fork-fencedcompleted201.0mok0
fork-hook-winscompleted131.0mok0
fork-timeout-winscompleted131.0mok0
unclaimed-payload-under-forkcompleted171.0mok0
claimed-payload-under-forkcompleted171.0mok0
writers-independent-step-bodiescompleted120msok0
writers-scripted-tempocompleted120msok0
cancel-mid-stepcancelled70msskipped0

Full trace: world-sim.txt

VaguelySeriousand others added 2 commits August 21, 2026 12:50
Serves `content/docs/v5` and `content/worlds/v5` unprefixed at /docs,
/worlds and /cookbook, moves v4 under /v4, and puts What's new first in
the v5 sidebar.
The versioned source config drives both route trees (the root tree always
renders `versionedSources.current`), so this is a `routePrefix` move plus
source re-binding rather than a restructure. The only file moves are
`app/[lang]/v5/**` → `app/[lang]/v4/**`.
- Version switcher: `v5 (Latest)` / `v4 (Maintenance)`, `current: 'v5'`.
- `pre-release-banner.tsx` becomes `maintenance-banner.tsx`. v4 pages
carry an amber notice whose "Go to Workflow 5 (Latest)" link deep-links
to the same page on the current version, falling back to the nearest
section index for v4-only pages, and keep `robots: noindex, follow`.
- Redirects: `/v5/*` to the unprefixed equivalent (bare `/v5` needs its
own rule, since `:path*` expands to an empty Location). The world-docs
and api-reference restructure rules are mirrored onto `/v4/docs/*`, and
every page existing in only one tree gets a version-switcher fallback.
- Both worlds route trees pass an explicit version into the shared page
components, whose semantics flipped with the switch, so the smoke checks
now assert the pairing: a " · v4" title marker and noindex on the
maintenance routes, neither on the canonical ones, and a community world
serving directly rather than self-redirecting.
- The link lint's two URL spaces swap with the prefixes. Redirect
destinations resolve against the real HTTP space, since redirects are
matched before render-time href rewriting.
- The two `/v4/...` links this makes expressible are restored: a v5 page
cannot link to a v4 page while v4 is the unprefixed version.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sweep of everything that landed on main since the last content refresh,
plus the spec-7 sealed log from #3634, which is not merged but is the
default for v5.
Spec 7 changes what a World declares, so the upgrade guide's Spec
versions section is rewritten around `mintedSpecVersion()`. The accepted
range widens back to two versions, because a deployment with
`WORKFLOW_SEALED_LOG=0` stamps the one below, and both `SPEC_VERSION_CURRENT`
and `SPEC_VERSION_SUPPORTS_SLOT_IDENTITY` become literals by another name
for the purpose of declaring it: neither follows the setting. The new
section says what a sealed log costs an implementer, which for most is
nothing — a World allocating each position at the commit cannot leave a
hole, so it never seals and never writes a `noop`. The obligation belongs
to a World that pre-assigns positions, and the half that binds everyone
is the reader's.
`WORKFLOW_SEALED_LOG` is documented in runtime-tuning, taken verbatim
from #3634 so whichever lands second is a no-op merge. The deep
reference sections that PR writes, in event-sourcing and the World
allocation contract, are left to it.
Two optional World members shipped after the guide was written and were
missing everywhere:
- `events.createBatch` — in the World reference (interface and contract
note), the upgrade guide's optional surface, and the skill. Implementing
it is the declaration, so the note leads with atomicity per attempt and
what a World must reject.
- `runs.waitForTerminalStatus` — same three places. It is also what makes
`await run.returnValue` a long poll rather than an interval, which is
user-facing, so What's new gets it too.
What's new also gains the batched suspension write and the pre-assigned
positions behind it, both under faster-and-cheaper runs where they belong:
neither has any API surface.
Not addressed: `workflow.step.execute.duration`, the OpenTelemetry
histogram added in #3526, has nowhere to go. The docs have no metrics
reference at all, and inventing one for a single metric is a bigger call
than this sweep.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@github-actions

github-actionsBot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

🧪 E2E Test Results

Some tests failed

❌ Failed E2E Tests

▲ Vercel Production (8 failed)

python-node (8 failed):

  • promiseAllWorkflow | wrun_41M0XAGXS00GK4H9P4BRDADZPF | 🔍 observability
  • sleepingWorkflow | wrun_41M0XAHK4C0GN8PMSN1G5MJ54R | 🔍 observability
  • parallelSleepWorkflow | wrun_41M0XAHKR70GX6C8R38YRX9JZR | 🔍 observability
  • nullByteWorkflow | wrun_41M0XAHTBJ0GPJDS4V1JB075V8 | 🔍 observability
  • cancelRun - cancelling a running workflow | wrun_41M0XAPE6F0GWZ7WFMJS2WQSZ7 | 🔍 observability
  • cancelRun via CLI - cancelling a running workflow | wrun_41M0XAPJ5Y0GVZ8EPNJZZFBXBN | 🔍 observability
  • sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration | wrun_41M0XAPTHD0GRRQPJZEA3CS0X9 | 🔍 observability
  • resilient start: addTenWorkflow completes when run_created returns 500 | wrun_41M0XAQ8AD0GG3DEEMY8R682VV | 🔍 observability

🌐 Cross-language Conformance (9 failed)

python (9 failed):

  • deploymentId: 'latest' is a no-op in non-Vercel worlds | wrun_01M0XASD1GCVQ8X0DC4TD9QQ8K
  • promiseAllWorkflow | wrun_41M0XAGXS00GK4H9P4BRDADZPF
  • sleepingWorkflow | wrun_41M0XAHK4C0GN8PMSN1G5MJ54R
  • parallelSleepWorkflow | wrun_41M0XAHKR70GX6C8R38YRX9JZR
  • nullByteWorkflow | wrun_41M0XAHTBJ0GPJDS4V1JB075V8
  • cancelRun - cancelling a running workflow | wrun_41M0XAPE6F0GWZ7WFMJS2WQSZ7
  • cancelRun via CLI - cancelling a running workflow | wrun_41M0XAPJ5Y0GVZ8EPNJZZFBXBN
  • sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration | wrun_41M0XAPTHD0GRRQPJZEA3CS0X9
  • resilient start: addTenWorkflow completes when run_created returns 500 | wrun_41M0XAQ8AD0GG3DEEMY8R682VV

⚠️ Flaky E2E Tests (passed on retry)

These tests failed at least once and passed on a retry. A recurring entry here is a real race worth investigating.

  • addTenWorkflow (express)
  • cancelRun via CLI - cancelling a running workflow (nextjs-turbopack)
  • hookWithSleepWorkflow - hook payloads delivered correctly with concurrent sleep (nextjs-webpack)
  • promiseAllWorkflow (nuxt)
  • RetryableError respects custom retryAfter delay (nitro)

🛠 Infra Events (absorbed by the harness)

Platform anomalies the e2e harness detected and worked around (e.g. a run the queue never picked up, replaced by a fresh run). Clustered timestamps indicate a backend blip; a steady drip indicates a platform issue worth escalating.

35 infra events
  • cold-start-warmup · suite warmup (python) · at 20:42:37Z · abandoned wrun_41M0XAEJYH0GKQ4W94H3ETH1ZY · (+7 more)
  • run-pickup-stall · nullByteWorkflow (python) · at 20:42:53Z · abandoned wrun_41M0XAJ7Y50GK8N5JNCV12GV8E
  • run-pickup-stall · parallelSleepWorkflow (python) · at 20:42:53Z · abandoned wrun_41M0XAJ7Y20GSX8SWCTH5RVR9M
  • run-pickup-stall · promiseAllWorkflow (python) · at 20:42:53Z · abandoned wrun_41M0XAJ7XV0GG32EEKFRD3B8FS
  • run-pickup-stall · sleepingWorkflow (python) · at 20:42:54Z · abandoned wrun_41M0XAJ7Y20GSX8SWCTH5RVR9K
  • run-pickup-stall · cancelRun - cancelling a running workflow (python) · at 20:42:54Z · abandoned wrun_41M0XAJ8BJ0GJZX1BNBA4CH8W8
  • run-pickup-stall · cancelRun - cancelling a running workflow (python) · at 20:43:27Z · abandoned wrun_41M0XAK8KD0GGARJ5E9EAKDQA7
  • run-pickup-stall · parallelSleepWorkflow (python) · at 20:43:54Z · abandoned wrun_41M0XAM3J00GNDEKT3M4EV9A3B
  • run-pickup-stall · nullByteWorkflow (python) · at 20:43:54Z · abandoned wrun_41M0XAM3J50GY1Z4PYVB875JW2
  • run-pickup-stall · sleepingWorkflow (python) · at 20:43:55Z · abandoned wrun_41M0XAM3NR0GMY2WC43XC9WEEG
  • run-pickup-stall · promiseAllWorkflow (python) · at 20:43:55Z · abandoned wrun_41M0XAM3PT0GKQPBP2CXFAYS50
  • cold-start-warmup · suite warmup (tanstack-start) · at 20:44:26Z · abandoned wrun_01M0XAMQCG384J98J2DSD14DR1
  • run-pickup-stall · cancelRun via CLI - cancelling a running workflow (python) · at 20:44:45Z · abandoned wrun_41M0XAM8FN0GV4BFNTQPWFKM5X
  • cold-start-warmup · suite warmup (python) · at 20:45:16Z · abandoned wrun_01M0XAKEM09ZDGG4DKY24BNT4R · (+7 more)
  • run-pickup-stall · deploymentId: 'latest' is a no-op in non-Vercel worlds (python) · at 20:45:31Z · abandoned wrun_01M0XAQ3RETMHB830AKZR4WRR3
  • run-pickup-stall · promiseAllWorkflow (python) · at 20:45:31Z · abandoned wrun_01M0XAQ3RF7PEAZN9P8KWR413P
  • run-pickup-stall · parallelSleepWorkflow (python) · at 20:45:31Z · abandoned wrun_01M0XAQ3RP7BN47JKYJVR7W9SN
  • run-pickup-stall · sleepingWorkflow (python) · at 20:45:31Z · abandoned wrun_01M0XAQ3RNB63W8SCJMFB059TD
  • run-pickup-stall · nullByteWorkflow (python) · at 20:45:31Z · abandoned wrun_01M0XAQ3RRZXSHD6R9Y4Q7HMN3
  • run-pickup-stall · cancelRun via CLI - cancelling a running workflow (python) · at 20:46:27Z · abandoned wrun_41M0XAQ0C60GXEJ7JBYYKRXP7W
  • run-pickup-stall · sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration (python) · at 20:46:28Z · abandoned wrun_41M0XAPVEJ0GJSWRFAK9D97ABV
  • run-pickup-stall · deploymentId: 'latest' is a no-op in non-Vercel worlds (python) · at 20:46:31Z · abandoned wrun_01M0XARYC38T4GCYXDEWNVNMX3
  • run-pickup-stall · promiseAllWorkflow (python) · at 20:46:31Z · abandoned wrun_01M0XARYC52C67FSA4N73VC5D7
  • run-pickup-stall · sleepingWorkflow (python) · at 20:46:31Z · abandoned wrun_01M0XARYCDFV9BC8DR74AKYXE5
  • run-pickup-stall · parallelSleepWorkflow (python) · at 20:46:32Z · abandoned wrun_01M0XARYCK0DC47WQPD9BH1JVJ
  • run-pickup-stall · nullByteWorkflow (python) · at 20:46:32Z · abandoned wrun_01M0XARYCM1HBYVNK0S93X5J0W
  • run-pickup-stall · cancelRun - cancelling a running workflow (python) · at 20:47:32Z · abandoned wrun_01M0XATRZQVJRSD3M331XYF0RA
  • run-pickup-stall · cancelRun via CLI - cancelling a running workflow (python) · at 20:47:32Z · abandoned wrun_01M0XATRZZS9C3MF3DY87TKVW5
  • run-pickup-stall · sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration (python) · at 20:47:32Z · abandoned wrun_01M0XATS031XZTYSFHCRKFRY0Z
  • run-pickup-stall · cancelRun - cancelling a running workflow (python) · at 20:48:02Z · abandoned wrun_01M0XAVPAX8XNNRK46QNQJ2XK9
  • run-pickup-stall · cancelRun via CLI - cancelling a running workflow (python) · at 20:48:02Z · abandoned wrun_01M0XAVPBFHXMMMA4YG99N83D1
  • run-pickup-stall · sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration (python) · at 20:48:32Z · abandoned wrun_01M0XAWKK6KJ97YQH5T3M65MQN
  • run-pickup-stall · plainModuleDoneHook resumed via plain API route (o2flow shape) (nextjs-webpack) · at 20:51:44Z · abandoned wrun_01M0XB2FMN0D9JTJB906JH00C2
  • run-pickup-stall · hookWithSleepFinalStepWorkflow - step only on final payload (nextjs-webpack) · at 20:52:05Z · abandoned wrun_01M0XB34HFYH9Y559Y5VFH0QKY
  • run-pickup-stall · sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration (nextjs-webpack) · at 20:52:06Z · abandoned wrun_01M0XB34PXRGGCJBBBPNXBSAQW

E2E Test Summary

Summary
PassedFailedSkippedTotal
❌ ▲ Vercel Production357087424320
✅ 💻 Local Development392205584480
✅ 📦 Local Production392205584480
✅ 🐘 Local Postgres392205584480
✅ 🪟 Windows32000320
❌ 🌐 Cross-language Conformance09132141
✅ vercel-http-transport8170143960
✅ vercel-multi-region270027
✅ vercel-ws-transport553087640
Total1705317277819848
Details by Category

❌ ▲ Vercel Production

AppPassedFailedSkipped
✅ astro-node132028
✅ astro-quickjs132028
✅ example-node132028
✅ example-quickjs132028
✅ express-node132028
✅ express-quickjs132028
✅ fastify-node132028
✅ fastify-quickjs132028
✅ hono-node132028
✅ hono-quickjs132028
✅ nest-node132028
✅ nest-quickjs132028
✅ nextjs-turbopack-node15703
✅ nextjs-turbopack-quickjs15703
✅ nextjs-webpack-node15703
✅ nextjs-webpack-quickjs15703
✅ nitro-node132028
✅ nitro-quickjs132028
✅ nuxt-node132028
✅ nuxt-quickjs132028
❌ python-node08152
✅ sveltekit-node15109
✅ sveltekit-quickjs15109
✅ tanstack-start-node132028
✅ tanstack-start-quickjs132028
✅ vite-node132028
✅ vite-quickjs132028

✅ 💻 Local Development

AppPassedFailedSkipped
✅ astro-stable-node134026
✅ astro-stable-quickjs134026
✅ express-stable-node134026
✅ express-stable-quickjs134026
✅ fastify-stable-node134026
✅ fastify-stable-quickjs134026
✅ hono-stable-node134026
✅ hono-stable-quickjs134026
✅ nest-stable-node134026
✅ nest-stable-quickjs134026
✅ nextjs-turbopack-canary-node141019
✅ nextjs-turbopack-canary-quickjs141019
✅ nextjs-turbopack-stable-node16000
✅ nextjs-turbopack-stable-quickjs16000
✅ nextjs-webpack-canary-node141019
✅ nextjs-webpack-canary-quickjs141019
✅ nextjs-webpack-stable-node16000
✅ nextjs-webpack-stable-quickjs16000
✅ nitro-stable-node134026
✅ nitro-stable-quickjs134026
✅ nuxt-stable-node134026
✅ nuxt-stable-quickjs134026
✅ sveltekit-stable-node15307
✅ sveltekit-stable-quickjs15307
✅ tanstack-start-node134026
✅ tanstack-start-quickjs134026
✅ vite-stable-node134026
✅ vite-stable-quickjs134026

✅ 📦 Local Production

AppPassedFailedSkipped
✅ astro-stable-node134026
✅ astro-stable-quickjs134026
✅ express-stable-node134026
✅ express-stable-quickjs134026
✅ fastify-stable-node134026
✅ fastify-stable-quickjs134026
✅ hono-stable-node134026
✅ hono-stable-quickjs134026
✅ nest-stable-node134026
✅ nest-stable-quickjs134026
✅ nextjs-turbopack-canary-node141019
✅ nextjs-turbopack-canary-quickjs141019
✅ nextjs-turbopack-stable-node16000
✅ nextjs-turbopack-stable-quickjs16000
✅ nextjs-webpack-canary-node141019
✅ nextjs-webpack-canary-quickjs141019
✅ nextjs-webpack-stable-node16000
✅ nextjs-webpack-stable-quickjs16000
✅ nitro-stable-node134026
✅ nitro-stable-quickjs134026
✅ nuxt-stable-node134026
✅ nuxt-stable-quickjs134026
✅ sveltekit-stable-node15307
✅ sveltekit-stable-quickjs15307
✅ tanstack-start-node134026
✅ tanstack-start-quickjs134026
✅ vite-stable-node134026
✅ vite-stable-quickjs134026

✅ 🐘 Local Postgres

AppPassedFailedSkipped
✅ astro-stable-node134026
✅ astro-stable-quickjs134026
✅ express-stable-node134026
✅ express-stable-quickjs134026
✅ fastify-stable-node134026
✅ fastify-stable-quickjs134026
✅ hono-stable-node134026
✅ hono-stable-quickjs134026
✅ nest-stable-node134026
✅ nest-stable-quickjs134026
✅ nextjs-turbopack-canary-node141019
✅ nextjs-turbopack-canary-quickjs141019
✅ nextjs-turbopack-stable-node16000
✅ nextjs-turbopack-stable-quickjs16000
✅ nextjs-webpack-canary-node141019
✅ nextjs-webpack-canary-quickjs141019
✅ nextjs-webpack-stable-node16000
✅ nextjs-webpack-stable-quickjs16000
✅ nitro-stable-node134026
✅ nitro-stable-quickjs134026
✅ nuxt-stable-node134026
✅ nuxt-stable-quickjs134026
✅ sveltekit-stable-node15307
✅ sveltekit-stable-quickjs15307
✅ tanstack-start-node134026
✅ tanstack-start-quickjs134026
✅ vite-stable-node134026
✅ vite-stable-quickjs134026

✅ 🪟 Windows

AppPassedFailedSkipped
✅ nextjs-turbopack-node16000
✅ nextjs-turbopack-quickjs16000

❌ 🌐 Cross-language Conformance

AppPassedFailedSkipped
❌ python09132

✅ vercel-http-transport

AppPassedFailedSkipped
✅ example132028
✅ express132028
✅ hono132028
✅ nextjs-turbopack15703
✅ nitro132028
✅ vite132028

✅ vercel-multi-region

AppPassedFailedSkipped
✅ nextjs-turbopack2700

✅ vercel-ws-transport

AppPassedFailedSkipped
✅ example132028
✅ express132028
✅ nextjs-turbopack15703
✅ vite132028

📋 View full workflow run

#3779 fixed the app migration skill, whose description ended with
`mode: 'client'`. The colon-space made the plain scalar parse as a nested
mapping, and the skills CLI dropped the file: `Found 5 skills`, and
`--skill migrating-workflow-v4-to-v5` answered `No matching skills
found`, which is the command whats-new.mdx tells readers to run.
The World skill's description has no colon-space today, so it parses.
It is also 590 characters of backticked identifiers, and any future
edit naming a field with its value reintroduces the break. Fold it the
same way now, while the value is known good. Verified with the yaml
package that the folded scalar is byte-identical, and with
`skills add . --skill migrating-world-v4-to-v5` that the CLI still
finds all six.
Signed-off-by: Peter Wielander <peter.wielander@vercel.com>
@github-actions

Copy link
Copy Markdown
Contributor
FrameworkFlow routeStep reg.Framework output
hono200.9 KiB (±0)40.5 KiB (±0)1.76 MiB (±0)
nextjs-turbopack206.3 KiB (±0)439 B (±0)762.8 KiB (±0)
About these numbers

Sizes are gzip; parentheses show the change against main.
Flow route and Step reg. gate this job, on raw bytes rather than the gzip shown, at max(2%, 50.0 KiB). Framework output is informational.

8d9081b · run

Sign up for freeto 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.

1 participant

@VaguelySerious
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' [docs] Make v5 the default documentation version by VaguelySerious · Pull Request #3714 · vercel/workflow · GitHub
Skip to content

[docs] Make v5 the default documentation version - #3714

Open
VaguelySerious wants to merge 5 commits into
mainfrom
peter/docs-v5-default
Open

[docs] Make v5 the default documentation version#3714
VaguelySerious wants to merge 5 commits into
mainfrom
peter/docs-v5-default

Conversation

@VaguelySerious

@VaguelySeriousVaguelySerious commented Aug 21, 2026

Copy link
Copy Markdown
Member

Makes v5 the default documentation version for the 5.0.0 GA, and catches the v5 content up with everything that landed on main since the v5 docs were last refreshed. Companion to #3090 (exit changeset pre mode) and #3091 (pin 4.x publishes to previous).

Version flip and routing

content/docs/v5 and content/worlds/v5 now serve unprefixed — /docs, /worlds, /cookbook — and v4 moves under a /v4 prefix. The versioned source config drives both route trees (the root tree always renders versionedSources.current), so this is a routePrefix move plus source re-binding, not a restructure. The only file moves are app/[lang]/v5/**app/[lang]/v4/**.

  • Version switcher: labels are v5 (Latest) / v4 (Maintenance); current: 'v5'.
  • Banner: pre-release-banner.tsxmaintenance-banner.tsx. v4 pages carry an amber notice (with dark-mode styling) whose "Go to Workflow 5 (Latest)" link deep-links to the same page on the current version; v4-only pages land on the nearest section index via the fallback redirects. v4 pages keep robots: noindex, follow.
  • Redirects (docs/next.config.ts): /v5/* → unprefixed equivalent (permanent; bare /v5 gets its own rule because :path* expands to an empty Location otherwise). The world-docs and api-reference restructure rules are mirrored onto /v4/docs/*, and every page that exists in only one tree has a version-switcher fallback (verified by diffing the two content trees).
  • Worlds routes: both the unprefixed and /v4 worlds routes pass an explicit version into the shared page components, whose semantics flipped with the switch — smoke checks (assertWorldVersionMarkers, assertServesDirectly('/worlds/turso')) now guard the pairing so the canonical /worlds/* pages can't silently serve the maintenance version or self-redirect-loop again.
  • Link lint (docs/scripts/lint.ts): the two-space model swaps with the URL space; redirect destinations resolve against the real HTTP space since redirects are matched before render-time href rewriting.
  • Intentional oddity: rewriteHrefForVersion pulls unprefixed hrefs on v4 pages into the /v4 view, so a /v5/... href is the only way for v4 content to point at a current page. Three such links are kept deliberately; the lint models this.

What moves with the flip

  • whats-new enters the v5 sidebar, first in the tree. [docs] v5 GA content: What's new, World upgrade guide, migration skills #3100 adds the page but leaves it out of content/docs/v5/meta.json, so until this lands it is reachable only by URL.
  • upgrading-to-v5 moves from app/[lang]/v5/worlds/ to app/[lang]/worlds/, following the rest of the v5 worlds routes.
  • Two cross-version links become expressible and are restored. While v4 is the unprefixed version, a v5 page cannot link to a v4 page at all: an unprefixed href on a v5 page is rewritten into the /v5 view. [docs] v5 GA content: What's new, World upgrade guide, migration skills #3100 therefore phrases both as pointers to the version picker. Here they go back to being links — the v4 docs entry point in the What's new callout, and the v4 version of the code-transform page.
  • editPath on the unprefixed docs route points at docs/content/docs/v5/{path}.

Catch-up with main

Swept the 53 commits that landed since the last content refresh, and added what the docs were missing. Most changesets in that window are fixes, internal, or already documented by their own PR; three things were not.

Spec 7, the sealed log (#3634, not merged, default for v5). Positions are handed out ahead of the commit instead of being claimed by the write that fills them, so concurrent writers never contend and a wide fan-out stops serializing. The cost is a position whose writer dies, which the backend closes with a noop event that replay steps over without delivering it and without advancing the deterministic clock.

  • upgrading-to-v5 › Spec versions is rewritten around mintedSpecVersion(). The accepted range widens back to two versions, because a deployment with WORKFLOW_SEALED_LOG=0 stamps the one below, and that makes both SPEC_VERSION_CURRENT and SPEC_VERSION_SUPPORTS_SLOT_IDENTITY literals by another name for declaring it — neither follows the setting. This replaces what [docs] v5 GA content: What's new, World upgrade guide, migration skills #3100 said for spec 6, which was that exactly one version is accepted.
  • A new "Sealed logs and noop events" subsection says what this costs an implementer, which for most is nothing: a World allocating each position at the commit cannot leave a hole, so it never seals and never emits a noop. The obligation belongs to a World that pre-assigns positions; the half that binds everyone is the reader's.
  • WORKFLOW_SEALED_LOG is documented in runtime-tuning, taken verbatim from Add support for 'noop' event type - spec version 7 #3634 so whichever lands second is a no-op merge. The deep reference sections that PR writes — in event-sourcing and the World allocation contract — are left to it, so this does not duplicate them.
  • The migration skill (v0.2.0) gets the same treatment, phrased as findings to report rather than edits to make.

events.createBatch (#3025). An optional World method appending an ordered list of events in one durable write with per-event outcomes. It was documented only as a changelog page and an env var, so the World reference had no mention of a method a World author has to decide about. Added to the interface snippet, to the Key Implementation Details as a contract note (atomicity per attempt, what a World must reject, the one legal same-entity pair), to the upgrade guide's optional surface, and to the skill.

runs.waitForTerminalStatus (#3570). Also missing from the upgrade guide and the skill. It is what makes await run.returnValue a long poll rather than an interval, which is user-facing, so What's new gets that as an entry.

What's new also gains the batched suspension write and the positions change under faster-and-cheaper runs, where they belong: neither has any API surface.

Not addressed.workflow.step.execute.duration, the OpenTelemetry histogram from #3526, has nowhere to go — the docs carry no metrics reference at all, and inventing one for a single metric is a bigger call than this sweep. Flagging rather than guessing.

Second catch-up: the WebSocket default and spec 7

Merged main again (13 commits). Four conflicts, all against #3704's writing-standards pass over the whole corpus, which rewrote the same paragraphs this branch had edited. Took main's normalized text wherever the difference was purely style, kept this branch's meaning where the two disagreed (the spec-7 paragraph main still had at spec 6, the /v4/... link the flip makes expressible, the batch-write contract note), and restyled this branch's own additions so no prose em dashes come back with it.

The WebSocket events transport is the default now.#3702 flipped it and updated worlds.mdx, vercel.mdx and runtime-tuning.mdx, but What's new still said "an opt-in WebSocket transport ... HTTP remains the default", which was the most wrong sentence left in the v5 docs. It now says what happens, that only the exact value http opts out so a typo fails toward the socket, and that tracing is unchanged because the client span is synthesized around the frame.

Spec 7 is settled.#3634 landed, then #3735 made the sealed log opt-in, then #3737 re-enabled it. The end state matches what this branch already documented, and the WORKFLOW_SEALED_LOG section I had taken verbatim merged as the no-op it was meant to be, modulo #3704's restyling. mintedSpecVersion(), the two-version accepted range, and the "if you allocate at the commit you are already compliant" framing all still hold.

Three World-developer notes, all from #3728. These are the ones a custom World cannot discover from its type errors:

  • Process-wide state has to live on globalThis. A module's top-level const/let is one instance per module instance, and a bundler compiles one copy per layer. The runtime caches the World object process-wide while module state it closes over stays layer-local, so anything a World reaches at request time has to be process-wide too. New contract note in the upgrade guide, plus a step of its own in the World skill (v0.3.0) with an intake item, a globalSingleton() example including what the shape version is for, an output-shape section, and a failure-checklist line. Documented by its casualty: the WS transport registered its channel in the route layer's registry and the write path read the instrumentation layer's empty one, so every event fell back to HTTP for the life of the process, with nothing logged and no test failing.
  • One World per process. The entrypoint's queue handler is built from getWorld() instead of getWorldHandlers(), so a stateful World stops getting duplicate connection pools and queue workers. The build-integration row that still pointed custom hosts at getWorldHandlers() is corrected: that export is the build-time view, not how a request-time handler is assembled.
  • A World's transport is its own business, except for the tracing. How a World ships events is unconstrained. What is constrained is that a non-HTTP transport still owes the per-event client span an HTTP write would emit, or the per-event view of a run silently disappears. Points at the Vercel World's span shape as the worked example.

Nothing needed for the remaining commits in the window: globalSingleton's own changeset and the sideEffects: false declaration are internal, the wait-continuation re-arm and the atomic step_created commit are fixes to behavior already documented, and the decrypt-control and trace-name changes are dashboard-side.

Verification

Link lint passes with 0 errors. pnpm build compiles, with /en/docs/whats-new prerendered under the unprefixed route, /[lang]/v4/docs/[[...slug]] serving the maintenance tree, and ƒ /[lang]/worlds/upgrading-to-v5.

Docs Preview

Links will be added from the workflow-docs preview once it deploys.

🤖 Generated with Claude Code

@vercel

vercelBot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated (UTC)
example-nextjs-workflow-turbopackReadyReadyPreview, v0Aug 25, 2026 8:40pm
example-nextjs-workflow-webpackReadyReadyPreview, v0Aug 25, 2026 8:40pm
example-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-astro-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-express-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-fastify-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-hono-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-nestjs-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-nitro-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-nuxt-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-python-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-sveltekit-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-tanstack-start-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-vite-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workflow-docsReadyReadyPreview, v0Aug 25, 2026 8:40pm
workflow-swc-playgroundBuildingBuildingPreview, v0Aug 25, 2026 8:40pm
workflow-tarballsReadyReadyPreview, v0Aug 25, 2026 8:40pm
workflow-webReadyReadyPreview, v0Aug 25, 2026 8:40pm

@changeset-bot

changeset-botBot commented Aug 21, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 8d9081b

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 0 packages

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions

github-actionsBot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Sim World

Simulated world deterministic testing for races. Traces

🟠 world-sim scenario book — 1 fail of 41 total

fence=per-spec

scenariooutcomeeventsvirtreplayviolations
smoke-no-stepscompleted30msok0
smoke-one-stepcompleted60msok0
hook-at-step-startedcompleted120msok0
hook-at-step-completedcompleted120msok0
hook-at-hook-createdcompleted120msok0
deadline-hook-winscompleted71.0hok0
deadline-expirescompleted71.0hok0
long-sleepcompleted1130.0dok0
hook-never-arrivesstalled30msskipped0
step-retries-twicecompleted102.0sok0
parallel-stepscompleted90msok0
hook-on-execution-statecompleted120msok0
peek-hook-before-branchcompleted120msok0
peek-hook-after-branchcompleted120msok0
peek-hook-at-registrationcompleted120msok0
race-hook-before-probecompleted120msok0
race-hook-after-probecompleted120msok0
race-duplicate-deliverycompleted130msok0
attr-hook-before-stepcompleted110msok0
attr-hook-after-stepcompleted110msok0
attr-from-step-bodycompleted130msok0
fork-hook-after-timeoutcompleted141.0mok0
fork-hook-before-timeoutcompleted141.0mok0
count-hook-after-timeoutcompleted171.0mok0
count-hook-before-timeoutcompleted201.0mok0
stale-read-step-count-forkcompleted201.0mok0
stale-read-equal-step-countscompleted141.0mok0
step-vs-step-forkcompleted120msok0
step-vs-step-fork-fencedcompleted120msok0
fence-catches-benign-directioncompleted125msok0
in-flight-before-decisioncompleted171.0mok0
in-flight-before-decision-countedcompleted171.0mok0
in-flight-after-decisioncompleted192.0mok0
stale-read-step-count-fork-fencedcompleted201.0mok0
fork-hook-winscompleted131.0mok0
fork-timeout-winscompleted131.0mok0
unclaimed-payload-under-forkcompleted171.0mok0
claimed-payload-under-forkcompleted171.0mok0
writers-independent-step-bodiescompleted120msok0
writers-scripted-tempocompleted120msok0
cancel-mid-stepcancelled70msskipped0

Full trace: world-sim.txt

VaguelySeriousand others added 2 commits August 21, 2026 12:50
Serves `content/docs/v5` and `content/worlds/v5` unprefixed at /docs,
/worlds and /cookbook, moves v4 under /v4, and puts What's new first in
the v5 sidebar.
The versioned source config drives both route trees (the root tree always
renders `versionedSources.current`), so this is a `routePrefix` move plus
source re-binding rather than a restructure. The only file moves are
`app/[lang]/v5/**` → `app/[lang]/v4/**`.
- Version switcher: `v5 (Latest)` / `v4 (Maintenance)`, `current: 'v5'`.
- `pre-release-banner.tsx` becomes `maintenance-banner.tsx`. v4 pages
carry an amber notice whose "Go to Workflow 5 (Latest)" link deep-links
to the same page on the current version, falling back to the nearest
section index for v4-only pages, and keep `robots: noindex, follow`.
- Redirects: `/v5/*` to the unprefixed equivalent (bare `/v5` needs its
own rule, since `:path*` expands to an empty Location). The world-docs
and api-reference restructure rules are mirrored onto `/v4/docs/*`, and
every page existing in only one tree gets a version-switcher fallback.
- Both worlds route trees pass an explicit version into the shared page
components, whose semantics flipped with the switch, so the smoke checks
now assert the pairing: a " · v4" title marker and noindex on the
maintenance routes, neither on the canonical ones, and a community world
serving directly rather than self-redirecting.
- The link lint's two URL spaces swap with the prefixes. Redirect
destinations resolve against the real HTTP space, since redirects are
matched before render-time href rewriting.
- The two `/v4/...` links this makes expressible are restored: a v5 page
cannot link to a v4 page while v4 is the unprefixed version.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sweep of everything that landed on main since the last content refresh,
plus the spec-7 sealed log from #3634, which is not merged but is the
default for v5.
Spec 7 changes what a World declares, so the upgrade guide's Spec
versions section is rewritten around `mintedSpecVersion()`. The accepted
range widens back to two versions, because a deployment with
`WORKFLOW_SEALED_LOG=0` stamps the one below, and both `SPEC_VERSION_CURRENT`
and `SPEC_VERSION_SUPPORTS_SLOT_IDENTITY` become literals by another name
for the purpose of declaring it: neither follows the setting. The new
section says what a sealed log costs an implementer, which for most is
nothing — a World allocating each position at the commit cannot leave a
hole, so it never seals and never writes a `noop`. The obligation belongs
to a World that pre-assigns positions, and the half that binds everyone
is the reader's.
`WORKFLOW_SEALED_LOG` is documented in runtime-tuning, taken verbatim
from #3634 so whichever lands second is a no-op merge. The deep
reference sections that PR writes, in event-sourcing and the World
allocation contract, are left to it.
Two optional World members shipped after the guide was written and were
missing everywhere:
- `events.createBatch` — in the World reference (interface and contract
note), the upgrade guide's optional surface, and the skill. Implementing
it is the declaration, so the note leads with atomicity per attempt and
what a World must reject.
- `runs.waitForTerminalStatus` — same three places. It is also what makes
`await run.returnValue` a long poll rather than an interval, which is
user-facing, so What's new gets it too.
What's new also gains the batched suspension write and the pre-assigned
positions behind it, both under faster-and-cheaper runs where they belong:
neither has any API surface.
Not addressed: `workflow.step.execute.duration`, the OpenTelemetry
histogram added in #3526, has nowhere to go. The docs have no metrics
reference at all, and inventing one for a single metric is a bigger call
than this sweep.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@github-actions

github-actionsBot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

🧪 E2E Test Results

Some tests failed

❌ Failed E2E Tests

▲ Vercel Production (8 failed)

python-node (8 failed):

  • promiseAllWorkflow | wrun_41M0XAGXS00GK4H9P4BRDADZPF | 🔍 observability
  • sleepingWorkflow | wrun_41M0XAHK4C0GN8PMSN1G5MJ54R | 🔍 observability
  • parallelSleepWorkflow | wrun_41M0XAHKR70GX6C8R38YRX9JZR | 🔍 observability
  • nullByteWorkflow | wrun_41M0XAHTBJ0GPJDS4V1JB075V8 | 🔍 observability
  • cancelRun - cancelling a running workflow | wrun_41M0XAPE6F0GWZ7WFMJS2WQSZ7 | 🔍 observability
  • cancelRun via CLI - cancelling a running workflow | wrun_41M0XAPJ5Y0GVZ8EPNJZZFBXBN | 🔍 observability
  • sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration | wrun_41M0XAPTHD0GRRQPJZEA3CS0X9 | 🔍 observability
  • resilient start: addTenWorkflow completes when run_created returns 500 | wrun_41M0XAQ8AD0GG3DEEMY8R682VV | 🔍 observability

🌐 Cross-language Conformance (9 failed)

python (9 failed):

  • deploymentId: 'latest' is a no-op in non-Vercel worlds | wrun_01M0XASD1GCVQ8X0DC4TD9QQ8K
  • promiseAllWorkflow | wrun_41M0XAGXS00GK4H9P4BRDADZPF
  • sleepingWorkflow | wrun_41M0XAHK4C0GN8PMSN1G5MJ54R
  • parallelSleepWorkflow | wrun_41M0XAHKR70GX6C8R38YRX9JZR
  • nullByteWorkflow | wrun_41M0XAHTBJ0GPJDS4V1JB075V8
  • cancelRun - cancelling a running workflow | wrun_41M0XAPE6F0GWZ7WFMJS2WQSZ7
  • cancelRun via CLI - cancelling a running workflow | wrun_41M0XAPJ5Y0GVZ8EPNJZZFBXBN
  • sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration | wrun_41M0XAPTHD0GRRQPJZEA3CS0X9
  • resilient start: addTenWorkflow completes when run_created returns 500 | wrun_41M0XAQ8AD0GG3DEEMY8R682VV

⚠️ Flaky E2E Tests (passed on retry)

These tests failed at least once and passed on a retry. A recurring entry here is a real race worth investigating.

  • addTenWorkflow (express)
  • cancelRun via CLI - cancelling a running workflow (nextjs-turbopack)
  • hookWithSleepWorkflow - hook payloads delivered correctly with concurrent sleep (nextjs-webpack)
  • promiseAllWorkflow (nuxt)
  • RetryableError respects custom retryAfter delay (nitro)

🛠 Infra Events (absorbed by the harness)

Platform anomalies the e2e harness detected and worked around (e.g. a run the queue never picked up, replaced by a fresh run). Clustered timestamps indicate a backend blip; a steady drip indicates a platform issue worth escalating.

35 infra events
  • cold-start-warmup · suite warmup (python) · at 20:42:37Z · abandoned wrun_41M0XAEJYH0GKQ4W94H3ETH1ZY · (+7 more)
  • run-pickup-stall · nullByteWorkflow (python) · at 20:42:53Z · abandoned wrun_41M0XAJ7Y50GK8N5JNCV12GV8E
  • run-pickup-stall · parallelSleepWorkflow (python) · at 20:42:53Z · abandoned wrun_41M0XAJ7Y20GSX8SWCTH5RVR9M
  • run-pickup-stall · promiseAllWorkflow (python) · at 20:42:53Z · abandoned wrun_41M0XAJ7XV0GG32EEKFRD3B8FS
  • run-pickup-stall · sleepingWorkflow (python) · at 20:42:54Z · abandoned wrun_41M0XAJ7Y20GSX8SWCTH5RVR9K
  • run-pickup-stall · cancelRun - cancelling a running workflow (python) · at 20:42:54Z · abandoned wrun_41M0XAJ8BJ0GJZX1BNBA4CH8W8
  • run-pickup-stall · cancelRun - cancelling a running workflow (python) · at 20:43:27Z · abandoned wrun_41M0XAK8KD0GGARJ5E9EAKDQA7
  • run-pickup-stall · parallelSleepWorkflow (python) · at 20:43:54Z · abandoned wrun_41M0XAM3J00GNDEKT3M4EV9A3B
  • run-pickup-stall · nullByteWorkflow (python) · at 20:43:54Z · abandoned wrun_41M0XAM3J50GY1Z4PYVB875JW2
  • run-pickup-stall · sleepingWorkflow (python) · at 20:43:55Z · abandoned wrun_41M0XAM3NR0GMY2WC43XC9WEEG
  • run-pickup-stall · promiseAllWorkflow (python) · at 20:43:55Z · abandoned wrun_41M0XAM3PT0GKQPBP2CXFAYS50
  • cold-start-warmup · suite warmup (tanstack-start) · at 20:44:26Z · abandoned wrun_01M0XAMQCG384J98J2DSD14DR1
  • run-pickup-stall · cancelRun via CLI - cancelling a running workflow (python) · at 20:44:45Z · abandoned wrun_41M0XAM8FN0GV4BFNTQPWFKM5X
  • cold-start-warmup · suite warmup (python) · at 20:45:16Z · abandoned wrun_01M0XAKEM09ZDGG4DKY24BNT4R · (+7 more)
  • run-pickup-stall · deploymentId: 'latest' is a no-op in non-Vercel worlds (python) · at 20:45:31Z · abandoned wrun_01M0XAQ3RETMHB830AKZR4WRR3
  • run-pickup-stall · promiseAllWorkflow (python) · at 20:45:31Z · abandoned wrun_01M0XAQ3RF7PEAZN9P8KWR413P
  • run-pickup-stall · parallelSleepWorkflow (python) · at 20:45:31Z · abandoned wrun_01M0XAQ3RP7BN47JKYJVR7W9SN
  • run-pickup-stall · sleepingWorkflow (python) · at 20:45:31Z · abandoned wrun_01M0XAQ3RNB63W8SCJMFB059TD
  • run-pickup-stall · nullByteWorkflow (python) · at 20:45:31Z · abandoned wrun_01M0XAQ3RRZXSHD6R9Y4Q7HMN3
  • run-pickup-stall · cancelRun via CLI - cancelling a running workflow (python) · at 20:46:27Z · abandoned wrun_41M0XAQ0C60GXEJ7JBYYKRXP7W
  • run-pickup-stall · sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration (python) · at 20:46:28Z · abandoned wrun_41M0XAPVEJ0GJSWRFAK9D97ABV
  • run-pickup-stall · deploymentId: 'latest' is a no-op in non-Vercel worlds (python) · at 20:46:31Z · abandoned wrun_01M0XARYC38T4GCYXDEWNVNMX3
  • run-pickup-stall · promiseAllWorkflow (python) · at 20:46:31Z · abandoned wrun_01M0XARYC52C67FSA4N73VC5D7
  • run-pickup-stall · sleepingWorkflow (python) · at 20:46:31Z · abandoned wrun_01M0XARYCDFV9BC8DR74AKYXE5
  • run-pickup-stall · parallelSleepWorkflow (python) · at 20:46:32Z · abandoned wrun_01M0XARYCK0DC47WQPD9BH1JVJ
  • run-pickup-stall · nullByteWorkflow (python) · at 20:46:32Z · abandoned wrun_01M0XARYCM1HBYVNK0S93X5J0W
  • run-pickup-stall · cancelRun - cancelling a running workflow (python) · at 20:47:32Z · abandoned wrun_01M0XATRZQVJRSD3M331XYF0RA
  • run-pickup-stall · cancelRun via CLI - cancelling a running workflow (python) · at 20:47:32Z · abandoned wrun_01M0XATRZZS9C3MF3DY87TKVW5
  • run-pickup-stall · sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration (python) · at 20:47:32Z · abandoned wrun_01M0XATS031XZTYSFHCRKFRY0Z
  • run-pickup-stall · cancelRun - cancelling a running workflow (python) · at 20:48:02Z · abandoned wrun_01M0XAVPAX8XNNRK46QNQJ2XK9
  • run-pickup-stall · cancelRun via CLI - cancelling a running workflow (python) · at 20:48:02Z · abandoned wrun_01M0XAVPBFHXMMMA4YG99N83D1
  • run-pickup-stall · sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration (python) · at 20:48:32Z · abandoned wrun_01M0XAWKK6KJ97YQH5T3M65MQN
  • run-pickup-stall · plainModuleDoneHook resumed via plain API route (o2flow shape) (nextjs-webpack) · at 20:51:44Z · abandoned wrun_01M0XB2FMN0D9JTJB906JH00C2
  • run-pickup-stall · hookWithSleepFinalStepWorkflow - step only on final payload (nextjs-webpack) · at 20:52:05Z · abandoned wrun_01M0XB34HFYH9Y559Y5VFH0QKY
  • run-pickup-stall · sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration (nextjs-webpack) · at 20:52:06Z · abandoned wrun_01M0XB34PXRGGCJBBBPNXBSAQW

E2E Test Summary

Summary
PassedFailedSkippedTotal
❌ ▲ Vercel Production357087424320
✅ 💻 Local Development392205584480
✅ 📦 Local Production392205584480
✅ 🐘 Local Postgres392205584480
✅ 🪟 Windows32000320
❌ 🌐 Cross-language Conformance09132141
✅ vercel-http-transport8170143960
✅ vercel-multi-region270027
✅ vercel-ws-transport553087640
Total1705317277819848
Details by Category

❌ ▲ Vercel Production

AppPassedFailedSkipped
✅ astro-node132028
✅ astro-quickjs132028
✅ example-node132028
✅ example-quickjs132028
✅ express-node132028
✅ express-quickjs132028
✅ fastify-node132028
✅ fastify-quickjs132028
✅ hono-node132028
✅ hono-quickjs132028
✅ nest-node132028
✅ nest-quickjs132028
✅ nextjs-turbopack-node15703
✅ nextjs-turbopack-quickjs15703
✅ nextjs-webpack-node15703
✅ nextjs-webpack-quickjs15703
✅ nitro-node132028
✅ nitro-quickjs132028
✅ nuxt-node132028
✅ nuxt-quickjs132028
❌ python-node08152
✅ sveltekit-node15109
✅ sveltekit-quickjs15109
✅ tanstack-start-node132028
✅ tanstack-start-quickjs132028
✅ vite-node132028
✅ vite-quickjs132028

✅ 💻 Local Development

AppPassedFailedSkipped
✅ astro-stable-node134026
✅ astro-stable-quickjs134026
✅ express-stable-node134026
✅ express-stable-quickjs134026
✅ fastify-stable-node134026
✅ fastify-stable-quickjs134026
✅ hono-stable-node134026
✅ hono-stable-quickjs134026
✅ nest-stable-node134026
✅ nest-stable-quickjs134026
✅ nextjs-turbopack-canary-node141019
✅ nextjs-turbopack-canary-quickjs141019
✅ nextjs-turbopack-stable-node16000
✅ nextjs-turbopack-stable-quickjs16000
✅ nextjs-webpack-canary-node141019
✅ nextjs-webpack-canary-quickjs141019
✅ nextjs-webpack-stable-node16000
✅ nextjs-webpack-stable-quickjs16000
✅ nitro-stable-node134026
✅ nitro-stable-quickjs134026
✅ nuxt-stable-node134026
✅ nuxt-stable-quickjs134026
✅ sveltekit-stable-node15307
✅ sveltekit-stable-quickjs15307
✅ tanstack-start-node134026
✅ tanstack-start-quickjs134026
✅ vite-stable-node134026
✅ vite-stable-quickjs134026

✅ 📦 Local Production

AppPassedFailedSkipped
✅ astro-stable-node134026
✅ astro-stable-quickjs134026
✅ express-stable-node134026
✅ express-stable-quickjs134026
✅ fastify-stable-node134026
✅ fastify-stable-quickjs134026
✅ hono-stable-node134026
✅ hono-stable-quickjs134026
✅ nest-stable-node134026
✅ nest-stable-quickjs134026
✅ nextjs-turbopack-canary-node141019
✅ nextjs-turbopack-canary-quickjs141019
✅ nextjs-turbopack-stable-node16000
✅ nextjs-turbopack-stable-quickjs16000
✅ nextjs-webpack-canary-node141019
✅ nextjs-webpack-canary-quickjs141019
✅ nextjs-webpack-stable-node16000
✅ nextjs-webpack-stable-quickjs16000
✅ nitro-stable-node134026
✅ nitro-stable-quickjs134026
✅ nuxt-stable-node134026
✅ nuxt-stable-quickjs134026
✅ sveltekit-stable-node15307
✅ sveltekit-stable-quickjs15307
✅ tanstack-start-node134026
✅ tanstack-start-quickjs134026
✅ vite-stable-node134026
✅ vite-stable-quickjs134026

✅ 🐘 Local Postgres

AppPassedFailedSkipped
✅ astro-stable-node134026
✅ astro-stable-quickjs134026
✅ express-stable-node134026
✅ express-stable-quickjs134026
✅ fastify-stable-node134026
✅ fastify-stable-quickjs134026
✅ hono-stable-node134026
✅ hono-stable-quickjs134026
✅ nest-stable-node134026
✅ nest-stable-quickjs134026
✅ nextjs-turbopack-canary-node141019
✅ nextjs-turbopack-canary-quickjs141019
✅ nextjs-turbopack-stable-node16000
✅ nextjs-turbopack-stable-quickjs16000
✅ nextjs-webpack-canary-node141019
✅ nextjs-webpack-canary-quickjs141019
✅ nextjs-webpack-stable-node16000
✅ nextjs-webpack-stable-quickjs16000
✅ nitro-stable-node134026
✅ nitro-stable-quickjs134026
✅ nuxt-stable-node134026
✅ nuxt-stable-quickjs134026
✅ sveltekit-stable-node15307
✅ sveltekit-stable-quickjs15307
✅ tanstack-start-node134026
✅ tanstack-start-quickjs134026
✅ vite-stable-node134026
✅ vite-stable-quickjs134026

✅ 🪟 Windows

AppPassedFailedSkipped
✅ nextjs-turbopack-node16000
✅ nextjs-turbopack-quickjs16000

❌ 🌐 Cross-language Conformance

AppPassedFailedSkipped
❌ python09132

✅ vercel-http-transport

AppPassedFailedSkipped
✅ example132028
✅ express132028
✅ hono132028
✅ nextjs-turbopack15703
✅ nitro132028
✅ vite132028

✅ vercel-multi-region

AppPassedFailedSkipped
✅ nextjs-turbopack2700

✅ vercel-ws-transport

AppPassedFailedSkipped
✅ example132028
✅ express132028
✅ nextjs-turbopack15703
✅ vite132028

📋 View full workflow run

#3779 fixed the app migration skill, whose description ended with
`mode: 'client'`. The colon-space made the plain scalar parse as a nested
mapping, and the skills CLI dropped the file: `Found 5 skills`, and
`--skill migrating-workflow-v4-to-v5` answered `No matching skills
found`, which is the command whats-new.mdx tells readers to run.
The World skill's description has no colon-space today, so it parses.
It is also 590 characters of backticked identifiers, and any future
edit naming a field with its value reintroduces the break. Fold it the
same way now, while the value is known good. Verified with the yaml
package that the folded scalar is byte-identical, and with
`skills add . --skill migrating-world-v4-to-v5` that the CLI still
finds all six.
Signed-off-by: Peter Wielander <peter.wielander@vercel.com>
@github-actions

Copy link
Copy Markdown
Contributor
FrameworkFlow routeStep reg.Framework output
hono200.9 KiB (±0)40.5 KiB (±0)1.76 MiB (±0)
nextjs-turbopack206.3 KiB (±0)439 B (±0)762.8 KiB (±0)
About these numbers

Sizes are gzip; parentheses show the change against main.
Flow route and Step reg. gate this job, on raw bytes rather than the gzip shown, at max(2%, 50.0 KiB). Framework output is informational.

8d9081b · run

Sign up for freeto 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.

1 participant

@VaguelySerious
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' [docs] Make v5 the default documentation version by VaguelySerious · Pull Request #3714 · vercel/workflow · GitHub
Skip to content

[docs] Make v5 the default documentation version - #3714

Open
VaguelySerious wants to merge 5 commits into
mainfrom
peter/docs-v5-default
Open

[docs] Make v5 the default documentation version#3714
VaguelySerious wants to merge 5 commits into
mainfrom
peter/docs-v5-default

Conversation

@VaguelySerious

@VaguelySeriousVaguelySerious commented Aug 21, 2026

Copy link
Copy Markdown
Member

Makes v5 the default documentation version for the 5.0.0 GA, and catches the v5 content up with everything that landed on main since the v5 docs were last refreshed. Companion to #3090 (exit changeset pre mode) and #3091 (pin 4.x publishes to previous).

Version flip and routing

content/docs/v5 and content/worlds/v5 now serve unprefixed — /docs, /worlds, /cookbook — and v4 moves under a /v4 prefix. The versioned source config drives both route trees (the root tree always renders versionedSources.current), so this is a routePrefix move plus source re-binding, not a restructure. The only file moves are app/[lang]/v5/**app/[lang]/v4/**.

  • Version switcher: labels are v5 (Latest) / v4 (Maintenance); current: 'v5'.
  • Banner: pre-release-banner.tsxmaintenance-banner.tsx. v4 pages carry an amber notice (with dark-mode styling) whose "Go to Workflow 5 (Latest)" link deep-links to the same page on the current version; v4-only pages land on the nearest section index via the fallback redirects. v4 pages keep robots: noindex, follow.
  • Redirects (docs/next.config.ts): /v5/* → unprefixed equivalent (permanent; bare /v5 gets its own rule because :path* expands to an empty Location otherwise). The world-docs and api-reference restructure rules are mirrored onto /v4/docs/*, and every page that exists in only one tree has a version-switcher fallback (verified by diffing the two content trees).
  • Worlds routes: both the unprefixed and /v4 worlds routes pass an explicit version into the shared page components, whose semantics flipped with the switch — smoke checks (assertWorldVersionMarkers, assertServesDirectly('/worlds/turso')) now guard the pairing so the canonical /worlds/* pages can't silently serve the maintenance version or self-redirect-loop again.
  • Link lint (docs/scripts/lint.ts): the two-space model swaps with the URL space; redirect destinations resolve against the real HTTP space since redirects are matched before render-time href rewriting.
  • Intentional oddity: rewriteHrefForVersion pulls unprefixed hrefs on v4 pages into the /v4 view, so a /v5/... href is the only way for v4 content to point at a current page. Three such links are kept deliberately; the lint models this.

What moves with the flip

  • whats-new enters the v5 sidebar, first in the tree. [docs] v5 GA content: What's new, World upgrade guide, migration skills #3100 adds the page but leaves it out of content/docs/v5/meta.json, so until this lands it is reachable only by URL.
  • upgrading-to-v5 moves from app/[lang]/v5/worlds/ to app/[lang]/worlds/, following the rest of the v5 worlds routes.
  • Two cross-version links become expressible and are restored. While v4 is the unprefixed version, a v5 page cannot link to a v4 page at all: an unprefixed href on a v5 page is rewritten into the /v5 view. [docs] v5 GA content: What's new, World upgrade guide, migration skills #3100 therefore phrases both as pointers to the version picker. Here they go back to being links — the v4 docs entry point in the What's new callout, and the v4 version of the code-transform page.
  • editPath on the unprefixed docs route points at docs/content/docs/v5/{path}.

Catch-up with main

Swept the 53 commits that landed since the last content refresh, and added what the docs were missing. Most changesets in that window are fixes, internal, or already documented by their own PR; three things were not.

Spec 7, the sealed log (#3634, not merged, default for v5). Positions are handed out ahead of the commit instead of being claimed by the write that fills them, so concurrent writers never contend and a wide fan-out stops serializing. The cost is a position whose writer dies, which the backend closes with a noop event that replay steps over without delivering it and without advancing the deterministic clock.

  • upgrading-to-v5 › Spec versions is rewritten around mintedSpecVersion(). The accepted range widens back to two versions, because a deployment with WORKFLOW_SEALED_LOG=0 stamps the one below, and that makes both SPEC_VERSION_CURRENT and SPEC_VERSION_SUPPORTS_SLOT_IDENTITY literals by another name for declaring it — neither follows the setting. This replaces what [docs] v5 GA content: What's new, World upgrade guide, migration skills #3100 said for spec 6, which was that exactly one version is accepted.
  • A new "Sealed logs and noop events" subsection says what this costs an implementer, which for most is nothing: a World allocating each position at the commit cannot leave a hole, so it never seals and never emits a noop. The obligation belongs to a World that pre-assigns positions; the half that binds everyone is the reader's.
  • WORKFLOW_SEALED_LOG is documented in runtime-tuning, taken verbatim from Add support for 'noop' event type - spec version 7 #3634 so whichever lands second is a no-op merge. The deep reference sections that PR writes — in event-sourcing and the World allocation contract — are left to it, so this does not duplicate them.
  • The migration skill (v0.2.0) gets the same treatment, phrased as findings to report rather than edits to make.

events.createBatch (#3025). An optional World method appending an ordered list of events in one durable write with per-event outcomes. It was documented only as a changelog page and an env var, so the World reference had no mention of a method a World author has to decide about. Added to the interface snippet, to the Key Implementation Details as a contract note (atomicity per attempt, what a World must reject, the one legal same-entity pair), to the upgrade guide's optional surface, and to the skill.

runs.waitForTerminalStatus (#3570). Also missing from the upgrade guide and the skill. It is what makes await run.returnValue a long poll rather than an interval, which is user-facing, so What's new gets that as an entry.

What's new also gains the batched suspension write and the positions change under faster-and-cheaper runs, where they belong: neither has any API surface.

Not addressed.workflow.step.execute.duration, the OpenTelemetry histogram from #3526, has nowhere to go — the docs carry no metrics reference at all, and inventing one for a single metric is a bigger call than this sweep. Flagging rather than guessing.

Second catch-up: the WebSocket default and spec 7

Merged main again (13 commits). Four conflicts, all against #3704's writing-standards pass over the whole corpus, which rewrote the same paragraphs this branch had edited. Took main's normalized text wherever the difference was purely style, kept this branch's meaning where the two disagreed (the spec-7 paragraph main still had at spec 6, the /v4/... link the flip makes expressible, the batch-write contract note), and restyled this branch's own additions so no prose em dashes come back with it.

The WebSocket events transport is the default now.#3702 flipped it and updated worlds.mdx, vercel.mdx and runtime-tuning.mdx, but What's new still said "an opt-in WebSocket transport ... HTTP remains the default", which was the most wrong sentence left in the v5 docs. It now says what happens, that only the exact value http opts out so a typo fails toward the socket, and that tracing is unchanged because the client span is synthesized around the frame.

Spec 7 is settled.#3634 landed, then #3735 made the sealed log opt-in, then #3737 re-enabled it. The end state matches what this branch already documented, and the WORKFLOW_SEALED_LOG section I had taken verbatim merged as the no-op it was meant to be, modulo #3704's restyling. mintedSpecVersion(), the two-version accepted range, and the "if you allocate at the commit you are already compliant" framing all still hold.

Three World-developer notes, all from #3728. These are the ones a custom World cannot discover from its type errors:

  • Process-wide state has to live on globalThis. A module's top-level const/let is one instance per module instance, and a bundler compiles one copy per layer. The runtime caches the World object process-wide while module state it closes over stays layer-local, so anything a World reaches at request time has to be process-wide too. New contract note in the upgrade guide, plus a step of its own in the World skill (v0.3.0) with an intake item, a globalSingleton() example including what the shape version is for, an output-shape section, and a failure-checklist line. Documented by its casualty: the WS transport registered its channel in the route layer's registry and the write path read the instrumentation layer's empty one, so every event fell back to HTTP for the life of the process, with nothing logged and no test failing.
  • One World per process. The entrypoint's queue handler is built from getWorld() instead of getWorldHandlers(), so a stateful World stops getting duplicate connection pools and queue workers. The build-integration row that still pointed custom hosts at getWorldHandlers() is corrected: that export is the build-time view, not how a request-time handler is assembled.
  • A World's transport is its own business, except for the tracing. How a World ships events is unconstrained. What is constrained is that a non-HTTP transport still owes the per-event client span an HTTP write would emit, or the per-event view of a run silently disappears. Points at the Vercel World's span shape as the worked example.

Nothing needed for the remaining commits in the window: globalSingleton's own changeset and the sideEffects: false declaration are internal, the wait-continuation re-arm and the atomic step_created commit are fixes to behavior already documented, and the decrypt-control and trace-name changes are dashboard-side.

Verification

Link lint passes with 0 errors. pnpm build compiles, with /en/docs/whats-new prerendered under the unprefixed route, /[lang]/v4/docs/[[...slug]] serving the maintenance tree, and ƒ /[lang]/worlds/upgrading-to-v5.

Docs Preview

Links will be added from the workflow-docs preview once it deploys.

🤖 Generated with Claude Code

@vercel

vercelBot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated (UTC)
example-nextjs-workflow-turbopackReadyReadyPreview, v0Aug 25, 2026 8:40pm
example-nextjs-workflow-webpackReadyReadyPreview, v0Aug 25, 2026 8:40pm
example-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-astro-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-express-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-fastify-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-hono-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-nestjs-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-nitro-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-nuxt-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-python-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-sveltekit-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-tanstack-start-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-vite-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workflow-docsReadyReadyPreview, v0Aug 25, 2026 8:40pm
workflow-swc-playgroundBuildingBuildingPreview, v0Aug 25, 2026 8:40pm
workflow-tarballsReadyReadyPreview, v0Aug 25, 2026 8:40pm
workflow-webReadyReadyPreview, v0Aug 25, 2026 8:40pm

@changeset-bot

changeset-botBot commented Aug 21, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 8d9081b

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 0 packages

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions

github-actionsBot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Sim World

Simulated world deterministic testing for races. Traces

🟠 world-sim scenario book — 1 fail of 41 total

fence=per-spec

scenariooutcomeeventsvirtreplayviolations
smoke-no-stepscompleted30msok0
smoke-one-stepcompleted60msok0
hook-at-step-startedcompleted120msok0
hook-at-step-completedcompleted120msok0
hook-at-hook-createdcompleted120msok0
deadline-hook-winscompleted71.0hok0
deadline-expirescompleted71.0hok0
long-sleepcompleted1130.0dok0
hook-never-arrivesstalled30msskipped0
step-retries-twicecompleted102.0sok0
parallel-stepscompleted90msok0
hook-on-execution-statecompleted120msok0
peek-hook-before-branchcompleted120msok0
peek-hook-after-branchcompleted120msok0
peek-hook-at-registrationcompleted120msok0
race-hook-before-probecompleted120msok0
race-hook-after-probecompleted120msok0
race-duplicate-deliverycompleted130msok0
attr-hook-before-stepcompleted110msok0
attr-hook-after-stepcompleted110msok0
attr-from-step-bodycompleted130msok0
fork-hook-after-timeoutcompleted141.0mok0
fork-hook-before-timeoutcompleted141.0mok0
count-hook-after-timeoutcompleted171.0mok0
count-hook-before-timeoutcompleted201.0mok0
stale-read-step-count-forkcompleted201.0mok0
stale-read-equal-step-countscompleted141.0mok0
step-vs-step-forkcompleted120msok0
step-vs-step-fork-fencedcompleted120msok0
fence-catches-benign-directioncompleted125msok0
in-flight-before-decisioncompleted171.0mok0
in-flight-before-decision-countedcompleted171.0mok0
in-flight-after-decisioncompleted192.0mok0
stale-read-step-count-fork-fencedcompleted201.0mok0
fork-hook-winscompleted131.0mok0
fork-timeout-winscompleted131.0mok0
unclaimed-payload-under-forkcompleted171.0mok0
claimed-payload-under-forkcompleted171.0mok0
writers-independent-step-bodiescompleted120msok0
writers-scripted-tempocompleted120msok0
cancel-mid-stepcancelled70msskipped0

Full trace: world-sim.txt

VaguelySeriousand others added 2 commits August 21, 2026 12:50
Serves `content/docs/v5` and `content/worlds/v5` unprefixed at /docs,
/worlds and /cookbook, moves v4 under /v4, and puts What's new first in
the v5 sidebar.
The versioned source config drives both route trees (the root tree always
renders `versionedSources.current`), so this is a `routePrefix` move plus
source re-binding rather than a restructure. The only file moves are
`app/[lang]/v5/**` → `app/[lang]/v4/**`.
- Version switcher: `v5 (Latest)` / `v4 (Maintenance)`, `current: 'v5'`.
- `pre-release-banner.tsx` becomes `maintenance-banner.tsx`. v4 pages
carry an amber notice whose "Go to Workflow 5 (Latest)" link deep-links
to the same page on the current version, falling back to the nearest
section index for v4-only pages, and keep `robots: noindex, follow`.
- Redirects: `/v5/*` to the unprefixed equivalent (bare `/v5` needs its
own rule, since `:path*` expands to an empty Location). The world-docs
and api-reference restructure rules are mirrored onto `/v4/docs/*`, and
every page existing in only one tree gets a version-switcher fallback.
- Both worlds route trees pass an explicit version into the shared page
components, whose semantics flipped with the switch, so the smoke checks
now assert the pairing: a " · v4" title marker and noindex on the
maintenance routes, neither on the canonical ones, and a community world
serving directly rather than self-redirecting.
- The link lint's two URL spaces swap with the prefixes. Redirect
destinations resolve against the real HTTP space, since redirects are
matched before render-time href rewriting.
- The two `/v4/...` links this makes expressible are restored: a v5 page
cannot link to a v4 page while v4 is the unprefixed version.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sweep of everything that landed on main since the last content refresh,
plus the spec-7 sealed log from #3634, which is not merged but is the
default for v5.
Spec 7 changes what a World declares, so the upgrade guide's Spec
versions section is rewritten around `mintedSpecVersion()`. The accepted
range widens back to two versions, because a deployment with
`WORKFLOW_SEALED_LOG=0` stamps the one below, and both `SPEC_VERSION_CURRENT`
and `SPEC_VERSION_SUPPORTS_SLOT_IDENTITY` become literals by another name
for the purpose of declaring it: neither follows the setting. The new
section says what a sealed log costs an implementer, which for most is
nothing — a World allocating each position at the commit cannot leave a
hole, so it never seals and never writes a `noop`. The obligation belongs
to a World that pre-assigns positions, and the half that binds everyone
is the reader's.
`WORKFLOW_SEALED_LOG` is documented in runtime-tuning, taken verbatim
from #3634 so whichever lands second is a no-op merge. The deep
reference sections that PR writes, in event-sourcing and the World
allocation contract, are left to it.
Two optional World members shipped after the guide was written and were
missing everywhere:
- `events.createBatch` — in the World reference (interface and contract
note), the upgrade guide's optional surface, and the skill. Implementing
it is the declaration, so the note leads with atomicity per attempt and
what a World must reject.
- `runs.waitForTerminalStatus` — same three places. It is also what makes
`await run.returnValue` a long poll rather than an interval, which is
user-facing, so What's new gets it too.
What's new also gains the batched suspension write and the pre-assigned
positions behind it, both under faster-and-cheaper runs where they belong:
neither has any API surface.
Not addressed: `workflow.step.execute.duration`, the OpenTelemetry
histogram added in #3526, has nowhere to go. The docs have no metrics
reference at all, and inventing one for a single metric is a bigger call
than this sweep.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@github-actions

github-actionsBot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

🧪 E2E Test Results

Some tests failed

❌ Failed E2E Tests

▲ Vercel Production (8 failed)

python-node (8 failed):

  • promiseAllWorkflow | wrun_41M0XAGXS00GK4H9P4BRDADZPF | 🔍 observability
  • sleepingWorkflow | wrun_41M0XAHK4C0GN8PMSN1G5MJ54R | 🔍 observability
  • parallelSleepWorkflow | wrun_41M0XAHKR70GX6C8R38YRX9JZR | 🔍 observability
  • nullByteWorkflow | wrun_41M0XAHTBJ0GPJDS4V1JB075V8 | 🔍 observability
  • cancelRun - cancelling a running workflow | wrun_41M0XAPE6F0GWZ7WFMJS2WQSZ7 | 🔍 observability
  • cancelRun via CLI - cancelling a running workflow | wrun_41M0XAPJ5Y0GVZ8EPNJZZFBXBN | 🔍 observability
  • sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration | wrun_41M0XAPTHD0GRRQPJZEA3CS0X9 | 🔍 observability
  • resilient start: addTenWorkflow completes when run_created returns 500 | wrun_41M0XAQ8AD0GG3DEEMY8R682VV | 🔍 observability

🌐 Cross-language Conformance (9 failed)

python (9 failed):

  • deploymentId: 'latest' is a no-op in non-Vercel worlds | wrun_01M0XASD1GCVQ8X0DC4TD9QQ8K
  • promiseAllWorkflow | wrun_41M0XAGXS00GK4H9P4BRDADZPF
  • sleepingWorkflow | wrun_41M0XAHK4C0GN8PMSN1G5MJ54R
  • parallelSleepWorkflow | wrun_41M0XAHKR70GX6C8R38YRX9JZR
  • nullByteWorkflow | wrun_41M0XAHTBJ0GPJDS4V1JB075V8
  • cancelRun - cancelling a running workflow | wrun_41M0XAPE6F0GWZ7WFMJS2WQSZ7
  • cancelRun via CLI - cancelling a running workflow | wrun_41M0XAPJ5Y0GVZ8EPNJZZFBXBN
  • sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration | wrun_41M0XAPTHD0GRRQPJZEA3CS0X9
  • resilient start: addTenWorkflow completes when run_created returns 500 | wrun_41M0XAQ8AD0GG3DEEMY8R682VV

⚠️ Flaky E2E Tests (passed on retry)

These tests failed at least once and passed on a retry. A recurring entry here is a real race worth investigating.

  • addTenWorkflow (express)
  • cancelRun via CLI - cancelling a running workflow (nextjs-turbopack)
  • hookWithSleepWorkflow - hook payloads delivered correctly with concurrent sleep (nextjs-webpack)
  • promiseAllWorkflow (nuxt)
  • RetryableError respects custom retryAfter delay (nitro)

🛠 Infra Events (absorbed by the harness)

Platform anomalies the e2e harness detected and worked around (e.g. a run the queue never picked up, replaced by a fresh run). Clustered timestamps indicate a backend blip; a steady drip indicates a platform issue worth escalating.

35 infra events
  • cold-start-warmup · suite warmup (python) · at 20:42:37Z · abandoned wrun_41M0XAEJYH0GKQ4W94H3ETH1ZY · (+7 more)
  • run-pickup-stall · nullByteWorkflow (python) · at 20:42:53Z · abandoned wrun_41M0XAJ7Y50GK8N5JNCV12GV8E
  • run-pickup-stall · parallelSleepWorkflow (python) · at 20:42:53Z · abandoned wrun_41M0XAJ7Y20GSX8SWCTH5RVR9M
  • run-pickup-stall · promiseAllWorkflow (python) · at 20:42:53Z · abandoned wrun_41M0XAJ7XV0GG32EEKFRD3B8FS
  • run-pickup-stall · sleepingWorkflow (python) · at 20:42:54Z · abandoned wrun_41M0XAJ7Y20GSX8SWCTH5RVR9K
  • run-pickup-stall · cancelRun - cancelling a running workflow (python) · at 20:42:54Z · abandoned wrun_41M0XAJ8BJ0GJZX1BNBA4CH8W8
  • run-pickup-stall · cancelRun - cancelling a running workflow (python) · at 20:43:27Z · abandoned wrun_41M0XAK8KD0GGARJ5E9EAKDQA7
  • run-pickup-stall · parallelSleepWorkflow (python) · at 20:43:54Z · abandoned wrun_41M0XAM3J00GNDEKT3M4EV9A3B
  • run-pickup-stall · nullByteWorkflow (python) · at 20:43:54Z · abandoned wrun_41M0XAM3J50GY1Z4PYVB875JW2
  • run-pickup-stall · sleepingWorkflow (python) · at 20:43:55Z · abandoned wrun_41M0XAM3NR0GMY2WC43XC9WEEG
  • run-pickup-stall · promiseAllWorkflow (python) · at 20:43:55Z · abandoned wrun_41M0XAM3PT0GKQPBP2CXFAYS50
  • cold-start-warmup · suite warmup (tanstack-start) · at 20:44:26Z · abandoned wrun_01M0XAMQCG384J98J2DSD14DR1
  • run-pickup-stall · cancelRun via CLI - cancelling a running workflow (python) · at 20:44:45Z · abandoned wrun_41M0XAM8FN0GV4BFNTQPWFKM5X
  • cold-start-warmup · suite warmup (python) · at 20:45:16Z · abandoned wrun_01M0XAKEM09ZDGG4DKY24BNT4R · (+7 more)
  • run-pickup-stall · deploymentId: 'latest' is a no-op in non-Vercel worlds (python) · at 20:45:31Z · abandoned wrun_01M0XAQ3RETMHB830AKZR4WRR3
  • run-pickup-stall · promiseAllWorkflow (python) · at 20:45:31Z · abandoned wrun_01M0XAQ3RF7PEAZN9P8KWR413P
  • run-pickup-stall · parallelSleepWorkflow (python) · at 20:45:31Z · abandoned wrun_01M0XAQ3RP7BN47JKYJVR7W9SN
  • run-pickup-stall · sleepingWorkflow (python) · at 20:45:31Z · abandoned wrun_01M0XAQ3RNB63W8SCJMFB059TD
  • run-pickup-stall · nullByteWorkflow (python) · at 20:45:31Z · abandoned wrun_01M0XAQ3RRZXSHD6R9Y4Q7HMN3
  • run-pickup-stall · cancelRun via CLI - cancelling a running workflow (python) · at 20:46:27Z · abandoned wrun_41M0XAQ0C60GXEJ7JBYYKRXP7W
  • run-pickup-stall · sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration (python) · at 20:46:28Z · abandoned wrun_41M0XAPVEJ0GJSWRFAK9D97ABV
  • run-pickup-stall · deploymentId: 'latest' is a no-op in non-Vercel worlds (python) · at 20:46:31Z · abandoned wrun_01M0XARYC38T4GCYXDEWNVNMX3
  • run-pickup-stall · promiseAllWorkflow (python) · at 20:46:31Z · abandoned wrun_01M0XARYC52C67FSA4N73VC5D7
  • run-pickup-stall · sleepingWorkflow (python) · at 20:46:31Z · abandoned wrun_01M0XARYCDFV9BC8DR74AKYXE5
  • run-pickup-stall · parallelSleepWorkflow (python) · at 20:46:32Z · abandoned wrun_01M0XARYCK0DC47WQPD9BH1JVJ
  • run-pickup-stall · nullByteWorkflow (python) · at 20:46:32Z · abandoned wrun_01M0XARYCM1HBYVNK0S93X5J0W
  • run-pickup-stall · cancelRun - cancelling a running workflow (python) · at 20:47:32Z · abandoned wrun_01M0XATRZQVJRSD3M331XYF0RA
  • run-pickup-stall · cancelRun via CLI - cancelling a running workflow (python) · at 20:47:32Z · abandoned wrun_01M0XATRZZS9C3MF3DY87TKVW5
  • run-pickup-stall · sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration (python) · at 20:47:32Z · abandoned wrun_01M0XATS031XZTYSFHCRKFRY0Z
  • run-pickup-stall · cancelRun - cancelling a running workflow (python) · at 20:48:02Z · abandoned wrun_01M0XAVPAX8XNNRK46QNQJ2XK9
  • run-pickup-stall · cancelRun via CLI - cancelling a running workflow (python) · at 20:48:02Z · abandoned wrun_01M0XAVPBFHXMMMA4YG99N83D1
  • run-pickup-stall · sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration (python) · at 20:48:32Z · abandoned wrun_01M0XAWKK6KJ97YQH5T3M65MQN
  • run-pickup-stall · plainModuleDoneHook resumed via plain API route (o2flow shape) (nextjs-webpack) · at 20:51:44Z · abandoned wrun_01M0XB2FMN0D9JTJB906JH00C2
  • run-pickup-stall · hookWithSleepFinalStepWorkflow - step only on final payload (nextjs-webpack) · at 20:52:05Z · abandoned wrun_01M0XB34HFYH9Y559Y5VFH0QKY
  • run-pickup-stall · sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration (nextjs-webpack) · at 20:52:06Z · abandoned wrun_01M0XB34PXRGGCJBBBPNXBSAQW

E2E Test Summary

Summary
PassedFailedSkippedTotal
❌ ▲ Vercel Production357087424320
✅ 💻 Local Development392205584480
✅ 📦 Local Production392205584480
✅ 🐘 Local Postgres392205584480
✅ 🪟 Windows32000320
❌ 🌐 Cross-language Conformance09132141
✅ vercel-http-transport8170143960
✅ vercel-multi-region270027
✅ vercel-ws-transport553087640
Total1705317277819848
Details by Category

❌ ▲ Vercel Production

AppPassedFailedSkipped
✅ astro-node132028
✅ astro-quickjs132028
✅ example-node132028
✅ example-quickjs132028
✅ express-node132028
✅ express-quickjs132028
✅ fastify-node132028
✅ fastify-quickjs132028
✅ hono-node132028
✅ hono-quickjs132028
✅ nest-node132028
✅ nest-quickjs132028
✅ nextjs-turbopack-node15703
✅ nextjs-turbopack-quickjs15703
✅ nextjs-webpack-node15703
✅ nextjs-webpack-quickjs15703
✅ nitro-node132028
✅ nitro-quickjs132028
✅ nuxt-node132028
✅ nuxt-quickjs132028
❌ python-node08152
✅ sveltekit-node15109
✅ sveltekit-quickjs15109
✅ tanstack-start-node132028
✅ tanstack-start-quickjs132028
✅ vite-node132028
✅ vite-quickjs132028

✅ 💻 Local Development

AppPassedFailedSkipped
✅ astro-stable-node134026
✅ astro-stable-quickjs134026
✅ express-stable-node134026
✅ express-stable-quickjs134026
✅ fastify-stable-node134026
✅ fastify-stable-quickjs134026
✅ hono-stable-node134026
✅ hono-stable-quickjs134026
✅ nest-stable-node134026
✅ nest-stable-quickjs134026
✅ nextjs-turbopack-canary-node141019
✅ nextjs-turbopack-canary-quickjs141019
✅ nextjs-turbopack-stable-node16000
✅ nextjs-turbopack-stable-quickjs16000
✅ nextjs-webpack-canary-node141019
✅ nextjs-webpack-canary-quickjs141019
✅ nextjs-webpack-stable-node16000
✅ nextjs-webpack-stable-quickjs16000
✅ nitro-stable-node134026
✅ nitro-stable-quickjs134026
✅ nuxt-stable-node134026
✅ nuxt-stable-quickjs134026
✅ sveltekit-stable-node15307
✅ sveltekit-stable-quickjs15307
✅ tanstack-start-node134026
✅ tanstack-start-quickjs134026
✅ vite-stable-node134026
✅ vite-stable-quickjs134026

✅ 📦 Local Production

AppPassedFailedSkipped
✅ astro-stable-node134026
✅ astro-stable-quickjs134026
✅ express-stable-node134026
✅ express-stable-quickjs134026
✅ fastify-stable-node134026
✅ fastify-stable-quickjs134026
✅ hono-stable-node134026
✅ hono-stable-quickjs134026
✅ nest-stable-node134026
✅ nest-stable-quickjs134026
✅ nextjs-turbopack-canary-node141019
✅ nextjs-turbopack-canary-quickjs141019
✅ nextjs-turbopack-stable-node16000
✅ nextjs-turbopack-stable-quickjs16000
✅ nextjs-webpack-canary-node141019
✅ nextjs-webpack-canary-quickjs141019
✅ nextjs-webpack-stable-node16000
✅ nextjs-webpack-stable-quickjs16000
✅ nitro-stable-node134026
✅ nitro-stable-quickjs134026
✅ nuxt-stable-node134026
✅ nuxt-stable-quickjs134026
✅ sveltekit-stable-node15307
✅ sveltekit-stable-quickjs15307
✅ tanstack-start-node134026
✅ tanstack-start-quickjs134026
✅ vite-stable-node134026
✅ vite-stable-quickjs134026

✅ 🐘 Local Postgres

AppPassedFailedSkipped
✅ astro-stable-node134026
✅ astro-stable-quickjs134026
✅ express-stable-node134026
✅ express-stable-quickjs134026
✅ fastify-stable-node134026
✅ fastify-stable-quickjs134026
✅ hono-stable-node134026
✅ hono-stable-quickjs134026
✅ nest-stable-node134026
✅ nest-stable-quickjs134026
✅ nextjs-turbopack-canary-node141019
✅ nextjs-turbopack-canary-quickjs141019
✅ nextjs-turbopack-stable-node16000
✅ nextjs-turbopack-stable-quickjs16000
✅ nextjs-webpack-canary-node141019
✅ nextjs-webpack-canary-quickjs141019
✅ nextjs-webpack-stable-node16000
✅ nextjs-webpack-stable-quickjs16000
✅ nitro-stable-node134026
✅ nitro-stable-quickjs134026
✅ nuxt-stable-node134026
✅ nuxt-stable-quickjs134026
✅ sveltekit-stable-node15307
✅ sveltekit-stable-quickjs15307
✅ tanstack-start-node134026
✅ tanstack-start-quickjs134026
✅ vite-stable-node134026
✅ vite-stable-quickjs134026

✅ 🪟 Windows

AppPassedFailedSkipped
✅ nextjs-turbopack-node16000
✅ nextjs-turbopack-quickjs16000

❌ 🌐 Cross-language Conformance

AppPassedFailedSkipped
❌ python09132

✅ vercel-http-transport

AppPassedFailedSkipped
✅ example132028
✅ express132028
✅ hono132028
✅ nextjs-turbopack15703
✅ nitro132028
✅ vite132028

✅ vercel-multi-region

AppPassedFailedSkipped
✅ nextjs-turbopack2700

✅ vercel-ws-transport

AppPassedFailedSkipped
✅ example132028
✅ express132028
✅ nextjs-turbopack15703
✅ vite132028

📋 View full workflow run

#3779 fixed the app migration skill, whose description ended with
`mode: 'client'`. The colon-space made the plain scalar parse as a nested
mapping, and the skills CLI dropped the file: `Found 5 skills`, and
`--skill migrating-workflow-v4-to-v5` answered `No matching skills
found`, which is the command whats-new.mdx tells readers to run.
The World skill's description has no colon-space today, so it parses.
It is also 590 characters of backticked identifiers, and any future
edit naming a field with its value reintroduces the break. Fold it the
same way now, while the value is known good. Verified with the yaml
package that the folded scalar is byte-identical, and with
`skills add . --skill migrating-world-v4-to-v5` that the CLI still
finds all six.
Signed-off-by: Peter Wielander <peter.wielander@vercel.com>
@github-actions

Copy link
Copy Markdown
Contributor
FrameworkFlow routeStep reg.Framework output
hono200.9 KiB (±0)40.5 KiB (±0)1.76 MiB (±0)
nextjs-turbopack206.3 KiB (±0)439 B (±0)762.8 KiB (±0)
About these numbers

Sizes are gzip; parentheses show the change against main.
Flow route and Step reg. gate this job, on raw bytes rather than the gzip shown, at max(2%, 50.0 KiB). Framework output is informational.

8d9081b · run

Sign up for freeto 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.

1 participant

@VaguelySerious
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); [docs] Make v5 the default documentation version by VaguelySerious · Pull Request #3714 · vercel/workflow · GitHub
Skip to content

[docs] Make v5 the default documentation version - #3714

Open
VaguelySerious wants to merge 5 commits into
mainfrom
peter/docs-v5-default
Open

[docs] Make v5 the default documentation version#3714
VaguelySerious wants to merge 5 commits into
mainfrom
peter/docs-v5-default

Conversation

@VaguelySerious

@VaguelySeriousVaguelySerious commented Aug 21, 2026

Copy link
Copy Markdown
Member

Makes v5 the default documentation version for the 5.0.0 GA, and catches the v5 content up with everything that landed on main since the v5 docs were last refreshed. Companion to #3090 (exit changeset pre mode) and #3091 (pin 4.x publishes to previous).

Version flip and routing

content/docs/v5 and content/worlds/v5 now serve unprefixed — /docs, /worlds, /cookbook — and v4 moves under a /v4 prefix. The versioned source config drives both route trees (the root tree always renders versionedSources.current), so this is a routePrefix move plus source re-binding, not a restructure. The only file moves are app/[lang]/v5/**app/[lang]/v4/**.

  • Version switcher: labels are v5 (Latest) / v4 (Maintenance); current: 'v5'.
  • Banner: pre-release-banner.tsxmaintenance-banner.tsx. v4 pages carry an amber notice (with dark-mode styling) whose "Go to Workflow 5 (Latest)" link deep-links to the same page on the current version; v4-only pages land on the nearest section index via the fallback redirects. v4 pages keep robots: noindex, follow.
  • Redirects (docs/next.config.ts): /v5/* → unprefixed equivalent (permanent; bare /v5 gets its own rule because :path* expands to an empty Location otherwise). The world-docs and api-reference restructure rules are mirrored onto /v4/docs/*, and every page that exists in only one tree has a version-switcher fallback (verified by diffing the two content trees).
  • Worlds routes: both the unprefixed and /v4 worlds routes pass an explicit version into the shared page components, whose semantics flipped with the switch — smoke checks (assertWorldVersionMarkers, assertServesDirectly('/worlds/turso')) now guard the pairing so the canonical /worlds/* pages can't silently serve the maintenance version or self-redirect-loop again.
  • Link lint (docs/scripts/lint.ts): the two-space model swaps with the URL space; redirect destinations resolve against the real HTTP space since redirects are matched before render-time href rewriting.
  • Intentional oddity: rewriteHrefForVersion pulls unprefixed hrefs on v4 pages into the /v4 view, so a /v5/... href is the only way for v4 content to point at a current page. Three such links are kept deliberately; the lint models this.

What moves with the flip

  • whats-new enters the v5 sidebar, first in the tree. [docs] v5 GA content: What's new, World upgrade guide, migration skills #3100 adds the page but leaves it out of content/docs/v5/meta.json, so until this lands it is reachable only by URL.
  • upgrading-to-v5 moves from app/[lang]/v5/worlds/ to app/[lang]/worlds/, following the rest of the v5 worlds routes.
  • Two cross-version links become expressible and are restored. While v4 is the unprefixed version, a v5 page cannot link to a v4 page at all: an unprefixed href on a v5 page is rewritten into the /v5 view. [docs] v5 GA content: What's new, World upgrade guide, migration skills #3100 therefore phrases both as pointers to the version picker. Here they go back to being links — the v4 docs entry point in the What's new callout, and the v4 version of the code-transform page.
  • editPath on the unprefixed docs route points at docs/content/docs/v5/{path}.

Catch-up with main

Swept the 53 commits that landed since the last content refresh, and added what the docs were missing. Most changesets in that window are fixes, internal, or already documented by their own PR; three things were not.

Spec 7, the sealed log (#3634, not merged, default for v5). Positions are handed out ahead of the commit instead of being claimed by the write that fills them, so concurrent writers never contend and a wide fan-out stops serializing. The cost is a position whose writer dies, which the backend closes with a noop event that replay steps over without delivering it and without advancing the deterministic clock.

  • upgrading-to-v5 › Spec versions is rewritten around mintedSpecVersion(). The accepted range widens back to two versions, because a deployment with WORKFLOW_SEALED_LOG=0 stamps the one below, and that makes both SPEC_VERSION_CURRENT and SPEC_VERSION_SUPPORTS_SLOT_IDENTITY literals by another name for declaring it — neither follows the setting. This replaces what [docs] v5 GA content: What's new, World upgrade guide, migration skills #3100 said for spec 6, which was that exactly one version is accepted.
  • A new "Sealed logs and noop events" subsection says what this costs an implementer, which for most is nothing: a World allocating each position at the commit cannot leave a hole, so it never seals and never emits a noop. The obligation belongs to a World that pre-assigns positions; the half that binds everyone is the reader's.
  • WORKFLOW_SEALED_LOG is documented in runtime-tuning, taken verbatim from Add support for 'noop' event type - spec version 7 #3634 so whichever lands second is a no-op merge. The deep reference sections that PR writes — in event-sourcing and the World allocation contract — are left to it, so this does not duplicate them.
  • The migration skill (v0.2.0) gets the same treatment, phrased as findings to report rather than edits to make.

events.createBatch (#3025). An optional World method appending an ordered list of events in one durable write with per-event outcomes. It was documented only as a changelog page and an env var, so the World reference had no mention of a method a World author has to decide about. Added to the interface snippet, to the Key Implementation Details as a contract note (atomicity per attempt, what a World must reject, the one legal same-entity pair), to the upgrade guide's optional surface, and to the skill.

runs.waitForTerminalStatus (#3570). Also missing from the upgrade guide and the skill. It is what makes await run.returnValue a long poll rather than an interval, which is user-facing, so What's new gets that as an entry.

What's new also gains the batched suspension write and the positions change under faster-and-cheaper runs, where they belong: neither has any API surface.

Not addressed.workflow.step.execute.duration, the OpenTelemetry histogram from #3526, has nowhere to go — the docs carry no metrics reference at all, and inventing one for a single metric is a bigger call than this sweep. Flagging rather than guessing.

Second catch-up: the WebSocket default and spec 7

Merged main again (13 commits). Four conflicts, all against #3704's writing-standards pass over the whole corpus, which rewrote the same paragraphs this branch had edited. Took main's normalized text wherever the difference was purely style, kept this branch's meaning where the two disagreed (the spec-7 paragraph main still had at spec 6, the /v4/... link the flip makes expressible, the batch-write contract note), and restyled this branch's own additions so no prose em dashes come back with it.

The WebSocket events transport is the default now.#3702 flipped it and updated worlds.mdx, vercel.mdx and runtime-tuning.mdx, but What's new still said "an opt-in WebSocket transport ... HTTP remains the default", which was the most wrong sentence left in the v5 docs. It now says what happens, that only the exact value http opts out so a typo fails toward the socket, and that tracing is unchanged because the client span is synthesized around the frame.

Spec 7 is settled.#3634 landed, then #3735 made the sealed log opt-in, then #3737 re-enabled it. The end state matches what this branch already documented, and the WORKFLOW_SEALED_LOG section I had taken verbatim merged as the no-op it was meant to be, modulo #3704's restyling. mintedSpecVersion(), the two-version accepted range, and the "if you allocate at the commit you are already compliant" framing all still hold.

Three World-developer notes, all from #3728. These are the ones a custom World cannot discover from its type errors:

  • Process-wide state has to live on globalThis. A module's top-level const/let is one instance per module instance, and a bundler compiles one copy per layer. The runtime caches the World object process-wide while module state it closes over stays layer-local, so anything a World reaches at request time has to be process-wide too. New contract note in the upgrade guide, plus a step of its own in the World skill (v0.3.0) with an intake item, a globalSingleton() example including what the shape version is for, an output-shape section, and a failure-checklist line. Documented by its casualty: the WS transport registered its channel in the route layer's registry and the write path read the instrumentation layer's empty one, so every event fell back to HTTP for the life of the process, with nothing logged and no test failing.
  • One World per process. The entrypoint's queue handler is built from getWorld() instead of getWorldHandlers(), so a stateful World stops getting duplicate connection pools and queue workers. The build-integration row that still pointed custom hosts at getWorldHandlers() is corrected: that export is the build-time view, not how a request-time handler is assembled.
  • A World's transport is its own business, except for the tracing. How a World ships events is unconstrained. What is constrained is that a non-HTTP transport still owes the per-event client span an HTTP write would emit, or the per-event view of a run silently disappears. Points at the Vercel World's span shape as the worked example.

Nothing needed for the remaining commits in the window: globalSingleton's own changeset and the sideEffects: false declaration are internal, the wait-continuation re-arm and the atomic step_created commit are fixes to behavior already documented, and the decrypt-control and trace-name changes are dashboard-side.

Verification

Link lint passes with 0 errors. pnpm build compiles, with /en/docs/whats-new prerendered under the unprefixed route, /[lang]/v4/docs/[[...slug]] serving the maintenance tree, and ƒ /[lang]/worlds/upgrading-to-v5.

Docs Preview

Links will be added from the workflow-docs preview once it deploys.

🤖 Generated with Claude Code

@vercel

vercelBot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated (UTC)
example-nextjs-workflow-turbopackReadyReadyPreview, v0Aug 25, 2026 8:40pm
example-nextjs-workflow-webpackReadyReadyPreview, v0Aug 25, 2026 8:40pm
example-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-astro-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-express-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-fastify-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-hono-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-nestjs-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-nitro-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-nuxt-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-python-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-sveltekit-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-tanstack-start-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workbench-vite-workflowReadyReadyPreview, v0Aug 25, 2026 8:40pm
workflow-docsReadyReadyPreview, v0Aug 25, 2026 8:40pm
workflow-swc-playgroundBuildingBuildingPreview, v0Aug 25, 2026 8:40pm
workflow-tarballsReadyReadyPreview, v0Aug 25, 2026 8:40pm
workflow-webReadyReadyPreview, v0Aug 25, 2026 8:40pm

@changeset-bot

changeset-botBot commented Aug 21, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 8d9081b

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 0 packages

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions

github-actionsBot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Sim World

Simulated world deterministic testing for races. Traces

🟠 world-sim scenario book — 1 fail of 41 total

fence=per-spec

scenariooutcomeeventsvirtreplayviolations
smoke-no-stepscompleted30msok0
smoke-one-stepcompleted60msok0
hook-at-step-startedcompleted120msok0
hook-at-step-completedcompleted120msok0
hook-at-hook-createdcompleted120msok0
deadline-hook-winscompleted71.0hok0
deadline-expirescompleted71.0hok0
long-sleepcompleted1130.0dok0
hook-never-arrivesstalled30msskipped0
step-retries-twicecompleted102.0sok0
parallel-stepscompleted90msok0
hook-on-execution-statecompleted120msok0
peek-hook-before-branchcompleted120msok0
peek-hook-after-branchcompleted120msok0
peek-hook-at-registrationcompleted120msok0
race-hook-before-probecompleted120msok0
race-hook-after-probecompleted120msok0
race-duplicate-deliverycompleted130msok0
attr-hook-before-stepcompleted110msok0
attr-hook-after-stepcompleted110msok0
attr-from-step-bodycompleted130msok0
fork-hook-after-timeoutcompleted141.0mok0
fork-hook-before-timeoutcompleted141.0mok0
count-hook-after-timeoutcompleted171.0mok0
count-hook-before-timeoutcompleted201.0mok0
stale-read-step-count-forkcompleted201.0mok0
stale-read-equal-step-countscompleted141.0mok0
step-vs-step-forkcompleted120msok0
step-vs-step-fork-fencedcompleted120msok0
fence-catches-benign-directioncompleted125msok0
in-flight-before-decisioncompleted171.0mok0
in-flight-before-decision-countedcompleted171.0mok0
in-flight-after-decisioncompleted192.0mok0
stale-read-step-count-fork-fencedcompleted201.0mok0
fork-hook-winscompleted131.0mok0
fork-timeout-winscompleted131.0mok0
unclaimed-payload-under-forkcompleted171.0mok0
claimed-payload-under-forkcompleted171.0mok0
writers-independent-step-bodiescompleted120msok0
writers-scripted-tempocompleted120msok0
cancel-mid-stepcancelled70msskipped0

Full trace: world-sim.txt

VaguelySeriousand others added 2 commits August 21, 2026 12:50
Serves `content/docs/v5` and `content/worlds/v5` unprefixed at /docs,
/worlds and /cookbook, moves v4 under /v4, and puts What's new first in
the v5 sidebar.
The versioned source config drives both route trees (the root tree always
renders `versionedSources.current`), so this is a `routePrefix` move plus
source re-binding rather than a restructure. The only file moves are
`app/[lang]/v5/**` → `app/[lang]/v4/**`.
- Version switcher: `v5 (Latest)` / `v4 (Maintenance)`, `current: 'v5'`.
- `pre-release-banner.tsx` becomes `maintenance-banner.tsx`. v4 pages
carry an amber notice whose "Go to Workflow 5 (Latest)" link deep-links
to the same page on the current version, falling back to the nearest
section index for v4-only pages, and keep `robots: noindex, follow`.
- Redirects: `/v5/*` to the unprefixed equivalent (bare `/v5` needs its
own rule, since `:path*` expands to an empty Location). The world-docs
and api-reference restructure rules are mirrored onto `/v4/docs/*`, and
every page existing in only one tree gets a version-switcher fallback.
- Both worlds route trees pass an explicit version into the shared page
components, whose semantics flipped with the switch, so the smoke checks
now assert the pairing: a " · v4" title marker and noindex on the
maintenance routes, neither on the canonical ones, and a community world
serving directly rather than self-redirecting.
- The link lint's two URL spaces swap with the prefixes. Redirect
destinations resolve against the real HTTP space, since redirects are
matched before render-time href rewriting.
- The two `/v4/...` links this makes expressible are restored: a v5 page
cannot link to a v4 page while v4 is the unprefixed version.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sweep of everything that landed on main since the last content refresh,
plus the spec-7 sealed log from #3634, which is not merged but is the
default for v5.
Spec 7 changes what a World declares, so the upgrade guide's Spec
versions section is rewritten around `mintedSpecVersion()`. The accepted
range widens back to two versions, because a deployment with
`WORKFLOW_SEALED_LOG=0` stamps the one below, and both `SPEC_VERSION_CURRENT`
and `SPEC_VERSION_SUPPORTS_SLOT_IDENTITY` become literals by another name
for the purpose of declaring it: neither follows the setting. The new
section says what a sealed log costs an implementer, which for most is
nothing — a World allocating each position at the commit cannot leave a
hole, so it never seals and never writes a `noop`. The obligation belongs
to a World that pre-assigns positions, and the half that binds everyone
is the reader's.
`WORKFLOW_SEALED_LOG` is documented in runtime-tuning, taken verbatim
from #3634 so whichever lands second is a no-op merge. The deep
reference sections that PR writes, in event-sourcing and the World
allocation contract, are left to it.
Two optional World members shipped after the guide was written and were
missing everywhere:
- `events.createBatch` — in the World reference (interface and contract
note), the upgrade guide's optional surface, and the skill. Implementing
it is the declaration, so the note leads with atomicity per attempt and
what a World must reject.
- `runs.waitForTerminalStatus` — same three places. It is also what makes
`await run.returnValue` a long poll rather than an interval, which is
user-facing, so What's new gets it too.
What's new also gains the batched suspension write and the pre-assigned
positions behind it, both under faster-and-cheaper runs where they belong:
neither has any API surface.
Not addressed: `workflow.step.execute.duration`, the OpenTelemetry
histogram added in #3526, has nowhere to go. The docs have no metrics
reference at all, and inventing one for a single metric is a bigger call
than this sweep.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@github-actions

github-actionsBot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

🧪 E2E Test Results

Some tests failed

❌ Failed E2E Tests

▲ Vercel Production (8 failed)

python-node (8 failed):

  • promiseAllWorkflow | wrun_41M0XAGXS00GK4H9P4BRDADZPF | 🔍 observability
  • sleepingWorkflow | wrun_41M0XAHK4C0GN8PMSN1G5MJ54R | 🔍 observability
  • parallelSleepWorkflow | wrun_41M0XAHKR70GX6C8R38YRX9JZR | 🔍 observability
  • nullByteWorkflow | wrun_41M0XAHTBJ0GPJDS4V1JB075V8 | 🔍 observability
  • cancelRun - cancelling a running workflow | wrun_41M0XAPE6F0GWZ7WFMJS2WQSZ7 | 🔍 observability
  • cancelRun via CLI - cancelling a running workflow | wrun_41M0XAPJ5Y0GVZ8EPNJZZFBXBN | 🔍 observability
  • sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration | wrun_41M0XAPTHD0GRRQPJZEA3CS0X9 | 🔍 observability
  • resilient start: addTenWorkflow completes when run_created returns 500 | wrun_41M0XAQ8AD0GG3DEEMY8R682VV | 🔍 observability

🌐 Cross-language Conformance (9 failed)

python (9 failed):

  • deploymentId: 'latest' is a no-op in non-Vercel worlds | wrun_01M0XASD1GCVQ8X0DC4TD9QQ8K
  • promiseAllWorkflow | wrun_41M0XAGXS00GK4H9P4BRDADZPF
  • sleepingWorkflow | wrun_41M0XAHK4C0GN8PMSN1G5MJ54R
  • parallelSleepWorkflow | wrun_41M0XAHKR70GX6C8R38YRX9JZR
  • nullByteWorkflow | wrun_41M0XAHTBJ0GPJDS4V1JB075V8
  • cancelRun - cancelling a running workflow | wrun_41M0XAPE6F0GWZ7WFMJS2WQSZ7
  • cancelRun via CLI - cancelling a running workflow | wrun_41M0XAPJ5Y0GVZ8EPNJZZFBXBN
  • sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration | wrun_41M0XAPTHD0GRRQPJZEA3CS0X9
  • resilient start: addTenWorkflow completes when run_created returns 500 | wrun_41M0XAQ8AD0GG3DEEMY8R682VV

⚠️ Flaky E2E Tests (passed on retry)

These tests failed at least once and passed on a retry. A recurring entry here is a real race worth investigating.

  • addTenWorkflow (express)
  • cancelRun via CLI - cancelling a running workflow (nextjs-turbopack)
  • hookWithSleepWorkflow - hook payloads delivered correctly with concurrent sleep (nextjs-webpack)
  • promiseAllWorkflow (nuxt)
  • RetryableError respects custom retryAfter delay (nitro)

🛠 Infra Events (absorbed by the harness)

Platform anomalies the e2e harness detected and worked around (e.g. a run the queue never picked up, replaced by a fresh run). Clustered timestamps indicate a backend blip; a steady drip indicates a platform issue worth escalating.

35 infra events
  • cold-start-warmup · suite warmup (python) · at 20:42:37Z · abandoned wrun_41M0XAEJYH0GKQ4W94H3ETH1ZY · (+7 more)
  • run-pickup-stall · nullByteWorkflow (python) · at 20:42:53Z · abandoned wrun_41M0XAJ7Y50GK8N5JNCV12GV8E
  • run-pickup-stall · parallelSleepWorkflow (python) · at 20:42:53Z · abandoned wrun_41M0XAJ7Y20GSX8SWCTH5RVR9M
  • run-pickup-stall · promiseAllWorkflow (python) · at 20:42:53Z · abandoned wrun_41M0XAJ7XV0GG32EEKFRD3B8FS
  • run-pickup-stall · sleepingWorkflow (python) · at 20:42:54Z · abandoned wrun_41M0XAJ7Y20GSX8SWCTH5RVR9K
  • run-pickup-stall · cancelRun - cancelling a running workflow (python) · at 20:42:54Z · abandoned wrun_41M0XAJ8BJ0GJZX1BNBA4CH8W8
  • run-pickup-stall · cancelRun - cancelling a running workflow (python) · at 20:43:27Z · abandoned wrun_41M0XAK8KD0GGARJ5E9EAKDQA7
  • run-pickup-stall · parallelSleepWorkflow (python) · at 20:43:54Z · abandoned wrun_41M0XAM3J00GNDEKT3M4EV9A3B
  • run-pickup-stall · nullByteWorkflow (python) · at 20:43:54Z · abandoned wrun_41M0XAM3J50GY1Z4PYVB875JW2
  • run-pickup-stall · sleepingWorkflow (python) · at 20:43:55Z · abandoned wrun_41M0XAM3NR0GMY2WC43XC9WEEG
  • run-pickup-stall · promiseAllWorkflow (python) · at 20:43:55Z · abandoned wrun_41M0XAM3PT0GKQPBP2CXFAYS50
  • cold-start-warmup · suite warmup (tanstack-start) · at 20:44:26Z · abandoned wrun_01M0XAMQCG384J98J2DSD14DR1
  • run-pickup-stall · cancelRun via CLI - cancelling a running workflow (python) · at 20:44:45Z · abandoned wrun_41M0XAM8FN0GV4BFNTQPWFKM5X
  • cold-start-warmup · suite warmup (python) · at 20:45:16Z · abandoned wrun_01M0XAKEM09ZDGG4DKY24BNT4R · (+7 more)
  • run-pickup-stall · deploymentId: 'latest' is a no-op in non-Vercel worlds (python) · at 20:45:31Z · abandoned wrun_01M0XAQ3RETMHB830AKZR4WRR3
  • run-pickup-stall · promiseAllWorkflow (python) · at 20:45:31Z · abandoned wrun_01M0XAQ3RF7PEAZN9P8KWR413P
  • run-pickup-stall · parallelSleepWorkflow (python) · at 20:45:31Z · abandoned wrun_01M0XAQ3RP7BN47JKYJVR7W9SN
  • run-pickup-stall · sleepingWorkflow (python) · at 20:45:31Z · abandoned wrun_01M0XAQ3RNB63W8SCJMFB059TD
  • run-pickup-stall · nullByteWorkflow (python) · at 20:45:31Z · abandoned wrun_01M0XAQ3RRZXSHD6R9Y4Q7HMN3
  • run-pickup-stall · cancelRun via CLI - cancelling a running workflow (python) · at 20:46:27Z · abandoned wrun_41M0XAQ0C60GXEJ7JBYYKRXP7W
  • run-pickup-stall · sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration (python) · at 20:46:28Z · abandoned wrun_41M0XAPVEJ0GJSWRFAK9D97ABV
  • run-pickup-stall · deploymentId: 'latest' is a no-op in non-Vercel worlds (python) · at 20:46:31Z · abandoned wrun_01M0XARYC38T4GCYXDEWNVNMX3
  • run-pickup-stall · promiseAllWorkflow (python) · at 20:46:31Z · abandoned wrun_01M0XARYC52C67FSA4N73VC5D7
  • run-pickup-stall · sleepingWorkflow (python) · at 20:46:31Z · abandoned wrun_01M0XARYCDFV9BC8DR74AKYXE5
  • run-pickup-stall · parallelSleepWorkflow (python) · at 20:46:32Z · abandoned wrun_01M0XARYCK0DC47WQPD9BH1JVJ
  • run-pickup-stall · nullByteWorkflow (python) · at 20:46:32Z · abandoned wrun_01M0XARYCM1HBYVNK0S93X5J0W
  • run-pickup-stall · cancelRun - cancelling a running workflow (python) · at 20:47:32Z · abandoned wrun_01M0XATRZQVJRSD3M331XYF0RA
  • run-pickup-stall · cancelRun via CLI - cancelling a running workflow (python) · at 20:47:32Z · abandoned wrun_01M0XATRZZS9C3MF3DY87TKVW5
  • run-pickup-stall · sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration (python) · at 20:47:32Z · abandoned wrun_01M0XATS031XZTYSFHCRKFRY0Z
  • run-pickup-stall · cancelRun - cancelling a running workflow (python) · at 20:48:02Z · abandoned wrun_01M0XAVPAX8XNNRK46QNQJ2XK9
  • run-pickup-stall · cancelRun via CLI - cancelling a running workflow (python) · at 20:48:02Z · abandoned wrun_01M0XAVPBFHXMMMA4YG99N83D1
  • run-pickup-stall · sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration (python) · at 20:48:32Z · abandoned wrun_01M0XAWKK6KJ97YQH5T3M65MQN
  • run-pickup-stall · plainModuleDoneHook resumed via plain API route (o2flow shape) (nextjs-webpack) · at 20:51:44Z · abandoned wrun_01M0XB2FMN0D9JTJB906JH00C2
  • run-pickup-stall · hookWithSleepFinalStepWorkflow - step only on final payload (nextjs-webpack) · at 20:52:05Z · abandoned wrun_01M0XB34HFYH9Y559Y5VFH0QKY
  • run-pickup-stall · sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration (nextjs-webpack) · at 20:52:06Z · abandoned wrun_01M0XB34PXRGGCJBBBPNXBSAQW

E2E Test Summary

Summary
PassedFailedSkippedTotal
❌ ▲ Vercel Production357087424320
✅ 💻 Local Development392205584480
✅ 📦 Local Production392205584480
✅ 🐘 Local Postgres392205584480
✅ 🪟 Windows32000320
❌ 🌐 Cross-language Conformance09132141
✅ vercel-http-transport8170143960
✅ vercel-multi-region270027
✅ vercel-ws-transport553087640
Total1705317277819848
Details by Category

❌ ▲ Vercel Production

AppPassedFailedSkipped
✅ astro-node132028
✅ astro-quickjs132028
✅ example-node132028
✅ example-quickjs132028
✅ express-node132028
✅ express-quickjs132028
✅ fastify-node132028
✅ fastify-quickjs132028
✅ hono-node132028
✅ hono-quickjs132028
✅ nest-node132028
✅ nest-quickjs132028
✅ nextjs-turbopack-node15703
✅ nextjs-turbopack-quickjs15703
✅ nextjs-webpack-node15703
✅ nextjs-webpack-quickjs15703
✅ nitro-node132028
✅ nitro-quickjs132028
✅ nuxt-node132028
✅ nuxt-quickjs132028
❌ python-node08152
✅ sveltekit-node15109
✅ sveltekit-quickjs15109
✅ tanstack-start-node132028
✅ tanstack-start-quickjs132028
✅ vite-node132028
✅ vite-quickjs132028

✅ 💻 Local Development

AppPassedFailedSkipped
✅ astro-stable-node134026
✅ astro-stable-quickjs134026
✅ express-stable-node134026
✅ express-stable-quickjs134026
✅ fastify-stable-node134026
✅ fastify-stable-quickjs134026
✅ hono-stable-node134026
✅ hono-stable-quickjs134026
✅ nest-stable-node134026
✅ nest-stable-quickjs134026
✅ nextjs-turbopack-canary-node141019
✅ nextjs-turbopack-canary-quickjs141019
✅ nextjs-turbopack-stable-node16000
✅ nextjs-turbopack-stable-quickjs16000
✅ nextjs-webpack-canary-node141019
✅ nextjs-webpack-canary-quickjs141019
✅ nextjs-webpack-stable-node16000
✅ nextjs-webpack-stable-quickjs16000
✅ nitro-stable-node134026
✅ nitro-stable-quickjs134026
✅ nuxt-stable-node134026
✅ nuxt-stable-quickjs134026
✅ sveltekit-stable-node15307
✅ sveltekit-stable-quickjs15307
✅ tanstack-start-node134026
✅ tanstack-start-quickjs134026
✅ vite-stable-node134026
✅ vite-stable-quickjs134026

✅ 📦 Local Production

AppPassedFailedSkipped
✅ astro-stable-node134026
✅ astro-stable-quickjs134026
✅ express-stable-node134026
✅ express-stable-quickjs134026
✅ fastify-stable-node134026
✅ fastify-stable-quickjs134026
✅ hono-stable-node134026
✅ hono-stable-quickjs134026
✅ nest-stable-node134026
✅ nest-stable-quickjs134026
✅ nextjs-turbopack-canary-node141019
✅ nextjs-turbopack-canary-quickjs141019
✅ nextjs-turbopack-stable-node16000
✅ nextjs-turbopack-stable-quickjs16000
✅ nextjs-webpack-canary-node141019
✅ nextjs-webpack-canary-quickjs141019
✅ nextjs-webpack-stable-node16000
✅ nextjs-webpack-stable-quickjs16000
✅ nitro-stable-node134026
✅ nitro-stable-quickjs134026
✅ nuxt-stable-node134026
✅ nuxt-stable-quickjs134026
✅ sveltekit-stable-node15307
✅ sveltekit-stable-quickjs15307
✅ tanstack-start-node134026
✅ tanstack-start-quickjs134026
✅ vite-stable-node134026
✅ vite-stable-quickjs134026

✅ 🐘 Local Postgres

AppPassedFailedSkipped
✅ astro-stable-node134026
✅ astro-stable-quickjs134026
✅ express-stable-node134026
✅ express-stable-quickjs134026
✅ fastify-stable-node134026
✅ fastify-stable-quickjs134026
✅ hono-stable-node134026
✅ hono-stable-quickjs134026
✅ nest-stable-node134026
✅ nest-stable-quickjs134026
✅ nextjs-turbopack-canary-node141019
✅ nextjs-turbopack-canary-quickjs141019
✅ nextjs-turbopack-stable-node16000
✅ nextjs-turbopack-stable-quickjs16000
✅ nextjs-webpack-canary-node141019
✅ nextjs-webpack-canary-quickjs141019
✅ nextjs-webpack-stable-node16000
✅ nextjs-webpack-stable-quickjs16000
✅ nitro-stable-node134026
✅ nitro-stable-quickjs134026
✅ nuxt-stable-node134026
✅ nuxt-stable-quickjs134026
✅ sveltekit-stable-node15307
✅ sveltekit-stable-quickjs15307
✅ tanstack-start-node134026
✅ tanstack-start-quickjs134026
✅ vite-stable-node134026
✅ vite-stable-quickjs134026

✅ 🪟 Windows

AppPassedFailedSkipped
✅ nextjs-turbopack-node16000
✅ nextjs-turbopack-quickjs16000

❌ 🌐 Cross-language Conformance

AppPassedFailedSkipped
❌ python09132

✅ vercel-http-transport

AppPassedFailedSkipped
✅ example132028
✅ express132028
✅ hono132028
✅ nextjs-turbopack15703
✅ nitro132028
✅ vite132028

✅ vercel-multi-region

AppPassedFailedSkipped
✅ nextjs-turbopack2700

✅ vercel-ws-transport

AppPassedFailedSkipped
✅ example132028
✅ express132028
✅ nextjs-turbopack15703
✅ vite132028

📋 View full workflow run

#3779 fixed the app migration skill, whose description ended with
`mode: 'client'`. The colon-space made the plain scalar parse as a nested
mapping, and the skills CLI dropped the file: `Found 5 skills`, and
`--skill migrating-workflow-v4-to-v5` answered `No matching skills
found`, which is the command whats-new.mdx tells readers to run.
The World skill's description has no colon-space today, so it parses.
It is also 590 characters of backticked identifiers, and any future
edit naming a field with its value reintroduces the break. Fold it the
same way now, while the value is known good. Verified with the yaml
package that the folded scalar is byte-identical, and with
`skills add . --skill migrating-world-v4-to-v5` that the CLI still
finds all six.
Signed-off-by: Peter Wielander <peter.wielander@vercel.com>
@github-actions

Copy link
Copy Markdown
Contributor
FrameworkFlow routeStep reg.Framework output
hono200.9 KiB (±0)40.5 KiB (±0)1.76 MiB (±0)
nextjs-turbopack206.3 KiB (±0)439 B (±0)762.8 KiB (±0)
About these numbers

Sizes are gzip; parentheses show the change against main.
Flow route and Step reg. gate this job, on raw bytes rather than the gzip shown, at max(2%, 50.0 KiB). Framework output is informational.

8d9081b · run

Sign up for freeto 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.

1 participant

@VaguelySerious