Repository navigation
[docs] Make v5 the default documentation version - #4498
Conversation
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>
Resolves 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 everywhere it 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, and the batch-write contract note. Restyled this branch's own additions to the standard main just adopted, so no prose em dashes come back with it. Content this landed on top: - **The WebSocket events transport is the default now**, not opt-in. The What's new entry said the opposite, which was the most wrong sentence in the v5 docs after #3702. - **Process-wide state has to live on `globalThis`.** New contract note in the World upgrade guide, and a step of its own in the World skill, since it type-checks, passes tests in isolation, and fails only in a host that bundles the World. Named after its casualty: the WS transport registered its channel in one bundler layer and looked it up in another layer's empty copy, so every event fell back to HTTP silently. - **One World per process.** The entrypoint's queue handler is built from `getWorld()` rather than `getWorldHandlers()`, so a stateful World stops getting duplicate pools and queue workers. The build-integration row that still sent custom hosts to `getWorldHandlers()` is corrected. - **A World's transport is its own business, except for the tracing.** A non-HTTP transport still owes the per-event client span, or the per-event view of a run disappears. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
#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>
…ics deltas Docs and migration skills pass over main since the last update: - errors-and-retries: STREAM_ERROR and DEPLOYMENT_MISMATCH rows, completing the RUN_ERROR_CODES table. - world/storage: runs.list status array form, TERMINAL_WORKFLOW_RUN_STATUSES, empty-array semantics and the per-World split. - building-a-world: terminal-run start fence, runContext on WorkflowInvokePayload, analytics.events.getMany plus page limits, streams.createWriteSession. - migrating-world-v4-to-v5: the same contract additions, plus checklist items. - migrating-workflow-v4-to-v5: analytics.events.listByCorrelationId is deprecated; the storage method of the same name is not.
…ow refs Four follow-ups to the Workflow 5 Vitest path: - Document that a v5 app has to install `@workflow/vitest@beta`, since `@workflow/vitest@latest` is still the 4.x line. - Fail the test build up front when `@workflow/vitest` and the app resolve incompatible `@workflow/core` majors, with the install command that fixes it. Same-major differences warn. `WORKFLOW_VITEST_VERSION_CHECK=off` skips the check. - Write the builder's `manifest.json` next to the test bundles and add `getWorkflowRef()` / `listWorkflowRefs()`, so a test can name a workflow instead of hand-writing the generated `workflow//...` id. - Rewrite the mocking docs to match what `vi.mock()` actually reaches, and pin each case in the workbench. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Co-Authored-By: Peter Wielander <29887157+VaguelySerious@users.noreply.github.com>
#4206 landed a longer cell for `params.status` on main while this branch carried its own. Adopt main's, so the merge that follows is a fast, conflict-free catch-up. Co-Authored-By: Peter Wielander <29887157+VaguelySerious@users.noreply.github.com>
… pages Stacked on #4267, which documents `npm i -D @workflow/vitest@beta`. That is right while 5.x only exists on the `beta` tag, and wrong the moment this PR's premise holds: `latest` becomes 5.x (#3090) and the 4.x line moves to `previous` (#3091). So the install guidance goes back to a plain `npm i -D @workflow/vitest` in the testing guide, the @workflow/vitest API reference, and the workflow skill. What survives from #4267's callout is the reason it was written: the plugin carries its own @workflow/core and has to stay on the app's major, which the plugin now checks at the start of each run. The runtime hint in packages/vitest/src/version-check.ts still points a v5 app at `@beta`. It is correct until 5.0.0 is published and should flip with the release, not here. Also refreshes the version-switcher fallbacks against the current content trees. Seven v5-only pages had no /v4 landing spot: the lifecycle-hooks pair that just landed on main, three changelog entries, the run-expired error, and observability/retention. Co-Authored-By: Peter Wielander <29887157+VaguelySerious@users.noreply.github.com>
The switcher dropdown resolves a missing page against getVersionSwitchPaths(); the maintenance banner's prefix swap and inbound /v4 URLs do not. Those are what the block catches. Co-Authored-By: Peter Wielander <29887157+VaguelySerious@users.noreply.github.com>
Union-resolve the v5 docs conflicts: keep main's newer capability list, resolveData contract note and DEPLOYMENT_MISMATCH wording, keep this branch's world process-state guidance and the two added optional-surface rows, and keep the GA install lines (no `@beta`) that are this branch's whole point. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
#4267 merged to main and its Version Packages run moved this file into .changeset/pre/. Keeping the pending copy here would bump the packages a second time for a change that already shipped. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ding Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
🦋 Changeset detectedLatest commit: 482fcad The changes in this PR will be included in the next version bump. This PR includes changesets to release 0 packagesWhen 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 |
🧪 E2E Test Results✅ All tests passed 🛠 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.
E2E Test SummarySummary
Details by Category✅ ▲ Vercel Production
✅ 💻 Local Development
✅ 📦 Local Production
✅ 🐘 Local Postgres
✅ 🪟 Windows
✅ 🌐 Cross-language Conformance
✅ dynamic-runs
✅ vercel-http-transport
✅ vercel-multi-region
✅ vercel-ws-transport
|
📊 Workflow Benchmarkscommit Backend:
Streams
📈 STSO distribution vs main (inline / queue-hop histograms)1020 steps (inline) Cumulative STSO time: main 226997ms → this run 205629ms (Δ -21368ms, -9%) 📈 CRTT drill-down vs main (RTT distributions & profiles)RTT over stream progress (avg per tenth of stream, bars scaled min→max): RTT by chunk size (avg per log size bin, ~160B → ~12KB serialized, bars scaled min→max): Delivery jitter over stream progress (avg positive CDV per tenth of stream, bars scaled min→max): ℹ️ Metric definitions & methodologyStreams: first-chunk RTT (the stream-open path, before any buffering/backpressure), CRTT percentiles, and worst delivery stall (CDV max). Cells are medians across iterations; per-run values in the artifacts. No 🔴/🟢 marks until targets attach. The collapsed STSO distribution section above buckets every step gap, split inline (same warm process — pure framework overhead) vs queue-hop (fresh process — dispatch, reinit, replay). The collapsed CRTT drill-down: per-variant RTT histograms (fixed log bins, Best/P75/P90/P99 deltas compare against the most recent benchmark run on Metrics — TTFS: time to first step body (in-deployment start() → first step body) · Fan-out TTFS: fan-out time to first step (in-deployment start() → first of the parallel step bodies to complete) · Fan-out TTLS: fan-out time to last step (in-deployment start() → last of the parallel step bodies to complete, i.e. when the Promise.all resolves) · STSO: step-to-step overhead (gap between consecutive step bodies) · WO: workflow overhead (whole-run time outside step bodies, in-deployment anchored) · CRTT: chunk round-trip time (per-chunk write → read latency, one clock domain: deployment → stream backend → same deployment) · CDV: chunk delay variation / delivery jitter (inter-arrival gap minus inter-write gap per seq-adjacent pair; skew-free; the row is each run's MAX positive value, so one stall moves it) Scenarios — step: one trivial no-op step, no stream; no hooks, so the run stays in turbo mode (in-process fast path) · stream: one streaming step; no hooks, so the run stays in turbo mode (in-process fast path) · hook + stream: registers a hook before one step, which exits turbo mode (dispatch path) · 1020 steps: 1020 trivial sequential steps; STSO is measured between consecutive steps in the given step ranges, and WO is the whole-run overhead outside step bodies · Promise.all(100 steps): 100 trivial no-op steps started together in a single Promise.all; Fan-out TTFS is the first of them to complete and Fan-out TTLS the last, both from the in-deployment clientStart, so their gap is the spread the runtime adds across the fan-out · paced control (100/s, 60B): the control: 300 tiny (~60B) deltas metronome-paced at 100/s — zero workload structure, so it reads the transport floor and flush cadence, and disambiguates transport-wide vs workload-specific when a replay row moves · size sweep (100/s, 160B-12KB): same pacing as the control with deltas padded in rotation across seven log-spaced sizes (~160B–12KB) — rotation decouples size from stream position, so it isolates whether chunk size causes latency · replay gateway-gpt-5.4-nano-2000t (1x): raw provider SSE cadence captured at the AI gateway boundary (gpt-5.4-nano, the most popular gateway model; per-token deltas p50 208B = the modal production chunk size), replayed exactly as measured — the typical customer's workload; its CDV is the typical customer's real delivery jitter · replay eve-gpt-5.6-sol-2000t (1x): a captured eve turn (gpt-5.6-sol, the most-used demanding eve model; ~2000 output tokens = production p50 turn length) replayed exactly as measured — eve's envelope protocol re-ships the cumulative message so sizes ramp 142B→13KB; the demanding outlier tenant's reality · replay eve-gpt-5.6-sol-2000t (2x): the same eve capture at 2x — the headroom/stress row; real fast-tier models emit the same chunk sizes at proportionally higher rate, so time compression is a faithful speed model · first chunk (pooled): every run's seq-0 RTT pooled across all stream scenarios — the first chunk precedes any workload differentiation, so pooling samples one shared stream-open path with exact percentiles Replay cadences (semantic sha256) — eve-gpt-5.6-sol-2000t 🔴 marks a percentile over its target (within target is left unmarked). Targets (p75/p90/p99, ms) — TTFS 200/300/600 All timestamps are deployment-side; runs are triggered in-deployment, so the CI runner and api.vercel.com sit outside every measured window. TTFS = Cold starts stay in the numbers (real bursty-workload latency, inflates P75+); Best is the warm floor. |
Sim WorldSimulated world deterministic testing for races. Traces 🟠 world-sim scenario book — 1 fail of 42 total
Full trace: |
About these numbersSizes are gzip; parentheses show the change against
|
|
No backport to This is a docs-site version flip for the 5.0.0 GA: it makes v5 the default documentation version, moves v4 under a To override, re-run the Backport to stable workflow manually via |
Replaces #3714, which GitHub auto-closed on 2026-09-21 when #4267 merged and deleted the
vitest-v5-follow-upsbranch it had been retargeted onto. Same branch, same content, now based onmain; #3714 cannot be reopened because its base branch is gone.Makes v5 the default documentation version for the 5.0.0 GA, and catches the v5 content up with everything that landed on
mainsince the v5 docs were last refreshed. Companion to #3090 (exit changeset pre mode) and #3091 (pin 4.x publishes toprevious). #4267 has since merged, so its@workflow/vitest@betainstall guidance is taken back tolatesthere rather than in a stack.Version flip and routing
content/docs/v5andcontent/worlds/v5now serve unprefixed —/docs,/worlds,/cookbook— and v4 moves under a/v4prefix. The versioned source config drives both route trees (the root tree always rendersversionedSources.current), so this is aroutePrefixmove plus source re-binding, not a restructure. The only file moves areapp/[lang]/v5/**→app/[lang]/v4/**.v5 (Latest)/v4 (Maintenance);current: 'v5'.pre-release-banner.tsx→maintenance-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 keeprobots: noindex, follow.docs/next.config.ts):/v5/*→ unprefixed equivalent (permanent; bare/v5gets its own rule because:path*expands to an emptyLocationotherwise). 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)./v4worlds 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.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.rewriteHrefForVersionpulls unprefixed hrefs on v4 pages into the/v4view, 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-newenters 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 ofcontent/docs/v5/meta.json, so until this lands it is reachable only by URL.upgrading-to-v5moves fromapp/[lang]/v5/worlds/toapp/[lang]/worlds/, following the rest of the v5 worlds routes./v5view. [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.editPathon the unprefixed docs route points atdocs/content/docs/v5/{path}.Catch-up with
mainSwept 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
noopevent that replay steps over without delivering it and without advancing the deterministic clock.upgrading-to-v5› Spec versions is rewritten aroundmintedSpecVersion(). The accepted range widens back to two versions, because a deployment withWORKFLOW_SEALED_LOG=0stamps the one below, and that makes bothSPEC_VERSION_CURRENTandSPEC_VERSION_SUPPORTS_SLOT_IDENTITYliterals 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.noopevents" 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 anoop. The obligation belongs to a World that pre-assigns positions; the half that binds everyone is the reader's.WORKFLOW_SEALED_LOGis 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 — inevent-sourcingand the World allocation contract — are left to it, so this does not duplicate them.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 makesawait run.returnValuea 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
mainagain (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.mdxandruntime-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 valuehttpopts 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_LOGsection 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:
globalThis. A module's top-levelconst/letis 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, aglobalSingleton()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.getWorld()instead ofgetWorldHandlers(), so a stateful World stops getting duplicate connection pools and queue workers. The build-integration row that still pointed custom hosts atgetWorldHandlers()is corrected: that export is the build-time view, not how a request-time handler is assembled.Nothing needed for the remaining commits in the window:
globalSingleton's own changeset and thesideEffects: falsedeclaration are internal, the wait-continuation re-arm and the atomicstep_createdcommit are fixes to behavior already documented, and the decrypt-control and trace-name changes are dashboard-side.Third catch-up:
mainagain, and the Vitest install tagMerged
mainonce more (21 commits) and stacked this PR on #4267 (vitest-v5-follow-ups), which already carries main's tip, so the merge is both at once. One conflict, inapi-reference/workflow-runtime/world/storage.mdx: #4206 rewrote theruns.listparams.statuscell on main while this branch carried its own. Main's wording is the one kept.Why the stack. #4267 documents
npm i -D @workflow/vitest@beta. That is right while 5.x exists only on thebetatag, and wrong the moment this PR's premise holds — 5.0.0 onlatest(#3090), the 4.x line onprevious(#3091). So the install guidance goes back to a plainnpm i -D @workflow/vitestin the testing guide, the@workflow/vitestAPI reference and the workflow skill, which is what every other install command in the v5 tree looks like. What survives from #4267's callout is the reason it was written: the plugin carries its own@workflow/core, has to stay on the app's major, and now checks that at the start of each run.The runtime hint in
packages/vitest/src/version-check.tsstill points a v5 app at@beta, deliberately. It is correct until 5.0.0 is published, and flipping it (latestfor v5,previousfor 4.x) edits #4267's own code and its tests, so it belongs with the release rather than with a docs PR stacked on top.Version-switcher fallbacks refreshed. Re-diffed the two content trees. Seven v5-only pages had no
/v4rule:api-reference/workflow-api/register-lifecycle-hooksandobservability/lifecycle-hooks(#3678, landed after the last sweep), thebatched-event-writes,lazy-hook-resumeandresilient-resumechangelog entries,errors/run-expired, andobservability/retention. Five of the seven predate the previous sweep, so the list was already out of date when it was written.The comment above the block overstated what it was for, and now says what it is actually load-bearing for. The switcher dropdown does resolve a missing page client-side, against the paths
getVersionSwitchPaths()hands it; what has no such check is the maintenance banner's "Go to Workflow 5" link (a straight prefix swap) and any hand-edited or inbound/v4/...URL. Those are what these rules catch.Nothing else in the window needed prose. The feature work that landed brought its own v5 pages with it — lifecycle hooks (#3678), the optional World
invoke(#4168), the Nest hardening (#3695), the attribute size limit (#4082), the deploy-time system env vars (#4166) — and the rest is tests, fixes, and the dashboard-side cancellation details (#4250). Note that #3090 was reverted onmain(#4195) and will re-land with the GA cut; this PR's premise is unchanged, and its merge order is unchanged with it.Fourth catch-up: back onto
mainMerged
main(56 commits) after #4267 landed. Five conflicts:api-reference/vitest/index.mdx,testing/index.mdx(x2),skills/workflow/SKILL.md(x2): main's@workflow/vitest@betainstall lines against this branch's plainnpm i -D @workflow/vitest. Kept this branch's, which is the premise of the PR. The "same major, checked at the start of each run" reason survives in both.foundations/errors-and-retries.mdx: both sides edited the error-code table. Main had already added its ownDEPLOYMENT_MISMATCHrow, so this branch's duplicate is dropped and main's row keeps its re-routing detail with this branch's link to/docs/errors/deployment-mismatchfolded in.STREAM_ERRORtakes main's phrasing plus this branch's "retry and report with therunId".worlds/v5/upgrading-to-v5.mdx: union. Main'sresolveData: 'skip-step-inputs'contract note and its widercapabilitieslist (hookForceClaim,dynamicWorkflowCode) are kept alongside this branch's process-state guidance and itsevents.createBatch/runs.waitForTerminalStatusrows.Also dropped
.changeset/vitest-refs-and-version-guard.md: #4267's Version Packages run already moved it into.changeset/pre/onmain, so the pending copy this branch carried would have bumped the packages a second time for a change that already shipped. Theworkflowskill goes to1.18for the install-wording change.Merge order is still the open question.
mainis on5.0.0-beta.58withpre.jsonback inpremode, so v5 is not GA yet and this PR should not land before #4362 (re-apply #3090) does. Everything here assumes 5.0.0 onlatestand the 4.x line onprevious.Verification
Link lint passes with 0 errors.
pnpm buildcompiles, with/en/docs/whats-newprerendered under the unprefixed route,/[lang]/v4/docs/[[...slug]]serving the maintenance tree, andƒ /[lang]/worlds/upgrading-to-v5. Both were re-run after the merge with #4267 and the fallback refresh, andbiome checkis clean on the touched files.Docs Preview
Base: https://workflow-docs-git-peter-docs-v5-default.vercel.sh (requires Vercel team access). Every page below is a current-version page, so the unprefixed URL is itself part of what there is to check; the maintenance tree is the same content under
/v4/docs/....docs/content/docs/v5/testing/index.mdx@workflow/vitestwith the SDKdocs/content/docs/v5/api-reference/vitest/index.mdxdocs/content/docs/v5/api-reference/workflow-runtime/world/storage.mdxruns.list()docs/content/docs/v5/whats-new.mdxdocs/content/docs/v5/foundations/errors-and-retries.mdxdocs/content/docs/v5/how-it-works/code-transform.mdxdocs/content/worlds/v5/building-a-world.mdxdocs/content/worlds/v5/upgrading-to-v5.mdx🤖 Generated with Claude Code