docs: apply Vercel technical writing standards (#3704)
* docs: apply Vercel technical writing standards
Audit the complete documentation corpus, package READMEs, skills, and
source TSDoc/comments against the vercel-technical-writing skill and
style-rules.md. Normalize sentence-case headings without changing
published anchors, remove prose em dashes and filler wording, improve
active voice and self-contained phrasing, standardize product/brand
capitalization, American English, list punctuation, units, and code
fence languages, and preserve exact runtime strings/table placeholders.
All executable code is unchanged. Modified skills have their metadata
versions bumped.
* docs: extend writing audit to repository Markdown
Apply the same technical-writing rules to design documents, compiler
specifications, workbench guides, package changelogs, and the remaining
tracked Markdown outside the deployed docs corpus. Preserve historical
meaning, commands, output literals, table placeholders, and heading
anchors.
* docs: exclude generated package changelogs from audit
2026-08-21 14:24:31 -07:00
# Agent instructions
2026-01-05 20:15:56 -08:00
2026-02-05 16:19:16 -08:00
**CRITICAL RULES: **
2026-04-08 13:02:21 -07:00
- NEVER push directly to the `main` or `stable` branches
2026-02-20 12:52:43 -08:00
- Do not remove or break agent-discoverable docs sitemap behavior: keep docs/app/sitemap.md/route.ts and docs/app/[lang]/sitemap.md/route.ts, and keep the sitemap link in docs/app/[lang]/llms.mdx/[[...slug]]/route.ts.
2026-01-05 20:15:56 -08:00
2026-03-11 12:56:25 -07:00
## Overview
2026-03-29 16:05:39 -07:00
Workflow SDK is a durable functions framework for JavaScript/TypeScript that enables writing long-running, stateful application logic on top of stateless compute. The runtime persists progress as an event log and deterministically replays code to reconstruct state after cold starts, failures, or scale events.
2026-03-11 12:56:25 -07:00
2026-03-29 16:05:39 -07:00
This repository contains the client-side SDK code for workflows, along with example apps that showcase Workflow SDK in action.
2026-03-11 12:56:25 -07:00
## Architecture
docs: apply Vercel technical writing standards (#3704)
* docs: apply Vercel technical writing standards
Audit the complete documentation corpus, package READMEs, skills, and
source TSDoc/comments against the vercel-technical-writing skill and
style-rules.md. Normalize sentence-case headings without changing
published anchors, remove prose em dashes and filler wording, improve
active voice and self-contained phrasing, standardize product/brand
capitalization, American English, list punctuation, units, and code
fence languages, and preserve exact runtime strings/table placeholders.
All executable code is unchanged. Modified skills have their metadata
versions bumped.
* docs: extend writing audit to repository Markdown
Apply the same technical-writing rules to design documents, compiler
specifications, workbench guides, package changelogs, and the remaining
tracked Markdown outside the deployed docs corpus. Preserve historical
meaning, commands, output literals, table placeholders, and heading
anchors.
* docs: exclude generated package changelogs from audit
2026-08-21 14:24:31 -07:00
### Core components
2026-03-11 12:56:25 -07:00
- **packages/core**: Core workflow runtime and primitives (`@workflow/core` )
- **packages/next**: Next.js integration (`@workflow/next` )
- **packages/cli**: Command-line interface (`@workflow/cli` )
- **packages/world**: Core interfaces and types for workflow storage backends (`@workflow/world` )
- **packages/world-local**: Filesystem-based workflow backend for local development and testing (`@workflow/world-local` )
- **packages/world-vercel**: Production workflow backend for Vercel platform deployments (`@workflow/world-vercel` )
- **packages/swc-plugin-workflow**: SWC compiler plugin for workflow transformations
- **workbench/example**: Basic workflow examples using the CLI (aka "standalone mode")
- **workbench/nextjs-turbopack**: Workflow examples using the Next.js integration
docs: apply Vercel technical writing standards (#3704)
* docs: apply Vercel technical writing standards
Audit the complete documentation corpus, package READMEs, skills, and
source TSDoc/comments against the vercel-technical-writing skill and
style-rules.md. Normalize sentence-case headings without changing
published anchors, remove prose em dashes and filler wording, improve
active voice and self-contained phrasing, standardize product/brand
capitalization, American English, list punctuation, units, and code
fence languages, and preserve exact runtime strings/table placeholders.
All executable code is unchanged. Modified skills have their metadata
versions bumped.
* docs: extend writing audit to repository Markdown
Apply the same technical-writing rules to design documents, compiler
specifications, workbench guides, package changelogs, and the remaining
tracked Markdown outside the deployed docs corpus. Preserve historical
meaning, commands, output literals, table placeholders, and heading
anchors.
* docs: exclude generated package changelogs from audit
2026-08-21 14:24:31 -07:00
### Workflow execution model
2026-03-11 12:56:25 -07:00
Workflows consist of two types of functions:
1. **Workflow functions ** (`"use workflow"` ): Orchestrators that run in a sandboxed VM without full Node.js access
2. **Step functions ** (`"use step"` ): Individual pieces of logic with full Node.js runtime access
The framework uses compiler transformations to split workflow files into separate bundles for client, workflow, and step execution contexts.
docs: apply Vercel technical writing standards (#3704)
* docs: apply Vercel technical writing standards
Audit the complete documentation corpus, package READMEs, skills, and
source TSDoc/comments against the vercel-technical-writing skill and
style-rules.md. Normalize sentence-case headings without changing
published anchors, remove prose em dashes and filler wording, improve
active voice and self-contained phrasing, standardize product/brand
capitalization, American English, list punctuation, units, and code
fence languages, and preserve exact runtime strings/table placeholders.
All executable code is unchanged. Modified skills have their metadata
versions bumped.
* docs: extend writing audit to repository Markdown
Apply the same technical-writing rules to design documents, compiler
specifications, workbench guides, package changelogs, and the remaining
tracked Markdown outside the deployed docs corpus. Preserve historical
meaning, commands, output literals, table placeholders, and heading
anchors.
* docs: exclude generated package changelogs from audit
2026-08-21 14:24:31 -07:00
## Development commands
2026-03-11 12:56:25 -07:00
docs: apply Vercel technical writing standards (#3704)
* docs: apply Vercel technical writing standards
Audit the complete documentation corpus, package READMEs, skills, and
source TSDoc/comments against the vercel-technical-writing skill and
style-rules.md. Normalize sentence-case headings without changing
published anchors, remove prose em dashes and filler wording, improve
active voice and self-contained phrasing, standardize product/brand
capitalization, American English, list punctuation, units, and code
fence languages, and preserve exact runtime strings/table placeholders.
All executable code is unchanged. Modified skills have their metadata
versions bumped.
* docs: extend writing audit to repository Markdown
Apply the same technical-writing rules to design documents, compiler
specifications, workbench guides, package changelogs, and the remaining
tracked Markdown outside the deployed docs corpus. Preserve historical
meaning, commands, output literals, table placeholders, and heading
anchors.
* docs: exclude generated package changelogs from audit
2026-08-21 14:24:31 -07:00
### Workspace-level commands
2026-03-11 12:56:25 -07:00
``` bash
# Build all packages
pnpm build
# Run tests across all packages
pnpm test
# Run end-to-end tests
pnpm test:e2e
# Format code with Biome
pnpm format
# Lint with Biome
pnpm lint
# Typecheck TypeScript
pnpm typecheck
# Clean build artifacts
pnpm clean
```
docs: apply Vercel technical writing standards (#3704)
* docs: apply Vercel technical writing standards
Audit the complete documentation corpus, package READMEs, skills, and
source TSDoc/comments against the vercel-technical-writing skill and
style-rules.md. Normalize sentence-case headings without changing
published anchors, remove prose em dashes and filler wording, improve
active voice and self-contained phrasing, standardize product/brand
capitalization, American English, list punctuation, units, and code
fence languages, and preserve exact runtime strings/table placeholders.
All executable code is unchanged. Modified skills have their metadata
versions bumped.
* docs: extend writing audit to repository Markdown
Apply the same technical-writing rules to design documents, compiler
specifications, workbench guides, package changelogs, and the remaining
tracked Markdown outside the deployed docs corpus. Preserve historical
meaning, commands, output literals, table placeholders, and heading
anchors.
* docs: exclude generated package changelogs from audit
2026-08-21 14:24:31 -07:00
### Core package testing
2026-03-11 12:56:25 -07:00
``` bash
# Test core functionality
cd packages/core && pnpm test
# Test specific file
cd packages/core && pnpm vitest run src/[ filename] .test.ts
# Run E2E tests (requires environment variables and running dev server)
# Note: Use nextjs-turbopack for local e2e testing (not example app - it has no dev server)
# Step 1: Start the dev server in background
2026-05-01 12:37:41 -07:00
# NOTE: WORKFLOW_PUBLIC_MANIFEST=1 is required for e2e tests to access the workflow manifest
cd workbench/nextjs-turbopack && WORKFLOW_PUBLIC_MANIFEST = 1 pnpm dev > /tmp/nextjs-dev.log 2>& 1 &
2026-03-11 12:56:25 -07:00
# Step 2: Wait for server to be ready (usually 15-20 seconds)
sleep 15
# Step 3: Run the e2e tests from the project root
DEPLOYMENT_URL = "http://localhost:3000" APP_NAME = "nextjs-turbopack" pnpm vitest run packages/core/e2e/e2e.test.ts
# Step 4: Stop the dev server when done
pkill -f "pnpm dev"
# To run specific tests, use the -t flag:
DEPLOYMENT_URL = "http://localhost:3000" APP_NAME = "nextjs-turbopack" pnpm vitest run packages/core/e2e/e2e.test.ts -t "sleeping"
2026-04-30 01:16:45 -07:00
# For running E2E locally against a deployed Vercel preview/production app:
# The test matrix in .github/workflows/tests.yml is the source of truth —
# each app entry defines the project-id / project-slug needed below.
#
# Required environment variables (matches the CI `e2e-vercel-prod` job):
# - DEPLOYMENT_URL: Full URL of the deployed app (e.g. a preview deployment URL)
# - VERCEL_DEPLOYMENT_ID: The dpl_... ID of the deployment (get via `vercel inspect <url>`)
# - APP_NAME: App name (example, nextjs-turbopack, nextjs-webpack, nitro, vite,
# nuxt, sveltekit, hono, express, fastify, astro)
# - WORKFLOW_VERCEL_ENV: "preview" or "production"
# - WORKFLOW_VERCEL_AUTH_TOKEN: Vercel auth token with access to the team
# - WORKFLOW_VERCEL_TEAM: Vercel team ID (CI uses team_nO2mCG4W8IxPIeKoSsqwAxxB for labs)
# - WORKFLOW_VERCEL_PROJECT: Vercel project ID (prj_...) — see test matrix
# - WORKFLOW_VERCEL_PROJECT_SLUG: Vercel project slug — see test matrix
ci: switch Vercel deployment-protection bypass to OIDC Trusted Sources (#1882)
* ci: switch Vercel deployment-protection bypass to OIDC Trusted Sources
The e2e, benchmark, and docs-smoke CI jobs previously used the static
`VERCEL_AUTOMATION_BYPASS_SECRET` deployment-protection bypass token
to reach protected Vercel deployments. Switch them over to the new OIDC
Trusted Sources flow: the GitHub Actions runner mints a short-lived
OIDC token via `core.getIDToken()` and forwards it on requests in the
`x-vercel-trusted-oidc-idp-token` header.
Each workbench project (and `workflow-docs`) has been configured with a
matching trusted-source rule:
aud=https://github.com/vercel, repository=vercel/workflow
The shared header helper now lives at `scripts/trusted-sources-headers.mjs`
and is imported by both the e2e/bench tests and the docs smoke script,
removing the previous duplication.
* rename to VERCEL_OIDC_TOKEN and wire through world-vercel
- Rename the env var from VERCEL_TRUSTED_OIDC_TOKEN to VERCEL_OIDC_TOKEN
to match Vercel's convention (also read by @vercel/oidc's
getVercelOidcToken()).
- In @workflow/world-vercel, replace the legacy
VERCEL_WORKFLOW_SERVER_PROTECTION_BYPASS / x-vercel-protection-bypass
flow with VERCEL_OIDC_TOKEN / x-vercel-trusted-oidc-idp-token. The
trusted-source header is attached on every outbound workflow-server
request (both proxied through api.vercel.com and direct).
- Drop the bypass header from the encryption-key and
resolve-latest-deployment fetches: those go to api.vercel.com which
is public.
- Drop VERCEL_WORKFLOW_SERVER_PROTECTION_BYPASS plumbing from tests.yml.
- Update the pending world-vercel changeset to describe the final
trusted-sources flow.
* .
* .
* ci: add statuses:read permission for wait-for-vercel-project action
The action queries /commits/{sha}/status (Commit Statuses API) in addition
to the Deployments API, in order to extract the Vercel `dpl_...` ID. With
an explicit permissions block in place, GITHUB_TOKEN now needs
`statuses: read` or the action 403s when resolving the deployment ID.
Reported by Copilot review on #1882.
* ci(docs): log status code and body when waitForServer times out
Helps diagnose deployment-protection / OIDC-trusted-source bypass
failures (e.g. SSO redirects) on the workflow-docs preview.
* ci(docs): log OIDC token claims (aud, repository, etc.) for diagnostics
Helps determine whether the bypass is failing because of missing
trusted-source config, claim mismatch, or audience mismatch.
* ci(docs): add curl debug step to verify OIDC header reaches Vercel
* .
* ci: remove debug logging now that trusted-sources config is correct
The fetch-failure root cause was the trusted-sources rule format: the
labs workbench projects had been PATCHed with just `to.slugs` (no
`preset`), but Vercel's edge requires the dashboard-form-style
`to.preset: 'all-custom'` field plus `development` in the slug list to
match incoming requests. After re-PATCHing all projects with the
correct format, the bypass works end-to-end.
* ci(docs): debug — test trusted-sources bypass against docs and labs deployments
Trying repository_owner claim added to one labs project to see if that
fixes the bypass.
* ci(docs): revert curl debug step
The GitHub Actions OIDC trusted-sources bypass returns 401 on all tested
projects regardless of claim configuration (including workflow-docs which
was set up via the dashboard). This is not a per-project config issue.
Need to investigate with Vercel team before continuing.
* ci(docs): probe trusted-sources bypass and surface x-vercel-id
Adds a debug step that does two HEAD requests against the docs preview
deployment (with and without the OIDC trusted-sources header) and prints
the response status line plus `x-vercel-id` for each. The proxy-side
trusted-sources changes for GitHub Actions OIDC tokens are rolling out
gradually (~12+ hours), so the edge-node identifier in `x-vercel-id`
helps explain why a request might succeed or fail during the rollout
window.
Also includes `x-vercel-id` in the `waitForServer` timeout error so
post-mortem analysis of failing runs has the same edge-node info.
* ci(docs): drop trusted-sources curl probe — bypass works once proxy fix reaches the serving edge node
The probe served its purpose: confirmed the bypass is functional once
the request lands on a region that has the proxy-side trusted-sources
fix rolled out. The waitForServer error message still surfaces
x-vercel-id for any future rollout-window debugging.
* .
* world-vercel: log outbound OIDC token claims once per process
Adds a one-shot diagnostic that prints the non-sensitive claims of the
OIDC token (`iss`, `aud`, `owner_id`, `project_id`, `environment`,
`sub`, `scope`, `exp`) on the first request that uses bearer auth.
This is invaluable for debugging Vercel deployment-protection
trusted-source rule mismatches: a 401 from the edge tells you nothing
about why the rule didn't match, and the token's claims are the only
thing that determines that. The signature is never logged.
Gated to once per process — Vercel-issued tokens are process-stable for
the lambda's lifetime so further log lines would just be redundant
spam.
* world-vercel: route trusted-sources header through getVercelOidcToken()
The Authorization bearer correctly preferred config.token (a static
Vercel auth token from CLI / Actions runner) and fell back to
getVercelOidcToken() inside a Vercel function. But the trusted-sources
bypass header (x-vercel-trusted-oidc-idp-token) was being read directly
from process.env.VERCEL_OIDC_TOKEN inside getHeaders(). That env var is
the bake-time token, frozen at deployment-creation time — on a project
that has been redeployed after a settings change, it carries stale
claims (e.g. an iss from when the project was briefly in 'global' mode)
that no longer match the workflow-server's trusted-sources rule.
Move trusted-sources header attachment from getHeaders() (sync) to
getHttpConfig() (async) and source it from getVercelOidcToken(). That
function reads getContext().headers['x-vercel-oidc-token'] first — a
freshly minted per-request token that always reflects current project
settings — and only falls back to the env var when that header is
missing.
Bearer auth source remains config.token-first.
Also expand the diagnostic to log claims from BOTH the per-request OIDC
token AND the bake-time env var so the divergence is visible in logs
when debugging future trusted-source mismatches.
Removes the now-misleading getProtectionBypassHeader() helper (its
'read env var directly' semantics were exactly the bug).
* world-vercel: skip OIDC trusted-sources header on proxied path
The two outbound flows have different auth requirements:
1. Proxied (usingProxy=true) — calls api.vercel.com/v1/workflow.
Public endpoint, authenticated with a static Vercel auth token via
config.token. The api-workflow proxy mints its own OIDC token
before forwarding to workflow-server, so the trusted-sources
bypass header on the SDK→proxy hop is meaningless. CLI, GitHub
Actions, and other API-client callers take this path.
2. Direct (usingProxy=false) — runs inside a Vercel deployment
talking straight to workflow-server. workflow-server validates a
Vercel OIDC bearer; Vercel's edge validates the trusted-sources
header. Both must come from getVercelOidcToken() (the per-request
fresh token), not process.env.VERCEL_OIDC_TOKEN (the bake-time
token that can be stale after a project config change).
Previously getHttpConfig attached x-vercel-trusted-oidc-idp-token on
both paths whenever getVercelOidcToken() resolved. That accidentally
forwarded the GitHub Actions OIDC token (when wired into
VERCEL_OIDC_TOKEN by the test runner) onto every SDK→proxy request,
which is harmless but wrong-by-design — the proxy is public, doesn't
look at that header on its inbound side, and the GHA token isn't its
intended audience.
Bearer auth source rules:
- Proxied: only config.token. (No fallback to OIDC; that auth
pathway doesn't go through the proxy's auth checks.)
- Direct: config.token (for tests / local dev), falling back to
getVercelOidcToken() (for Vercel-runtime calls).
* world-vercel: throw if proxied path is hit without a Vercel auth token
The api-workflow proxy authenticates the caller with a regular Vercel
auth token (not OIDC), so reaching the proxied path with no
config.token is always wrong: the proxy will reject the request and
the SDK caller would see an opaque 401 with no actionable hint.
Throw at config-resolution time with a clear message that points to
the WORKFLOW_VERCEL_AUTH_TOKEN env var the SDK reads from. Adds tests
covering both the no-token-throws case and the with-token-attaches-
bearer-and-skips-trusted-sources case.
* test(e2e): include x-vercel-id in startWorkflowViaHttp error message
When the trusted-sources bypass returns 401, the error message now
surfaces the response's x-vercel-id header so we can identify which
edge node served the failure. Helps distinguish proxy-rollout
incompleteness from actual config errors during incremental
rollouts of edge-side changes.
* ci: mint GHA OIDC tokens on demand to survive 5-minute expiry
GitHub Actions OIDC tokens have a hard 5-minute lifetime that cannot be
extended (no API to ask for a longer TTL — exp is always iat + ~300s).
Pre-minting once at the start of the job and shipping the result down
to the test runner via env var means tests that run late in the suite
hit an expired token and 401 on /api/trigger-pages (and any other
trusted-sources protected endpoint).
Move minting into scripts/trusted-sources-headers.mjs:
- getTrustedSourcesHeaders() is now async.
- It calls the runner's ACTIONS_ID_TOKEN_REQUEST_URL endpoint directly
(the env vars GHA exposes when permissions: id-token: write is on)
and re-mints 60s before the cached token's exp.
- Falls back to process.env.VERCEL_OIDC_TOKEN for non-GHA contexts
(Vercel runtime, local dev).
Workflow files drop the now-redundant 'Mint OIDC token' step and the
VERCEL_OIDC_TOKEN env-var passthrough on the test step. The runner env
vars propagate to subsequent steps automatically.
Updates all 17 callers in e2e.test.ts / bench.bench.ts / utils.ts /
docs/scripts/check-docs-smoke.mjs to await the now-async call.
* address PR #1882 code review
- Drop `statuses: read` from the three workflow permission blocks (the
wait-for-vercel-project action works without it on a public repo).
- Revert the `x-vercel-id` debug logging in `startWorkflowViaHttp`.
- Delete `packages/world-vercel/src/jwt-claims.ts` (debug-only helper).
- Drop the JWT claims diagnostic logging from `getHttpConfig`.
- Tighten the auth-flow comment in `getHttpConfig` and remove the
historical 'no longer attaches' note from `getHeaders`/its test.
- Restore `.changeset/world-vercel-protection-bypass.md` (already
shipped in a beta release per .changeset/pre.json).
- Trim the `.changeset/world-vercel-trusted-sources.md` description to
one short paragraph.
* docs(AGENTS): document local VERCEL_OIDC_TOKEN via vercel env pull
Configured trustedSources.projects on all 11 workbench app projects so
each one accepts a Vercel-issued OIDC token from any of the others. A
developer running e2e locally can now do `vercel env pull` from any
workbench app's directory and use the resulting VERCEL_OIDC_TOKEN to
bypass Deployment Protection on any of the workbench preview/prod
deployments — no need to disable protection on the project just to run
the suite locally.
2026-05-02 03:21:52 -07:00
# - VERCEL_OIDC_TOKEN: Short-lived OIDC token used to bypass
# deployment protection via Trusted Sources.
# In CI this is auto-minted from the GitHub
# Actions runner. Locally, run
# `vercel env pull` from any workbench app's
# directory and the resulting `.env.local`
# will contain a `VERCEL_OIDC_TOKEN` value
# that all workbench projects accept (they
# are configured to trust each other under
# `trustedSources.projects`).
2026-04-30 01:16:45 -07:00
#
# Example (nextjs-turbopack preview deployment):
NODE_OPTIONS = "--enable-source-maps" \
DEPLOYMENT_URL = "https://example-nextjs-workflow-turbopack-<hash>.labs.vercel.dev" \
VERCEL_DEPLOYMENT_ID = "dpl_..." \
APP_NAME = "nextjs-turbopack" \
WORKFLOW_VERCEL_ENV = "preview" \
WORKFLOW_VERCEL_AUTH_TOKEN = "<vercel_labs_token>" \
WORKFLOW_VERCEL_TEAM = "team_nO2mCG4W8IxPIeKoSsqwAxxB" \
WORKFLOW_VERCEL_PROJECT = "prj_yjkM7UdHliv8bfxZ1sMJQf1pMpdi" \
WORKFLOW_VERCEL_PROJECT_SLUG = "example-nextjs-workflow-turbopack" \
ci: switch Vercel deployment-protection bypass to OIDC Trusted Sources (#1882)
* ci: switch Vercel deployment-protection bypass to OIDC Trusted Sources
The e2e, benchmark, and docs-smoke CI jobs previously used the static
`VERCEL_AUTOMATION_BYPASS_SECRET` deployment-protection bypass token
to reach protected Vercel deployments. Switch them over to the new OIDC
Trusted Sources flow: the GitHub Actions runner mints a short-lived
OIDC token via `core.getIDToken()` and forwards it on requests in the
`x-vercel-trusted-oidc-idp-token` header.
Each workbench project (and `workflow-docs`) has been configured with a
matching trusted-source rule:
aud=https://github.com/vercel, repository=vercel/workflow
The shared header helper now lives at `scripts/trusted-sources-headers.mjs`
and is imported by both the e2e/bench tests and the docs smoke script,
removing the previous duplication.
* rename to VERCEL_OIDC_TOKEN and wire through world-vercel
- Rename the env var from VERCEL_TRUSTED_OIDC_TOKEN to VERCEL_OIDC_TOKEN
to match Vercel's convention (also read by @vercel/oidc's
getVercelOidcToken()).
- In @workflow/world-vercel, replace the legacy
VERCEL_WORKFLOW_SERVER_PROTECTION_BYPASS / x-vercel-protection-bypass
flow with VERCEL_OIDC_TOKEN / x-vercel-trusted-oidc-idp-token. The
trusted-source header is attached on every outbound workflow-server
request (both proxied through api.vercel.com and direct).
- Drop the bypass header from the encryption-key and
resolve-latest-deployment fetches: those go to api.vercel.com which
is public.
- Drop VERCEL_WORKFLOW_SERVER_PROTECTION_BYPASS plumbing from tests.yml.
- Update the pending world-vercel changeset to describe the final
trusted-sources flow.
* .
* .
* ci: add statuses:read permission for wait-for-vercel-project action
The action queries /commits/{sha}/status (Commit Statuses API) in addition
to the Deployments API, in order to extract the Vercel `dpl_...` ID. With
an explicit permissions block in place, GITHUB_TOKEN now needs
`statuses: read` or the action 403s when resolving the deployment ID.
Reported by Copilot review on #1882.
* ci(docs): log status code and body when waitForServer times out
Helps diagnose deployment-protection / OIDC-trusted-source bypass
failures (e.g. SSO redirects) on the workflow-docs preview.
* ci(docs): log OIDC token claims (aud, repository, etc.) for diagnostics
Helps determine whether the bypass is failing because of missing
trusted-source config, claim mismatch, or audience mismatch.
* ci(docs): add curl debug step to verify OIDC header reaches Vercel
* .
* ci: remove debug logging now that trusted-sources config is correct
The fetch-failure root cause was the trusted-sources rule format: the
labs workbench projects had been PATCHed with just `to.slugs` (no
`preset`), but Vercel's edge requires the dashboard-form-style
`to.preset: 'all-custom'` field plus `development` in the slug list to
match incoming requests. After re-PATCHing all projects with the
correct format, the bypass works end-to-end.
* ci(docs): debug — test trusted-sources bypass against docs and labs deployments
Trying repository_owner claim added to one labs project to see if that
fixes the bypass.
* ci(docs): revert curl debug step
The GitHub Actions OIDC trusted-sources bypass returns 401 on all tested
projects regardless of claim configuration (including workflow-docs which
was set up via the dashboard). This is not a per-project config issue.
Need to investigate with Vercel team before continuing.
* ci(docs): probe trusted-sources bypass and surface x-vercel-id
Adds a debug step that does two HEAD requests against the docs preview
deployment (with and without the OIDC trusted-sources header) and prints
the response status line plus `x-vercel-id` for each. The proxy-side
trusted-sources changes for GitHub Actions OIDC tokens are rolling out
gradually (~12+ hours), so the edge-node identifier in `x-vercel-id`
helps explain why a request might succeed or fail during the rollout
window.
Also includes `x-vercel-id` in the `waitForServer` timeout error so
post-mortem analysis of failing runs has the same edge-node info.
* ci(docs): drop trusted-sources curl probe — bypass works once proxy fix reaches the serving edge node
The probe served its purpose: confirmed the bypass is functional once
the request lands on a region that has the proxy-side trusted-sources
fix rolled out. The waitForServer error message still surfaces
x-vercel-id for any future rollout-window debugging.
* .
* world-vercel: log outbound OIDC token claims once per process
Adds a one-shot diagnostic that prints the non-sensitive claims of the
OIDC token (`iss`, `aud`, `owner_id`, `project_id`, `environment`,
`sub`, `scope`, `exp`) on the first request that uses bearer auth.
This is invaluable for debugging Vercel deployment-protection
trusted-source rule mismatches: a 401 from the edge tells you nothing
about why the rule didn't match, and the token's claims are the only
thing that determines that. The signature is never logged.
Gated to once per process — Vercel-issued tokens are process-stable for
the lambda's lifetime so further log lines would just be redundant
spam.
* world-vercel: route trusted-sources header through getVercelOidcToken()
The Authorization bearer correctly preferred config.token (a static
Vercel auth token from CLI / Actions runner) and fell back to
getVercelOidcToken() inside a Vercel function. But the trusted-sources
bypass header (x-vercel-trusted-oidc-idp-token) was being read directly
from process.env.VERCEL_OIDC_TOKEN inside getHeaders(). That env var is
the bake-time token, frozen at deployment-creation time — on a project
that has been redeployed after a settings change, it carries stale
claims (e.g. an iss from when the project was briefly in 'global' mode)
that no longer match the workflow-server's trusted-sources rule.
Move trusted-sources header attachment from getHeaders() (sync) to
getHttpConfig() (async) and source it from getVercelOidcToken(). That
function reads getContext().headers['x-vercel-oidc-token'] first — a
freshly minted per-request token that always reflects current project
settings — and only falls back to the env var when that header is
missing.
Bearer auth source remains config.token-first.
Also expand the diagnostic to log claims from BOTH the per-request OIDC
token AND the bake-time env var so the divergence is visible in logs
when debugging future trusted-source mismatches.
Removes the now-misleading getProtectionBypassHeader() helper (its
'read env var directly' semantics were exactly the bug).
* world-vercel: skip OIDC trusted-sources header on proxied path
The two outbound flows have different auth requirements:
1. Proxied (usingProxy=true) — calls api.vercel.com/v1/workflow.
Public endpoint, authenticated with a static Vercel auth token via
config.token. The api-workflow proxy mints its own OIDC token
before forwarding to workflow-server, so the trusted-sources
bypass header on the SDK→proxy hop is meaningless. CLI, GitHub
Actions, and other API-client callers take this path.
2. Direct (usingProxy=false) — runs inside a Vercel deployment
talking straight to workflow-server. workflow-server validates a
Vercel OIDC bearer; Vercel's edge validates the trusted-sources
header. Both must come from getVercelOidcToken() (the per-request
fresh token), not process.env.VERCEL_OIDC_TOKEN (the bake-time
token that can be stale after a project config change).
Previously getHttpConfig attached x-vercel-trusted-oidc-idp-token on
both paths whenever getVercelOidcToken() resolved. That accidentally
forwarded the GitHub Actions OIDC token (when wired into
VERCEL_OIDC_TOKEN by the test runner) onto every SDK→proxy request,
which is harmless but wrong-by-design — the proxy is public, doesn't
look at that header on its inbound side, and the GHA token isn't its
intended audience.
Bearer auth source rules:
- Proxied: only config.token. (No fallback to OIDC; that auth
pathway doesn't go through the proxy's auth checks.)
- Direct: config.token (for tests / local dev), falling back to
getVercelOidcToken() (for Vercel-runtime calls).
* world-vercel: throw if proxied path is hit without a Vercel auth token
The api-workflow proxy authenticates the caller with a regular Vercel
auth token (not OIDC), so reaching the proxied path with no
config.token is always wrong: the proxy will reject the request and
the SDK caller would see an opaque 401 with no actionable hint.
Throw at config-resolution time with a clear message that points to
the WORKFLOW_VERCEL_AUTH_TOKEN env var the SDK reads from. Adds tests
covering both the no-token-throws case and the with-token-attaches-
bearer-and-skips-trusted-sources case.
* test(e2e): include x-vercel-id in startWorkflowViaHttp error message
When the trusted-sources bypass returns 401, the error message now
surfaces the response's x-vercel-id header so we can identify which
edge node served the failure. Helps distinguish proxy-rollout
incompleteness from actual config errors during incremental
rollouts of edge-side changes.
* ci: mint GHA OIDC tokens on demand to survive 5-minute expiry
GitHub Actions OIDC tokens have a hard 5-minute lifetime that cannot be
extended (no API to ask for a longer TTL — exp is always iat + ~300s).
Pre-minting once at the start of the job and shipping the result down
to the test runner via env var means tests that run late in the suite
hit an expired token and 401 on /api/trigger-pages (and any other
trusted-sources protected endpoint).
Move minting into scripts/trusted-sources-headers.mjs:
- getTrustedSourcesHeaders() is now async.
- It calls the runner's ACTIONS_ID_TOKEN_REQUEST_URL endpoint directly
(the env vars GHA exposes when permissions: id-token: write is on)
and re-mints 60s before the cached token's exp.
- Falls back to process.env.VERCEL_OIDC_TOKEN for non-GHA contexts
(Vercel runtime, local dev).
Workflow files drop the now-redundant 'Mint OIDC token' step and the
VERCEL_OIDC_TOKEN env-var passthrough on the test step. The runner env
vars propagate to subsequent steps automatically.
Updates all 17 callers in e2e.test.ts / bench.bench.ts / utils.ts /
docs/scripts/check-docs-smoke.mjs to await the now-async call.
* address PR #1882 code review
- Drop `statuses: read` from the three workflow permission blocks (the
wait-for-vercel-project action works without it on a public repo).
- Revert the `x-vercel-id` debug logging in `startWorkflowViaHttp`.
- Delete `packages/world-vercel/src/jwt-claims.ts` (debug-only helper).
- Drop the JWT claims diagnostic logging from `getHttpConfig`.
- Tighten the auth-flow comment in `getHttpConfig` and remove the
historical 'no longer attaches' note from `getHeaders`/its test.
- Restore `.changeset/world-vercel-protection-bypass.md` (already
shipped in a beta release per .changeset/pre.json).
- Trim the `.changeset/world-vercel-trusted-sources.md` description to
one short paragraph.
* docs(AGENTS): document local VERCEL_OIDC_TOKEN via vercel env pull
Configured trustedSources.projects on all 11 workbench app projects so
each one accepts a Vercel-issued OIDC token from any of the others. A
developer running e2e locally can now do `vercel env pull` from any
workbench app's directory and use the resulting VERCEL_OIDC_TOKEN to
bypass Deployment Protection on any of the workbench preview/prod
deployments — no need to disable protection on the project just to run
the suite locally.
2026-05-02 03:21:52 -07:00
VERCEL_OIDC_TOKEN = " $( grep VERCEL_OIDC_TOKEN workbench/nextjs-turbopack/.env.local | cut -d= -f2-) " \
2026-04-30 01:16:45 -07:00
pnpm run test:e2e
2026-03-11 12:56:25 -07:00
```
docs: apply Vercel technical writing standards (#3704)
* docs: apply Vercel technical writing standards
Audit the complete documentation corpus, package READMEs, skills, and
source TSDoc/comments against the vercel-technical-writing skill and
style-rules.md. Normalize sentence-case headings without changing
published anchors, remove prose em dashes and filler wording, improve
active voice and self-contained phrasing, standardize product/brand
capitalization, American English, list punctuation, units, and code
fence languages, and preserve exact runtime strings/table placeholders.
All executable code is unchanged. Modified skills have their metadata
versions bumped.
* docs: extend writing audit to repository Markdown
Apply the same technical-writing rules to design documents, compiler
specifications, workbench guides, package changelogs, and the remaining
tracked Markdown outside the deployed docs corpus. Preserve historical
meaning, commands, output literals, table placeholders, and heading
anchors.
* docs: exclude generated package changelogs from audit
2026-08-21 14:24:31 -07:00
### Event log race repro
2026-08-01 10:59:07 -07:00
`packages/core/e2e/event-log-race-repro.test.ts` is a dedicated harness for
2026-09-08 15:19:32 -07:00
`CORRUPTED_EVENT_LOG` . It drives five scenarios against one deployment:
2026-08-01 10:59:07 -07:00
`step-storm` and `hook-storm` (concurrent replays of a single run racing the
2026-09-08 15:19:32 -07:00
per-branch watchdog; `hook-storm` is a production shape), `blocked-branch`
2026-08-21 15:31:52 -07:00
(each branch parks on a launch step before its hook race, so a woken replay can
hold a log that predates a sibling's launch completion and take the ordinal that
sibling's wait is about to get; it covers the class the wake-order fixes miss),
2026-09-08 15:19:32 -07:00
`wake-loop` (one sequential loop racing a reusable hook read against a
heartbeat sleep, no fan-out; the driver supplies the concurrency with bursty
resumes and resumes aimed at the heartbeat deadline, the shape of a production
run whose replays of one immutable prefix diverged non-deterministically on an
unconsumable `wait_created` ), plus a `hook-sleep` control that provides the
calibration baseline. Any outcome
2026-08-21 15:31:52 -07:00
other than `completed` fails the run, except `infra` , which means the harness
could not reach the deployment.
2026-08-01 10:59:07 -07:00
docs: apply Vercel technical writing standards (#3704)
* docs: apply Vercel technical writing standards
Audit the complete documentation corpus, package READMEs, skills, and
source TSDoc/comments against the vercel-technical-writing skill and
style-rules.md. Normalize sentence-case headings without changing
published anchors, remove prose em dashes and filler wording, improve
active voice and self-contained phrasing, standardize product/brand
capitalization, American English, list punctuation, units, and code
fence languages, and preserve exact runtime strings/table placeholders.
All executable code is unchanged. Modified skills have their metadata
versions bumped.
* docs: extend writing audit to repository Markdown
Apply the same technical-writing rules to design documents, compiler
specifications, workbench guides, package changelogs, and the remaining
tracked Markdown outside the deployed docs corpus. Preserve historical
meaning, commands, output literals, table placeholders, and heading
anchors.
* docs: exclude generated package changelogs from audit
2026-08-21 14:24:31 -07:00
Run it against a locally started workbench app. No Vercel deployment or
credentials are required:
2026-08-01 10:59:07 -07:00
``` bash
2026-08-12 13:16:42 -07:00
pnpm run test:e2e:event-log-race-repro:local # world-postgres
pnpm run test:e2e:event-log-race-repro:local --world local # world-local
2026-08-01 10:59:07 -07:00
```
2026-08-12 13:16:42 -07:00
The script (`scripts/event-log-race-repro-local.sh` , `--help` for flags) builds
and starts `workbench/nextjs-turbopack` with `WORKFLOW_TARGET_WORLD` and
2026-08-01 10:59:07 -07:00
`WORKFLOW_PUBLIC_MANIFEST=1` set **at build time ** (both are build-time inputs;
2026-08-12 13:16:42 -07:00
missing either silently yields a default-world app or a 404 manifest), runs the
harness, prints the same summary table CI posts, and tears the server down. For
world-postgres it first brings up the container and applies migrations, and
leaves Postgres running for the next iteration unless `--teardown` is passed;
the container flags (`--skip-db-setup` , `--no-docker` , `--teardown` ) do nothing
under `--world local` , whose only state is a data directory the script clears
before each run.
docs: apply Vercel technical writing standards (#3704)
* docs: apply Vercel technical writing standards
Audit the complete documentation corpus, package READMEs, skills, and
source TSDoc/comments against the vercel-technical-writing skill and
style-rules.md. Normalize sentence-case headings without changing
published anchors, remove prose em dashes and filler wording, improve
active voice and self-contained phrasing, standardize product/brand
capitalization, American English, list punctuation, units, and code
fence languages, and preserve exact runtime strings/table placeholders.
All executable code is unchanged. Modified skills have their metadata
versions bumped.
* docs: extend writing audit to repository Markdown
Apply the same technical-writing rules to design documents, compiler
specifications, workbench guides, package changelogs, and the remaining
tracked Markdown outside the deployed docs corpus. Preserve historical
meaning, commands, output literals, table placeholders, and heading
anchors.
* docs: exclude generated package changelogs from audit
2026-08-21 14:24:31 -07:00
Run both worlds because neither subsumes the other: world-postgres
2026-08-12 13:16:42 -07:00
arbitrates event slots inside one SQL statement, while world-local arbitrates
them with an exclusive `link(2)` against a directory that two processes (the app
and the harness) both write to. A slot race a transaction closes is not
automatically closed by a filesystem.
2026-08-01 10:59:07 -07:00
Scale is controlled entirely by `EVENT_LOG_RACE_REPRO_*` environment variables.
docs: apply Vercel technical writing standards (#3704)
* docs: apply Vercel technical writing standards
Audit the complete documentation corpus, package READMEs, skills, and
source TSDoc/comments against the vercel-technical-writing skill and
style-rules.md. Normalize sentence-case headings without changing
published anchors, remove prose em dashes and filler wording, improve
active voice and self-contained phrasing, standardize product/brand
capitalization, American English, list punctuation, units, and code
fence languages, and preserve exact runtime strings/table placeholders.
All executable code is unchanged. Modified skills have their metadata
versions bumped.
* docs: extend writing audit to repository Markdown
Apply the same technical-writing rules to design documents, compiler
specifications, workbench guides, package changelogs, and the remaining
tracked Markdown outside the deployed docs corpus. Preserve historical
meaning, commands, output literals, table placeholders, and heading
anchors.
* docs: exclude generated package changelogs from audit
2026-08-21 14:24:31 -07:00
Their defaults live only in `event-log-race-repro.test.ts` ; neither the CI
2026-08-01 10:59:07 -07:00
workflow nor the local script defines a second copy. The default scale (14 runs)
is a per-PR regression check, not a rate measurement; a clean run means "the
storms did not trip it", not "the rate is below X". To soak for a * rate * , use the
historical scale:
``` bash
EVENT_LOG_RACE_REPRO_STEP_STORM_ATTEMPTS = 600 \
EVENT_LOG_RACE_REPRO_HOOK_STORM_ATTEMPTS = 600 \
EVENT_LOG_RACE_REPRO_ATTEMPTS = 200 \
EVENT_LOG_RACE_REPRO_CONCURRENCY = 40 \
EVENT_LOG_RACE_REPRO_BUDGET_MS = 4500000 \
pnpm run test:e2e:event-log-race-repro:local --skip-build --skip-db-setup
```
Against world-postgres the storms bite much harder than the CI job's Vercel
preview does: on `main` , three 14-run passes failed 8 of their 18 `step-storm`
attempts with `CORRUPTED_EVENT_LOG` while `hook-storm` and `hook-sleep` stayed
clean, so the script exits non-zero. That is the harness working, not a broken
setup, and it is why the local runner is the fast signal while a fix is in
docs: apply Vercel technical writing standards (#3704)
* docs: apply Vercel technical writing standards
Audit the complete documentation corpus, package READMEs, skills, and
source TSDoc/comments against the vercel-technical-writing skill and
style-rules.md. Normalize sentence-case headings without changing
published anchors, remove prose em dashes and filler wording, improve
active voice and self-contained phrasing, standardize product/brand
capitalization, American English, list punctuation, units, and code
fence languages, and preserve exact runtime strings/table placeholders.
All executable code is unchanged. Modified skills have their metadata
versions bumped.
* docs: extend writing audit to repository Markdown
Apply the same technical-writing rules to design documents, compiler
specifications, workbench guides, package changelogs, and the remaining
tracked Markdown outside the deployed docs corpus. Preserve historical
meaning, commands, output literals, table placeholders, and heading
anchors.
* docs: exclude generated package changelogs from audit
2026-08-21 14:24:31 -07:00
flight. At 14 runs, a green CI job means "the storms did not trip it", nowhere
2026-08-01 10:59:07 -07:00
near "the rate is below X".
2026-08-14 11:34:29 -07:00
That is a * laptop * result, and the distinction matters: `CORRUPTED_EVENT_LOG`
means the run finished the race, while `stuck` usually means it never got to
run one. Two dispatches of the local lanes against unmodified `main` on GitHub's
4-core runners scored, at the default scale, world-postgres 5-6 of 6 `step-storm`
docs: apply Vercel technical writing standards (#3704)
* docs: apply Vercel technical writing standards
Audit the complete documentation corpus, package READMEs, skills, and
source TSDoc/comments against the vercel-technical-writing skill and
style-rules.md. Normalize sentence-case headings without changing
published anchors, remove prose em dashes and filler wording, improve
active voice and self-contained phrasing, standardize product/brand
capitalization, American English, list punctuation, units, and code
fence languages, and preserve exact runtime strings/table placeholders.
All executable code is unchanged. Modified skills have their metadata
versions bumped.
* docs: extend writing audit to repository Markdown
Apply the same technical-writing rules to design documents, compiler
specifications, workbench guides, package changelogs, and the remaining
tracked Markdown outside the deployed docs corpus. Preserve historical
meaning, commands, output literals, table placeholders, and heading
anchors.
* docs: exclude generated package changelogs from audit
2026-08-21 14:24:31 -07:00
runs `stuck` at `runTimeoutMs` in both, and world-local 6 and 12 of 14 `stuck` .
The * same * lane, the same commit, "6/14" and "12/14" one dispatch apart. Read a
2026-08-14 11:34:29 -07:00
single local-lane number as a verdict on a PR and it will mislead you; read
`pressure.resumesSent` and `progress.events` in the results JSON instead, which
say whether the run was racing or starving.
Two properties of the harness made that starvation self-sustaining, and both are
docs: apply Vercel technical writing standards (#3704)
* docs: apply Vercel technical writing standards
Audit the complete documentation corpus, package READMEs, skills, and
source TSDoc/comments against the vercel-technical-writing skill and
style-rules.md. Normalize sentence-case headings without changing
published anchors, remove prose em dashes and filler wording, improve
active voice and self-contained phrasing, standardize product/brand
capitalization, American English, list punctuation, units, and code
fence languages, and preserve exact runtime strings/table placeholders.
All executable code is unchanged. Modified skills have their metadata
versions bumped.
* docs: extend writing audit to repository Markdown
Apply the same technical-writing rules to design documents, compiler
specifications, workbench guides, package changelogs, and the remaining
tracked Markdown outside the deployed docs corpus. Preserve historical
meaning, commands, output literals, table placeholders, and heading
anchors.
* docs: exclude generated package changelogs from audit
2026-08-21 14:24:31 -07:00
now bounded. If you change either, know what you are giving up:
2026-08-14 11:34:29 -07:00
2026-08-21 15:31:52 -07:00
* **The poke pump decays** (`EVENT_LOG_RACE_REPRO_POKE_MAX` , default 64, then
`POKE_DECAY_FACTOR` , default 8). `step-storm` 's pressure is a wall-clock
cadence, so a slow run collected * more * out-of-band writes per unit of progress
than a fast one, and each one appends a `hook_received` that every later replay
re-reads. Unbounded on a 4-core runner it reached approximately 270 pokes per
run and no run ever finished. A healthy 6-round run sends 35-41 and never
reaches the budget. The pump slows rather than stopping, so a saturated run's
later rounds still get out-of-band writes; a hard stop left the back half of a
160s CI run unpressured. The lanes were never comparable on this axis anyway:
each Vercel resume pays a network round trip, so that lane's pump achieves an
effective 2.3s interval (35-44 pokes per run) where localhost runs the full
750ms, and the decayed rate is what brings the local lanes near it.
docs: apply Vercel technical writing standards (#3704)
* docs: apply Vercel technical writing standards
Audit the complete documentation corpus, package READMEs, skills, and
source TSDoc/comments against the vercel-technical-writing skill and
style-rules.md. Normalize sentence-case headings without changing
published anchors, remove prose em dashes and filler wording, improve
active voice and self-contained phrasing, standardize product/brand
capitalization, American English, list punctuation, units, and code
fence languages, and preserve exact runtime strings/table placeholders.
All executable code is unchanged. Modified skills have their metadata
versions bumped.
* docs: extend writing audit to repository Markdown
Apply the same technical-writing rules to design documents, compiler
specifications, workbench guides, package changelogs, and the remaining
tracked Markdown outside the deployed docs corpus. Preserve historical
meaning, commands, output literals, table placeholders, and heading
anchors.
* docs: exclude generated package changelogs from audit
2026-08-21 14:24:31 -07:00
* * *Runs abandoned at `runTimeoutMs` are canceled.** They used to keep replaying
2026-08-14 11:34:29 -07:00
in the same app process for the rest of the job. That is how world-local's
docs: apply Vercel technical writing standards (#3704)
* docs: apply Vercel technical writing standards
Audit the complete documentation corpus, package READMEs, skills, and
source TSDoc/comments against the vercel-technical-writing skill and
style-rules.md. Normalize sentence-case headings without changing
published anchors, remove prose em dashes and filler wording, improve
active voice and self-contained phrasing, standardize product/brand
capitalization, American English, list punctuation, units, and code
fence languages, and preserve exact runtime strings/table placeholders.
All executable code is unchanged. Modified skills have their metadata
versions bumped.
* docs: extend writing audit to repository Markdown
Apply the same technical-writing rules to design documents, compiler
specifications, workbench guides, package changelogs, and the remaining
tracked Markdown outside the deployed docs corpus. Preserve historical
meaning, commands, output literals, table placeholders, and heading
anchors.
* docs: exclude generated package changelogs from audit
2026-08-21 14:24:31 -07:00
`hook-storm` came to report six `stuck` runs with `resumesSent: 0` . Every one
2026-08-14 11:34:29 -07:00
of them starved behind the previous scenario's six abandoned `step-storm` runs
and never created a hook for the driver to resume, so the scenario measured
nothing about hooks at all.
2026-08-21 15:31:52 -07:00
The local script also raises `EVENT_LOG_RACE_REPRO_RUN_TIMEOUT_MS` to 480000
(export your own to override). A local lane runs the same storm about twice as
slowly as the Vercel lane. Measured on 4-core runners at the default scale,
`step-storm` takes 194-203s on world-local and 168-175s on world-postgres
against Vercel's 85-100s, so the harness' 240000 default left the local lanes at
approximately 83% of their own timeout, close enough that a slow runner turns a
lane that reproduces into a lane full of `stuck` . It is the one scale knob the
script sets, because it is the one whose meaning depends on everything sharing a
process.
docs: apply Vercel technical writing standards (#3704)
* docs: apply Vercel technical writing standards
Audit the complete documentation corpus, package READMEs, skills, and
source TSDoc/comments against the vercel-technical-writing skill and
style-rules.md. Normalize sentence-case headings without changing
published anchors, remove prose em dashes and filler wording, improve
active voice and self-contained phrasing, standardize product/brand
capitalization, American English, list punctuation, units, and code
fence languages, and preserve exact runtime strings/table placeholders.
All executable code is unchanged. Modified skills have their metadata
versions bumped.
* docs: extend writing audit to repository Markdown
Apply the same technical-writing rules to design documents, compiler
specifications, workbench guides, package changelogs, and the remaining
tracked Markdown outside the deployed docs corpus. Preserve historical
meaning, commands, output literals, table placeholders, and heading
anchors.
* docs: exclude generated package changelogs from audit
2026-08-21 14:24:31 -07:00
One difference affects how you read a local result: in CI each replay gets its
own Fluid invocation, while here every replay
2026-08-01 10:59:07 -07:00
of every run shares one Next.js process. world-postgres gives that process (and
docs: apply Vercel technical writing standards (#3704)
* docs: apply Vercel technical writing standards
Audit the complete documentation corpus, package READMEs, skills, and
source TSDoc/comments against the vercel-technical-writing skill and
style-rules.md. Normalize sentence-case headings without changing
published anchors, remove prose em dashes and filler wording, improve
active voice and self-contained phrasing, standardize product/brand
capitalization, American English, list punctuation, units, and code
fence languages, and preserve exact runtime strings/table placeholders.
All executable code is unchanged. Modified skills have their metadata
versions bumped.
* docs: extend writing audit to repository Markdown
Apply the same technical-writing rules to design documents, compiler
specifications, workbench guides, package changelogs, and the remaining
tracked Markdown outside the deployed docs corpus. Preserve historical
meaning, commands, output literals, table placeholders, and heading
anchors.
* docs: exclude generated package changelogs from audit
2026-08-21 14:24:31 -07:00
the harness process) 50 embedded Graphile Worker slots each, and approximately
100 replays in one heap saturates GC. Measured on a 12-core laptop, all 14
attempts came back
2026-08-01 10:59:07 -07:00
`stuck` with the server at 6.4 GB RSS and Postgres idle. The script therefore
sets `WORKFLOW_POSTGRES_WORKER_CONCURRENCY=10` (override by exporting it) and
raises the app's old-space limit (`--heap-mb` ). If a local run reports `stuck`
rather than `CORRUPTED_EVENT_LOG` , suspect the machine before the SDK.
2026-08-12 13:16:42 -07:00
world-local saturates the same single process from its own in-process queue,
docs: apply Vercel technical writing standards (#3704)
* docs: apply Vercel technical writing standards
Audit the complete documentation corpus, package READMEs, skills, and
source TSDoc/comments against the vercel-technical-writing skill and
style-rules.md. Normalize sentence-case headings without changing
published anchors, remove prose em dashes and filler wording, improve
active voice and self-contained phrasing, standardize product/brand
capitalization, American English, list punctuation, units, and code
fence languages, and preserve exact runtime strings/table placeholders.
All executable code is unchanged. Modified skills have their metadata
versions bumped.
* docs: extend writing audit to repository Markdown
Apply the same technical-writing rules to design documents, compiler
specifications, workbench guides, package changelogs, and the remaining
tracked Markdown outside the deployed docs corpus. Preserve historical
meaning, commands, output literals, table placeholders, and heading
anchors.
* docs: exclude generated package changelogs from audit
2026-08-21 14:24:31 -07:00
which defaults to 1,000 deliveries in flight, so the script holds it at the same
2026-08-12 13:16:42 -07:00
number via `WORKFLOW_LOCAL_QUEUE_CONCURRENCY` .
2026-08-21 15:31:52 -07:00
What the local lanes are * not * is a throughput bug in the two Worlds. Under
saturation world-local logged zero failed deliveries, zero handler errors and
zero exhausted messages across three 14-run passes: its semaphore parks a
message * before * the delivery fetch, so queue waiting never consumes the
transport timeout and there is no retry amplification to find. It is a bounded
FIFO doing what it says, and the ceiling it hits is one Node process serving
what the Vercel lane spreads across Fluid instances. Two things about these
Worlds are nonetheless worth fixing on their own merits, and neither is what
made the lanes red: world-local defaults to **1000 ** in-flight deliveries (the
comment above it says the limit exists to avoid overwhelming the process, and
the repro script has to override it to 10), world-postgres to 50 embedded
workers * per process * ; and neither World has world-vercel's per-run replay
serialization, which is itself opt-in there behind
`WORKFLOW_SEQUENTIAL_REPLAYS` (vercel/workflow#2193 ), so a run's concurrent
wakes each replay the whole log.
2026-08-12 13:16:42 -07:00
world-local's storms come out clean far more often than world-postgres's, so the
default scale says even less there: the corruption it does produce needs a
`hook_received` to be staged and then rejected, which the harness reaches only
in a run's terminal moments. Reach for a unit test in
`packages/world-local/src/storage/` when a suspected filesystem race can be
docs: apply Vercel technical writing standards (#3704)
* docs: apply Vercel technical writing standards
Audit the complete documentation corpus, package READMEs, skills, and
source TSDoc/comments against the vercel-technical-writing skill and
style-rules.md. Normalize sentence-case headings without changing
published anchors, remove prose em dashes and filler wording, improve
active voice and self-contained phrasing, standardize product/brand
capitalization, American English, list punctuation, units, and code
fence languages, and preserve exact runtime strings/table placeholders.
All executable code is unchanged. Modified skills have their metadata
versions bumped.
* docs: extend writing audit to repository Markdown
Apply the same technical-writing rules to design documents, compiler
specifications, workbench guides, package changelogs, and the remaining
tracked Markdown outside the deployed docs corpus. Preserve historical
meaning, commands, output literals, table placeholders, and heading
anchors.
* docs: exclude generated package changelogs from audit
2026-08-21 14:24:31 -07:00
staged directly. It costs milliseconds and does not depend on the interleaving
2026-08-12 13:16:42 -07:00
showing up.
2026-08-01 10:59:07 -07:00
In CI the same harness runs from `.github/workflows/event-log-race-repro.yml` ,
docs: apply Vercel technical writing standards (#3704)
* docs: apply Vercel technical writing standards
Audit the complete documentation corpus, package READMEs, skills, and
source TSDoc/comments against the vercel-technical-writing skill and
style-rules.md. Normalize sentence-case headings without changing
published anchors, remove prose em dashes and filler wording, improve
active voice and self-contained phrasing, standardize product/brand
capitalization, American English, list punctuation, units, and code
fence languages, and preserve exact runtime strings/table placeholders.
All executable code is unchanged. Modified skills have their metadata
versions bumped.
* docs: extend writing audit to repository Markdown
Apply the same technical-writing rules to design documents, compiler
specifications, workbench guides, package changelogs, and the remaining
tracked Markdown outside the deployed docs corpus. Preserve historical
meaning, commands, output literals, table placeholders, and heading
anchors.
* docs: exclude generated package changelogs from audit
2026-08-21 14:24:31 -07:00
triggered by adding the `event-log-race-repro` label to a PR or by
`workflow_dispatch` , whose inputs are the soak dial. Raise `timeout-minutes` in
that dispatch's branch if you raise `budget_ms` . Alongside the Vercel lane, the
2026-08-14 10:59:00 -07:00
workflow runs the local script against world-local and world-postgres as
docs: apply Vercel technical writing standards (#3704)
* docs: apply Vercel technical writing standards
Audit the complete documentation corpus, package READMEs, skills, and
source TSDoc/comments against the vercel-technical-writing skill and
style-rules.md. Normalize sentence-case headings without changing
published anchors, remove prose em dashes and filler wording, improve
active voice and self-contained phrasing, standardize product/brand
capitalization, American English, list punctuation, units, and code
fence languages, and preserve exact runtime strings/table placeholders.
All executable code is unchanged. Modified skills have their metadata
versions bumped.
* docs: extend writing audit to repository Markdown
Apply the same technical-writing rules to design documents, compiler
specifications, workbench guides, package changelogs, and the remaining
tracked Markdown outside the deployed docs corpus. Preserve historical
meaning, commands, output literals, table placeholders, and heading
anchors.
* docs: exclude generated package changelogs from audit
2026-08-21 14:24:31 -07:00
parallel lanes. Those two lanes are report-only because the local storms have red
2026-08-14 10:59:00 -07:00
baselines at the default scale (see above), so they publish numbers rather than a
verdict and fail only when the harness produced no result file at all; the Vercel
lane remains the gate.
All three lanes land in one sticky PR comment, rendered from their artifacts by
the `event-log-race-repro-comment` job: a verdict line per lane, then a history
table of one row per lane per run (total / complete / corrupt / stuck / other),
then the latest run's non-completed runs with links. Each lane's own job summary
carries the same tables for that lane alone. The comment keeps the last few runs;
older ones stay in the jobs' artifacts, which hold the full results JSON.
2026-08-01 10:59:07 -07:00
To poke at a run afterwards, the CLI reads the same world from the environment:
``` bash
WORKFLOW_TARGET_WORLD = @workflow/world-postgres \
WORKFLOW_POSTGRES_URL = postgres://world:world@localhost:5432/world \
pnpm wf inspect <run-id>
2026-08-12 13:16:42 -07:00
WORKFLOW_TARGET_WORLD = local \
WORKFLOW_LOCAL_DATA_DIR = workbench/nextjs-turbopack/.next/workflow-data \
pnpm wf inspect <run-id>
2026-08-01 10:59:07 -07:00
```
docs: apply Vercel technical writing standards (#3704)
* docs: apply Vercel technical writing standards
Audit the complete documentation corpus, package READMEs, skills, and
source TSDoc/comments against the vercel-technical-writing skill and
style-rules.md. Normalize sentence-case headings without changing
published anchors, remove prose em dashes and filler wording, improve
active voice and self-contained phrasing, standardize product/brand
capitalization, American English, list punctuation, units, and code
fence languages, and preserve exact runtime strings/table placeholders.
All executable code is unchanged. Modified skills have their metadata
versions bumped.
* docs: extend writing audit to repository Markdown
Apply the same technical-writing rules to design documents, compiler
specifications, workbench guides, package changelogs, and the remaining
tracked Markdown outside the deployed docs corpus. Preserve historical
meaning, commands, output literals, table placeholders, and heading
anchors.
* docs: exclude generated package changelogs from audit
2026-08-21 14:24:31 -07:00
### Example app development
2026-03-11 12:56:25 -07:00
``` bash
# Build workflow bundles for example app
cd workbench/example && pnpm build
# Use workflow CLI directly
cd workbench/example && pnpm workflow [ command]
cd workbench/example && pnpm wf [ command] # shorthand
```
docs: apply Vercel technical writing standards (#3704)
* docs: apply Vercel technical writing standards
Audit the complete documentation corpus, package READMEs, skills, and
source TSDoc/comments against the vercel-technical-writing skill and
style-rules.md. Normalize sentence-case headings without changing
published anchors, remove prose em dashes and filler wording, improve
active voice and self-contained phrasing, standardize product/brand
capitalization, American English, list punctuation, units, and code
fence languages, and preserve exact runtime strings/table placeholders.
All executable code is unchanged. Modified skills have their metadata
versions bumped.
* docs: extend writing audit to repository Markdown
Apply the same technical-writing rules to design documents, compiler
specifications, workbench guides, package changelogs, and the remaining
tracked Markdown outside the deployed docs corpus. Preserve historical
meaning, commands, output literals, table placeholders, and heading
anchors.
* docs: exclude generated package changelogs from audit
2026-08-21 14:24:31 -07:00
### Next.js app development
2026-03-11 12:56:25 -07:00
``` bash
# Start Next.js dev server with workflow support
cd workbench/nextjs-turbopack && pnpm dev
# Build Next.js app with workflows
cd workbench/nextjs-turbopack && pnpm build
# Production server
cd workbench/nextjs-turbopack && pnpm start
```
docs: apply Vercel technical writing standards (#3704)
* docs: apply Vercel technical writing standards
Audit the complete documentation corpus, package READMEs, skills, and
source TSDoc/comments against the vercel-technical-writing skill and
style-rules.md. Normalize sentence-case headings without changing
published anchors, remove prose em dashes and filler wording, improve
active voice and self-contained phrasing, standardize product/brand
capitalization, American English, list punctuation, units, and code
fence languages, and preserve exact runtime strings/table placeholders.
All executable code is unchanged. Modified skills have their metadata
versions bumped.
* docs: extend writing audit to repository Markdown
Apply the same technical-writing rules to design documents, compiler
specifications, workbench guides, package changelogs, and the remaining
tracked Markdown outside the deployed docs corpus. Preserve historical
meaning, commands, output literals, table placeholders, and heading
anchors.
* docs: exclude generated package changelogs from audit
2026-08-21 14:24:31 -07:00
## Key workflow concepts
2026-03-11 12:56:25 -07:00
2026-03-29 16:05:39 -07:00
**These are only relevant when writing code using the Workflow SDK **
2026-03-11 12:56:25 -07:00
- Workflow functions orchestrate step execution but have limited runtime access
- Step functions handle side effects, API calls, and complex logic with full Node.js access
- All function inputs/outputs are serialized to the event log for replay
- Built-in retry semantics for step functions with `FatalError` /`RetryableError` controls
- Standard JavaScript async patterns work: `Promise.all()` , `Promise.race()` , etc.
docs: apply Vercel technical writing standards (#3704)
* docs: apply Vercel technical writing standards
Audit the complete documentation corpus, package READMEs, skills, and
source TSDoc/comments against the vercel-technical-writing skill and
style-rules.md. Normalize sentence-case headings without changing
published anchors, remove prose em dashes and filler wording, improve
active voice and self-contained phrasing, standardize product/brand
capitalization, American English, list punctuation, units, and code
fence languages, and preserve exact runtime strings/table placeholders.
All executable code is unchanged. Modified skills have their metadata
versions bumped.
* docs: extend writing audit to repository Markdown
Apply the same technical-writing rules to design documents, compiler
specifications, workbench guides, package changelogs, and the remaining
tracked Markdown outside the deployed docs corpus. Preserve historical
meaning, commands, output literals, table placeholders, and heading
anchors.
* docs: exclude generated package changelogs from audit
2026-08-21 14:24:31 -07:00
## File structure conventions
2026-03-11 12:56:25 -07:00
2026-03-29 16:05:39 -07:00
**These are only relevant when writing code using the Workflow SDK **
2026-03-11 12:56:25 -07:00
- Workflow files go in `workflows/` directory (or `src/workflows/` if using src)
- Generated API routes appear in `app/.well-known/workflow/v1/` (Next.js integration)
- Workflow files must contain `"use workflow"` or `"use step"` directives to be processed
- Add `.swc` directory to `.gitignore` for SWC plugin cache artifacts
docs: apply Vercel technical writing standards (#3704)
* docs: apply Vercel technical writing standards
Audit the complete documentation corpus, package READMEs, skills, and
source TSDoc/comments against the vercel-technical-writing skill and
style-rules.md. Normalize sentence-case headings without changing
published anchors, remove prose em dashes and filler wording, improve
active voice and self-contained phrasing, standardize product/brand
capitalization, American English, list punctuation, units, and code
fence languages, and preserve exact runtime strings/table placeholders.
All executable code is unchanged. Modified skills have their metadata
versions bumped.
* docs: extend writing audit to repository Markdown
Apply the same technical-writing rules to design documents, compiler
specifications, workbench guides, package changelogs, and the remaining
tracked Markdown outside the deployed docs corpus. Preserve historical
meaning, commands, output literals, table placeholders, and heading
anchors.
* docs: exclude generated package changelogs from audit
2026-08-21 14:24:31 -07:00
## Package manager
2026-03-11 12:56:25 -07:00
This project uses pnpm with workspace configuration. The required version is specified in `package.json#packageManager` .
docs: apply Vercel technical writing standards (#3704)
* docs: apply Vercel technical writing standards
Audit the complete documentation corpus, package READMEs, skills, and
source TSDoc/comments against the vercel-technical-writing skill and
style-rules.md. Normalize sentence-case headings without changing
published anchors, remove prose em dashes and filler wording, improve
active voice and self-contained phrasing, standardize product/brand
capitalization, American English, list punctuation, units, and code
fence languages, and preserve exact runtime strings/table placeholders.
All executable code is unchanged. Modified skills have their metadata
versions bumped.
* docs: extend writing audit to repository Markdown
Apply the same technical-writing rules to design documents, compiler
specifications, workbench guides, package changelogs, and the remaining
tracked Markdown outside the deployed docs corpus. Preserve historical
meaning, commands, output literals, table placeholders, and heading
anchors.
* docs: exclude generated package changelogs from audit
2026-08-21 14:24:31 -07:00
## Code style
2026-03-11 12:56:25 -07:00
- Uses Biome for formatting and linting
- 2-space indentation, single quotes, trailing commas (ES5)
- Import type enforcement enabled
- Explicit `any` is discouraged (Biome's `noExplicitAny` rule is currently disabled); exhaustive dependencies warnings enabled
docs: apply Vercel technical writing standards (#3704)
* docs: apply Vercel technical writing standards
Audit the complete documentation corpus, package READMEs, skills, and
source TSDoc/comments against the vercel-technical-writing skill and
style-rules.md. Normalize sentence-case headings without changing
published anchors, remove prose em dashes and filler wording, improve
active voice and self-contained phrasing, standardize product/brand
capitalization, American English, list punctuation, units, and code
fence languages, and preserve exact runtime strings/table placeholders.
All executable code is unchanged. Modified skills have their metadata
versions bumped.
* docs: extend writing audit to repository Markdown
Apply the same technical-writing rules to design documents, compiler
specifications, workbench guides, package changelogs, and the remaining
tracked Markdown outside the deployed docs corpus. Preserve historical
meaning, commands, output literals, table placeholders, and heading
anchors.
* docs: exclude generated package changelogs from audit
2026-08-21 14:24:31 -07:00
## Local checks vs. CI
2026-07-21 12:55:21 +07:00
docs: apply Vercel technical writing standards (#3704)
* docs: apply Vercel technical writing standards
Audit the complete documentation corpus, package READMEs, skills, and
source TSDoc/comments against the vercel-technical-writing skill and
style-rules.md. Normalize sentence-case headings without changing
published anchors, remove prose em dashes and filler wording, improve
active voice and self-contained phrasing, standardize product/brand
capitalization, American English, list punctuation, units, and code
fence languages, and preserve exact runtime strings/table placeholders.
All executable code is unchanged. Modified skills have their metadata
versions bumped.
* docs: extend writing audit to repository Markdown
Apply the same technical-writing rules to design documents, compiler
specifications, workbench guides, package changelogs, and the remaining
tracked Markdown outside the deployed docs corpus. Preserve historical
meaning, commands, output literals, table placeholders, and heading
anchors.
* docs: exclude generated package changelogs from audit
2026-08-21 14:24:31 -07:00
Linting, formatting, and typechecking (`pnpm lint` , `pnpm format` , `pnpm typecheck` ) are all facets of the same static-quality gate, and CI runs them on every PR. Treat them as **advisory ** while working locally: run them and fix obvious issues when it's convenient, but a failure in any of them should **not ** block you from committing, pushing, or opening a PR. CI is the source of truth and will report anything that matters. Don't get stuck iterating locally to make these pass before handing off.
2026-07-21 12:55:21 +07:00
2026-08-25 13:06:49 -07:00
## Bundle size
`.github/workflows/bundle-size.yml` builds the `nextjs-turbopack` and `hono` workbench apps on every PR, measures the `/.well-known/workflow/v1/flow` route, and posts a sticky comment with the delta against `main` . Pushes to `main` exist to produce the baseline artifacts that PR runs download.
It reports two numbers per app, because neither app emits an isolable function bundle for that route (Next.js emits a ~1 KB turbopack chunk loader pointing at chunks shared with other routes; nitro inlines the handler into a single server entry):
- **Gated**: what the workflow builders emit for the flow route, before the framework bundles it. Growth beyond `max(2%, 50 KiB)` raw fails the job. Add the `allow-bundle-size-growth` label to accept it.
- **Informational**: the framework's own build output. Unrelated changes move it, so it never gates.
The comment is a single table showing **gzip ** sizes with the change against `main` in parentheses, because that is the number worth reading at a glance. Everything else, including what gates the job, sits in a collapsed block below it. The gate compares **raw ** bytes, which is what the runtime parses on a cold start, so a red check can sit next to a small gzip delta; the collapsed block says so.
The two are only ever compared against their own baselines, never against each other, and neither alone is the deployed function: the gated bundle is the VM code the route carries as an inline string, while the code hosting it sits in the framework output.
**The gate does not cover the world adapters. ** Building `nextjs-turbopack` with `WORKFLOW_TARGET_WORLD=local` and `=vercel` produces byte-identical reports on all three metrics, because every world the app depends on is bundled into the framework output either way and the choice is made at runtime. A change confined to `@workflow/world-vercel` will not move the gated numbers.
The job pins `WORKFLOW_SOURCEMAP` , `WORKFLOW_PUBLIC_MANIFEST` , and `WORKFLOW_TARGET_WORLD` , and records them in each report's fingerprint; the renderer refuses to diff reports whose fingerprints disagree. `WORKFLOW_SOURCEMAP=false` is the one that moves the numbers, since sourcemap mode defaults to inline outside a production build and that alone takes the Next flow bundle from 1.38 MB to 5.85 MB. Changing any pin invalidates comparisons against older baselines.
docs: apply Vercel technical writing standards (#3704)
* docs: apply Vercel technical writing standards
Audit the complete documentation corpus, package READMEs, skills, and
source TSDoc/comments against the vercel-technical-writing skill and
style-rules.md. Normalize sentence-case headings without changing
published anchors, remove prose em dashes and filler wording, improve
active voice and self-contained phrasing, standardize product/brand
capitalization, American English, list punctuation, units, and code
fence languages, and preserve exact runtime strings/table placeholders.
All executable code is unchanged. Modified skills have their metadata
versions bumped.
* docs: extend writing audit to repository Markdown
Apply the same technical-writing rules to design documents, compiler
specifications, workbench guides, package changelogs, and the remaining
tracked Markdown outside the deployed docs corpus. Preserve historical
meaning, commands, output literals, table placeholders, and heading
anchors.
* docs: exclude generated package changelogs from audit
2026-08-21 14:24:31 -07:00
## Documentation standards
2026-03-11 12:56:25 -07:00
- README.md files in each package must accurately reflect the current functionality and purpose of that package
- READMEs should not contain outdated or incorrect information about package capabilities
- When modifying package functionality, ensure corresponding README updates are included
2026-07-07 17:56:41 -07:00
- Document every user-configurable environment variable in the docs.
2026-03-11 12:56:25 -07:00
- When modifying skill files in `skills/` , always bump the `version` field in the frontmatter metadata
docs: apply Vercel technical writing standards (#3704)
* docs: apply Vercel technical writing standards
Audit the complete documentation corpus, package READMEs, skills, and
source TSDoc/comments against the vercel-technical-writing skill and
style-rules.md. Normalize sentence-case headings without changing
published anchors, remove prose em dashes and filler wording, improve
active voice and self-contained phrasing, standardize product/brand
capitalization, American English, list punctuation, units, and code
fence languages, and preserve exact runtime strings/table placeholders.
All executable code is unchanged. Modified skills have their metadata
versions bumped.
* docs: extend writing audit to repository Markdown
Apply the same technical-writing rules to design documents, compiler
specifications, workbench guides, package changelogs, and the remaining
tracked Markdown outside the deployed docs corpus. Preserve historical
meaning, commands, output literals, table placeholders, and heading
anchors.
* docs: exclude generated package changelogs from audit
2026-08-21 14:24:31 -07:00
### Docs preview links in PR descriptions
2026-06-11 15:12:06 -07:00
When a PR adds or updates docs pages (anything under `docs/content/` ), add a "Docs Preview" section to the PR description with direct links to each changed page on the `workflow-docs` preview deployment:
docs: apply Vercel technical writing standards (#3704)
* docs: apply Vercel technical writing standards
Audit the complete documentation corpus, package READMEs, skills, and
source TSDoc/comments against the vercel-technical-writing skill and
style-rules.md. Normalize sentence-case headings without changing
published anchors, remove prose em dashes and filler wording, improve
active voice and self-contained phrasing, standardize product/brand
capitalization, American English, list punctuation, units, and code
fence languages, and preserve exact runtime strings/table placeholders.
All executable code is unchanged. Modified skills have their metadata
versions bumped.
* docs: extend writing audit to repository Markdown
Apply the same technical-writing rules to design documents, compiler
specifications, workbench guides, package changelogs, and the remaining
tracked Markdown outside the deployed docs corpus. Preserve historical
meaning, commands, output literals, table placeholders, and heading
anchors.
* docs: exclude generated package changelogs from audit
2026-08-21 14:24:31 -07:00
- Get the preview base URL from the `vercel[bot]` comment on the PR. Use the Preview link from the `workflow-docs` project row (e.g. `https://workflow-docs-git-<branch-slug>.vercel.sh` ). Don't construct the URL by hand because Vercel's branch-slug normalization is not a direct substitution.
2026-08-21 12:45:05 -07:00
- Map content paths to routes: `docs/content/docs/v5/<path>.mdx` is served at `/docs/<path>` (v5 is the default/latest version) and `docs/content/docs/v4/<path>.mdx` at `/v4/docs/<path>` (v4 is the maintenance version).
2026-06-11 15:12:06 -07:00
- When a change is scoped to a specific section of a page, link to its heading anchor (e.g. `/docs/foundations/hooks#checking-for-token-conflicts` ) and verify the anchor matches a real heading in the MDX.
docs: apply Vercel technical writing standards (#3704)
* docs: apply Vercel technical writing standards
Audit the complete documentation corpus, package READMEs, skills, and
source TSDoc/comments against the vercel-technical-writing skill and
style-rules.md. Normalize sentence-case headings without changing
published anchors, remove prose em dashes and filler wording, improve
active voice and self-contained phrasing, standardize product/brand
capitalization, American English, list punctuation, units, and code
fence languages, and preserve exact runtime strings/table placeholders.
All executable code is unchanged. Modified skills have their metadata
versions bumped.
* docs: extend writing audit to repository Markdown
Apply the same technical-writing rules to design documents, compiler
specifications, workbench guides, package changelogs, and the remaining
tracked Markdown outside the deployed docs corpus. Preserve historical
meaning, commands, output literals, table placeholders, and heading
anchors.
* docs: exclude generated package changelogs from audit
2026-08-21 14:24:31 -07:00
- A table with one row per page (and one column per docs version, when both v4 and v5 were updated) works well.
- The preview deployment sits behind deployment protection, so the links require Vercel team access. This is expected; include them anyway for reviewers.
2026-06-11 15:12:06 -07:00
docs: apply Vercel technical writing standards (#3704)
* docs: apply Vercel technical writing standards
Audit the complete documentation corpus, package READMEs, skills, and
source TSDoc/comments against the vercel-technical-writing skill and
style-rules.md. Normalize sentence-case headings without changing
published anchors, remove prose em dashes and filler wording, improve
active voice and self-contained phrasing, standardize product/brand
capitalization, American English, list punctuation, units, and code
fence languages, and preserve exact runtime strings/table placeholders.
All executable code is unchanged. Modified skills have their metadata
versions bumped.
* docs: extend writing audit to repository Markdown
Apply the same technical-writing rules to design documents, compiler
specifications, workbench guides, package changelogs, and the remaining
tracked Markdown outside the deployed docs corpus. Preserve historical
meaning, commands, output literals, table placeholders, and heading
anchors.
* docs: exclude generated package changelogs from audit
2026-08-21 14:24:31 -07:00
## SWC plugin
2026-01-20 12:24:11 -08:00
When modifying the SWC compiler plugin (`packages/swc-plugin-workflow` ), you must also update the specification document at `packages/swc-plugin-workflow/spec.md` to reflect any changes to the transformation behavior.
2026-03-11 12:56:25 -07:00
docs: apply Vercel technical writing standards (#3704)
* docs: apply Vercel technical writing standards
Audit the complete documentation corpus, package READMEs, skills, and
source TSDoc/comments against the vercel-technical-writing skill and
style-rules.md. Normalize sentence-case headings without changing
published anchors, remove prose em dashes and filler wording, improve
active voice and self-contained phrasing, standardize product/brand
capitalization, American English, list punctuation, units, and code
fence languages, and preserve exact runtime strings/table placeholders.
All executable code is unchanged. Modified skills have their metadata
versions bumped.
* docs: extend writing audit to repository Markdown
Apply the same technical-writing rules to design documents, compiler
specifications, workbench guides, package changelogs, and the remaining
tracked Markdown outside the deployed docs corpus. Preserve historical
meaning, commands, output literals, table placeholders, and heading
anchors.
* docs: exclude generated package changelogs from audit
2026-08-21 14:24:31 -07:00
## Versioning & release strategy
2026-03-11 12:56:25 -07:00
2026-04-08 13:02:21 -07:00
This repository uses a dual-branch release model with [changesets ](https://github.com/changesets/changesets ) for version management.
docs: apply Vercel technical writing standards (#3704)
* docs: apply Vercel technical writing standards
Audit the complete documentation corpus, package READMEs, skills, and
source TSDoc/comments against the vercel-technical-writing skill and
style-rules.md. Normalize sentence-case headings without changing
published anchors, remove prose em dashes and filler wording, improve
active voice and self-contained phrasing, standardize product/brand
capitalization, American English, list punctuation, units, and code
fence languages, and preserve exact runtime strings/table placeholders.
All executable code is unchanged. Modified skills have their metadata
versions bumped.
* docs: extend writing audit to repository Markdown
Apply the same technical-writing rules to design documents, compiler
specifications, workbench guides, package changelogs, and the remaining
tracked Markdown outside the deployed docs corpus. Preserve historical
meaning, commands, output literals, table placeholders, and heading
anchors.
* docs: exclude generated package changelogs from audit
2026-08-21 14:24:31 -07:00
### Branch model
2026-04-08 13:02:21 -07:00
docs: apply Vercel technical writing standards (#3704)
* docs: apply Vercel technical writing standards
Audit the complete documentation corpus, package READMEs, skills, and
source TSDoc/comments against the vercel-technical-writing skill and
style-rules.md. Normalize sentence-case headings without changing
published anchors, remove prose em dashes and filler wording, improve
active voice and self-contained phrasing, standardize product/brand
capitalization, American English, list punctuation, units, and code
fence languages, and preserve exact runtime strings/table placeholders.
All executable code is unchanged. Modified skills have their metadata
versions bumped.
* docs: extend writing audit to repository Markdown
Apply the same technical-writing rules to design documents, compiler
specifications, workbench guides, package changelogs, and the remaining
tracked Markdown outside the deployed docs corpus. Preserve historical
meaning, commands, output literals, table placeholders, and heading
anchors.
* docs: exclude generated package changelogs from audit
2026-08-21 14:24:31 -07:00
- **`main` **: Bleeding-edge / beta channel. Changesets are in pre-release mode (`beta` tag). Published packages get the `beta` npm dist-tag (e.g. `5.0.0-beta.3` ).
- **`stable` **: GA / production channel. Changesets are in regular mode. Published packages get the `latest` npm dist-tag (e.g. `4.2.1` ).
2026-04-08 13:02:21 -07:00
Both branches trigger the release workflow (`.github/workflows/release.yml` ) on push. The changesets action creates a "Version Packages" PR on each branch when there are pending changesets.
2026-04-17 11:10:17 -07:00
**Important: ** Some directories are not fully maintained on the `stable` branch:
docs: apply Vercel technical writing standards (#3704)
* docs: apply Vercel technical writing standards
Audit the complete documentation corpus, package READMEs, skills, and
source TSDoc/comments against the vercel-technical-writing skill and
style-rules.md. Normalize sentence-case headings without changing
published anchors, remove prose em dashes and filler wording, improve
active voice and self-contained phrasing, standardize product/brand
capitalization, American English, list punctuation, units, and code
fence languages, and preserve exact runtime strings/table placeholders.
All executable code is unchanged. Modified skills have their metadata
versions bumped.
* docs: extend writing audit to repository Markdown
Apply the same technical-writing rules to design documents, compiler
specifications, workbench guides, package changelogs, and the remaining
tracked Markdown outside the deployed docs corpus. Preserve historical
meaning, commands, output literals, table placeholders, and heading
anchors.
* docs: exclude generated package changelogs from audit
2026-08-21 14:24:31 -07:00
- **`docs/` **: Only `docs/content/` is actively maintained on `stable` ; the rest of the docs app is a minimal placeholder (documentation is deployed only from `main` ). `docs/content/` is kept on `stable` because the markdown files are bundled into npm packages via `prepack` scripts.
2026-04-17 11:10:17 -07:00
- **`skills/` **: Not maintained on `stable` at all. Skill files are unrelated to npm packaging, so there is no reason to keep them in sync on the release branch.
When backporting changes to `stable` , any conflicts involving docs app files (outside of `docs/content/` ) or `skills/` files should be resolved by keeping the `stable` branch version (discarding the incoming change from `main` ). Conflicts in `docs/content/` should be resolved normally. The backport GitHub Action handles this automatically.
2026-04-16 14:15:13 -07:00
ci: stop deploying changeset-release/main, run its e2e against production (#3243)
* ci: stop deploying changeset-release/main, run its e2e against production
The changesets action force-pushes `changeset-release/main`, and it can
point at exactly main's HEAD SHA. Vercel keeps one commit status per
project per SHA, so when both a production deployment (from main) and a
preview deployment (from changeset-release/main) are built for the same
commit, whichever finishes last owns the status. On 2026-07-30 the
preview finished last, so `vercel/wait-for-deployment-action` — which
reads the deployment ID out of that status — handed production e2e runs
a preview deployment ID and forked runs across environments.
Disable git deployments for that branch in every Vercel project rooted
in this repo, and give the changeset PR's Vercel e2e lanes a deployment
to test that actually exists: main's production deployment for the PR's
base SHA, resolved by SHA so a mid-flight production build is waited out
rather than silently replaced by an older one.
Signed-off-by: Pranay Prakash <pranay.gp@gmail.com>
* ci: resolve changeset-release e2e deployments with the wait action, tokenless
Per review: with changeset-release/main no longer deployed, main SHAs
can never again be deployed to a second environment of these projects,
so the per-SHA commit status the action reads is unambiguous for
exactly this lane. Reuse vercel/wait-for-deployment-action with
environment: production and sha pinned to the PR base SHA instead of
the Vercel-API polling script, drop the script and its VERCEL_TOKEN
usage, and inherit the action's inactive/skipped-build handling.
Signed-off-by: Pranay Prakash <pranay.gp@gmail.com>
---------
Signed-off-by: Pranay Prakash <pranay.gp@gmail.com>
2026-07-31 10:09:36 -07:00
#### The `changeset-release/main` branch is never deployed
Every Vercel project rooted in this repo sets `git.deploymentEnabled` to `false` for `changeset-release/main` in its `vercel.json` . **When you add a new Vercel project, add that key to its `vercel.json` too. **
docs: apply Vercel technical writing standards (#3704)
* docs: apply Vercel technical writing standards
Audit the complete documentation corpus, package READMEs, skills, and
source TSDoc/comments against the vercel-technical-writing skill and
style-rules.md. Normalize sentence-case headings without changing
published anchors, remove prose em dashes and filler wording, improve
active voice and self-contained phrasing, standardize product/brand
capitalization, American English, list punctuation, units, and code
fence languages, and preserve exact runtime strings/table placeholders.
All executable code is unchanged. Modified skills have their metadata
versions bumped.
* docs: extend writing audit to repository Markdown
Apply the same technical-writing rules to design documents, compiler
specifications, workbench guides, package changelogs, and the remaining
tracked Markdown outside the deployed docs corpus. Preserve historical
meaning, commands, output literals, table placeholders, and heading
anchors.
* docs: exclude generated package changelogs from audit
2026-08-21 14:24:31 -07:00
The changesets action force-pushes `changeset-release/main` , and it can point at exactly main's HEAD SHA. Vercel keeps one commit status per project per SHA, so a preview deployment of that branch overwrites the production deployment's status for the same commit. `vercel/wait-for-deployment-action` , which reads the deployment ID out of that status, then hands a production e2e run a preview deployment ID, forking the run across environments.
ci: stop deploying changeset-release/main, run its e2e against production (#3243)
* ci: stop deploying changeset-release/main, run its e2e against production
The changesets action force-pushes `changeset-release/main`, and it can
point at exactly main's HEAD SHA. Vercel keeps one commit status per
project per SHA, so when both a production deployment (from main) and a
preview deployment (from changeset-release/main) are built for the same
commit, whichever finishes last owns the status. On 2026-07-30 the
preview finished last, so `vercel/wait-for-deployment-action` — which
reads the deployment ID out of that status — handed production e2e runs
a preview deployment ID and forked runs across environments.
Disable git deployments for that branch in every Vercel project rooted
in this repo, and give the changeset PR's Vercel e2e lanes a deployment
to test that actually exists: main's production deployment for the PR's
base SHA, resolved by SHA so a mid-flight production build is waited out
rather than silently replaced by an older one.
Signed-off-by: Pranay Prakash <pranay.gp@gmail.com>
* ci: resolve changeset-release e2e deployments with the wait action, tokenless
Per review: with changeset-release/main no longer deployed, main SHAs
can never again be deployed to a second environment of these projects,
so the per-SHA commit status the action reads is unambiguous for
exactly this lane. Reuse vercel/wait-for-deployment-action with
environment: production and sha pinned to the PR base SHA instead of
the Vercel-API polling script, drop the script and its VERCEL_TOKEN
usage, and inherit the action's inactive/skipped-build handling.
Signed-off-by: Pranay Prakash <pranay.gp@gmail.com>
---------
Signed-off-by: Pranay Prakash <pranay.gp@gmail.com>
2026-07-31 10:09:36 -07:00
docs: apply Vercel technical writing standards (#3704)
* docs: apply Vercel technical writing standards
Audit the complete documentation corpus, package READMEs, skills, and
source TSDoc/comments against the vercel-technical-writing skill and
style-rules.md. Normalize sentence-case headings without changing
published anchors, remove prose em dashes and filler wording, improve
active voice and self-contained phrasing, standardize product/brand
capitalization, American English, list punctuation, units, and code
fence languages, and preserve exact runtime strings/table placeholders.
All executable code is unchanged. Modified skills have their metadata
versions bumped.
* docs: extend writing audit to repository Markdown
Apply the same technical-writing rules to design documents, compiler
specifications, workbench guides, package changelogs, and the remaining
tracked Markdown outside the deployed docs corpus. Preserve historical
meaning, commands, output literals, table placeholders, and heading
anchors.
* docs: exclude generated package changelogs from audit
2026-08-21 14:24:31 -07:00
Because those PRs have no deployment of their own, CI treats them specially: the Vercel e2e lanes in `tests.yml` run `vercel/wait-for-deployment-action` a second way, with `environment: production` and `sha` pinned to the PR's base SHA. They therefore test main's production deployment and run as `production` . (The commit-status ID that action reads is unambiguous for main SHAs precisely because this repo no longer deploys `changeset-release/main` , the only branch that ever deployed a commit main also deployed.) The deployment-dependent jobs in `docs-checks.yml` , `tarballs-checks.yml` , and `benchmarks.yml` are skipped. Anything new that waits on a deployment needs the same treatment.
ci: stop deploying changeset-release/main, run its e2e against production (#3243)
* ci: stop deploying changeset-release/main, run its e2e against production
The changesets action force-pushes `changeset-release/main`, and it can
point at exactly main's HEAD SHA. Vercel keeps one commit status per
project per SHA, so when both a production deployment (from main) and a
preview deployment (from changeset-release/main) are built for the same
commit, whichever finishes last owns the status. On 2026-07-30 the
preview finished last, so `vercel/wait-for-deployment-action` — which
reads the deployment ID out of that status — handed production e2e runs
a preview deployment ID and forked runs across environments.
Disable git deployments for that branch in every Vercel project rooted
in this repo, and give the changeset PR's Vercel e2e lanes a deployment
to test that actually exists: main's production deployment for the PR's
base SHA, resolved by SHA so a mid-flight production build is waited out
rather than silently replaced by an older one.
Signed-off-by: Pranay Prakash <pranay.gp@gmail.com>
* ci: resolve changeset-release e2e deployments with the wait action, tokenless
Per review: with changeset-release/main no longer deployed, main SHAs
can never again be deployed to a second environment of these projects,
so the per-SHA commit status the action reads is unambiguous for
exactly this lane. Reuse vercel/wait-for-deployment-action with
environment: production and sha pinned to the PR base SHA instead of
the Vercel-API polling script, drop the script and its VERCEL_TOKEN
usage, and inherit the action's inactive/skipped-build handling.
Signed-off-by: Pranay Prakash <pranay.gp@gmail.com>
---------
Signed-off-by: Pranay Prakash <pranay.gp@gmail.com>
2026-07-31 10:09:36 -07:00
2026-04-08 13:02:21 -07:00
### Changesets
docs: apply Vercel technical writing standards (#3704)
* docs: apply Vercel technical writing standards
Audit the complete documentation corpus, package READMEs, skills, and
source TSDoc/comments against the vercel-technical-writing skill and
style-rules.md. Normalize sentence-case headings without changing
published anchors, remove prose em dashes and filler wording, improve
active voice and self-contained phrasing, standardize product/brand
capitalization, American English, list punctuation, units, and code
fence languages, and preserve exact runtime strings/table placeholders.
All executable code is unchanged. Modified skills have their metadata
versions bumped.
* docs: extend writing audit to repository Markdown
Apply the same technical-writing rules to design documents, compiler
specifications, workbench guides, package changelogs, and the remaining
tracked Markdown outside the deployed docs corpus. Preserve historical
meaning, commands, output literals, table placeholders, and heading
anchors.
* docs: exclude generated package changelogs from audit
2026-08-21 14:24:31 -07:00
- `workflow` and `@workflow/core` use changesets' "fixed" versioning strategy, so they always have the same version number
2026-03-11 12:56:25 -07:00
- Every PR requires a changeset to be included before it will be merged
- To check if one is needed, run `pnpm changeset status --since=main >/dev/null 2>&1 && echo "no changeset needed" || echo "changeset needed"`
- Create a changeset using `pnpm changeset add`
- All changed packages should be included in the changeset. Never include unchanged packages.
2026-09-03 17:02:00 -07:00
- Never list a package from the `ignore` array in `.changeset/config.json` (private workbench and simulation packages such as `@workflow/world-sim` ), even when the PR changes it. Changesets rejects a changeset that mixes ignored and published packages, and the failure only surfaces in the Release job on `main` . `node scripts/check-changesets.mjs` runs that validation locally; CI runs it in `lint.yml` .
2026-04-08 13:02:21 -07:00
- Use the correct semver bump type: `patch` for bug fixes, `minor` for new features, `major` for breaking changes
- On `main` (pre-release mode), the bump type doesn't affect beta numbering (it always increments `beta.N` ) but it **does matter ** when changes are backported to `stable`
2026-03-11 12:56:25 -07:00
- Remember to always build any packages that get changed before running downstream tests like e2e tests in the workbench
- Remember that changes made to one workbench should propagate to all other workbenches. The workflows should typically only be written once inside the example workbench and symlinked into all the other workbenches
docs: apply Vercel technical writing standards (#3704)
* docs: apply Vercel technical writing standards
Audit the complete documentation corpus, package READMEs, skills, and
source TSDoc/comments against the vercel-technical-writing skill and
style-rules.md. Normalize sentence-case headings without changing
published anchors, remove prose em dashes and filler wording, improve
active voice and self-contained phrasing, standardize product/brand
capitalization, American English, list punctuation, units, and code
fence languages, and preserve exact runtime strings/table placeholders.
All executable code is unchanged. Modified skills have their metadata
versions bumped.
* docs: extend writing audit to repository Markdown
Apply the same technical-writing rules to design documents, compiler
specifications, workbench guides, package changelogs, and the remaining
tracked Markdown outside the deployed docs corpus. Preserve historical
meaning, commands, output literals, table placeholders, and heading
anchors.
* docs: exclude generated package changelogs from audit
2026-08-21 14:24:31 -07:00
- When writing changesets (via `pnpm changeset add` from the repo root, as noted above), keep the description terse: one sentence, or two at most. Try to make changesets that are specific to each modified package so they are targeted.
2026-03-11 12:56:25 -07:00
2026-04-08 13:02:21 -07:00
### Backporting to `stable`
docs: apply Vercel technical writing standards (#3704)
* docs: apply Vercel technical writing standards
Audit the complete documentation corpus, package READMEs, skills, and
source TSDoc/comments against the vercel-technical-writing skill and
style-rules.md. Normalize sentence-case headings without changing
published anchors, remove prose em dashes and filler wording, improve
active voice and self-contained phrasing, standardize product/brand
capitalization, American English, list punctuation, units, and code
fence languages, and preserve exact runtime strings/table placeholders.
All executable code is unchanged. Modified skills have their metadata
versions bumped.
* docs: extend writing audit to repository Markdown
Apply the same technical-writing rules to design documents, compiler
specifications, workbench guides, package changelogs, and the remaining
tracked Markdown outside the deployed docs corpus. Preserve historical
meaning, commands, output literals, table placeholders, and heading
anchors.
* docs: exclude generated package changelogs from audit
2026-08-21 14:24:31 -07:00
Backports are handled by a GitHub Action (`.github/workflows/backport.yml` ) that runs on every push to `main` . For each commit, AI analyzes the change and decides whether to recommend a backport. The action **always opens a PR ** against `stable` for human review; it never pushes directly. The changeset file is included in the cherry-pick, so the correct semver bump type is preserved on `stable` .
2026-04-08 13:02:21 -07:00
docs: apply Vercel technical writing standards (#3704)
* docs: apply Vercel technical writing standards
Audit the complete documentation corpus, package READMEs, skills, and
source TSDoc/comments against the vercel-technical-writing skill and
style-rules.md. Normalize sentence-case headings without changing
published anchors, remove prose em dashes and filler wording, improve
active voice and self-contained phrasing, standardize product/brand
capitalization, American English, list punctuation, units, and code
fence languages, and preserve exact runtime strings/table placeholders.
All executable code is unchanged. Modified skills have their metadata
versions bumped.
* docs: extend writing audit to repository Markdown
Apply the same technical-writing rules to design documents, compiler
specifications, workbench guides, package changelogs, and the remaining
tracked Markdown outside the deployed docs corpus. Preserve historical
meaning, commands, output literals, table placeholders, and heading
anchors.
* docs: exclude generated package changelogs from audit
2026-08-21 14:24:31 -07:00
**Decision criteria. ** `stable` is a maintenance branch and takes **stability fixes only ** . Feature work stays on `main` , however small or cleanly it would cherry-pick. AI is instructed to recommend a backport only for:
2026-05-05 00:44:31 -07:00
2026-07-24 14:29:50 -07:00
- Bug fixes to functionality that already exists on `stable`
- Correctness, data-loss, crash, hang, deadlock, and resource-leak fixes
- Security fixes, including dependency bumps that address a known vulnerability
- Fixes for regressions introduced by an earlier backport
- Test-only changes covering behavior that also exists on `stable` , and flaky-test fixes
- Build/CI/release-plumbing fixes needed to keep `stable` buildable and releasable
- Documentation corrections for content already on `stable` (fixing what's wrong, not documenting new capabilities)
2026-05-05 00:44:31 -07:00
2026-07-24 14:29:50 -07:00
AI is told to recommend AGAINST backporting anything else: new features and feature enhancements (including small, self-contained, additive ones), performance work and refactors that aren't fixing a user-visible defect, non-defect behavior changes to existing APIs, changes that build on `main` -only APIs, breaking changes for the next major, routine non-security dependency bumps, changes confined to directories not maintained on `stable` (the `docs/` app outside `docs/content/` , and `skills/` ), and release plumbing like changeset/version-bump commits. Commits mixing a fix with feature work are declined, with the fix identified in the reasoning so a human can split it out.
When in doubt, AI is told to decline: a missed fix can be forced through later via `workflow_dispatch` , while unwanted change on `stable` costs its users the stability they stayed behind for.
2026-05-05 00:44:31 -07:00
docs: apply Vercel technical writing standards (#3704)
* docs: apply Vercel technical writing standards
Audit the complete documentation corpus, package READMEs, skills, and
source TSDoc/comments against the vercel-technical-writing skill and
style-rules.md. Normalize sentence-case headings without changing
published anchors, remove prose em dashes and filler wording, improve
active voice and self-contained phrasing, standardize product/brand
capitalization, American English, list punctuation, units, and code
fence languages, and preserve exact runtime strings/table placeholders.
All executable code is unchanged. Modified skills have their metadata
versions bumped.
* docs: extend writing audit to repository Markdown
Apply the same technical-writing rules to design documents, compiler
specifications, workbench guides, package changelogs, and the remaining
tracked Markdown outside the deployed docs corpus. Preserve historical
meaning, commands, output literals, table placeholders, and heading
anchors.
* docs: exclude generated package changelogs from audit
2026-08-21 14:24:31 -07:00
**Manual override. ** The workflow can be run manually from the GitHub Actions UI via `workflow_dispatch` , which accepts an optional `ref` input (a commit SHA on `main` ; defaults to `main` HEAD) and an optional `model` input (the AI model used for AI-assisted decisions and conflict resolution, in `<provider>/<model>` form; defaults to the workflow's current default). Manual dispatch always forces a backport (skipping AI analysis). Use this when AI declined a backport that you want to ship to `stable` .
2026-05-05 00:44:31 -07:00
2026-05-12 10:37:35 -07:00
**No-backport notification. ** When AI decides against a backport, it leaves a comment on the source PR (if one is associated with the commit) explaining its reasoning, with instructions for forcing a backport via `workflow_dispatch` .
2026-05-05 00:44:31 -07:00
**Conflict handling. ** If the cherry-pick fails due to conflicts, the action first auto-resolves conflicts in directories that are not maintained on `stable` (docs app files under `docs/` except `docs/content/` , and any files under `skills/` ) by keeping the `stable` branch version. It also auto-resolves `pnpm-lock.yaml` conflicts by re-running `pnpm install` . Any remaining conflicts are resolved using [opencode ](https://opencode.ai ) (AI-powered conflict resolution); the resulting backport PR notes that conflicts were AI-resolved and must be reviewed carefully. If AI cannot resolve the conflicts, the action comments on the original PR with instructions for manual resolution.
2026-04-08 13:02:21 -07:00
docs: apply Vercel technical writing standards (#3704)
* docs: apply Vercel technical writing standards
Audit the complete documentation corpus, package READMEs, skills, and
source TSDoc/comments against the vercel-technical-writing skill and
style-rules.md. Normalize sentence-case headings without changing
published anchors, remove prose em dashes and filler wording, improve
active voice and self-contained phrasing, standardize product/brand
capitalization, American English, list punctuation, units, and code
fence languages, and preserve exact runtime strings/table placeholders.
All executable code is unchanged. Modified skills have their metadata
versions bumped.
* docs: extend writing audit to repository Markdown
Apply the same technical-writing rules to design documents, compiler
specifications, workbench guides, package changelogs, and the remaining
tracked Markdown outside the deployed docs corpus. Preserve historical
meaning, commands, output literals, table placeholders, and heading
anchors.
* docs: exclude generated package changelogs from audit
2026-08-21 14:24:31 -07:00
### Pre-release lifecycle
2026-04-08 13:02:21 -07:00
The `main` branch uses changesets' [pre-release mode ](https://github.com/changesets/changesets/blob/main/docs/prereleases.md ) to publish beta versions.
**Starting a new pre-release cycle: **
1. Create a changeset with the desired base bump (e.g. `major` for a new major version)
2. Enter pre-release mode: `pnpm changeset pre enter beta`
3. Merge the "Version Packages (beta)" PR to publish the first beta
**Publishing subsequent betas: **
- Merge PRs with changesets to `main` as normal
- Each "Version Packages (beta)" PR merge publishes the next `beta.N` increment
**Graduating to stable: **
1. (Optional) Transition to release candidates: `pnpm changeset pre enter rc` (publishes `X.Y.Z-rc.N` )
2. Exit pre-release mode: `pnpm changeset pre exit`
3. The next "Version Packages" PR will publish the final stable version to npm
docs: apply Vercel technical writing standards (#3704)
* docs: apply Vercel technical writing standards
Audit the complete documentation corpus, package READMEs, skills, and
source TSDoc/comments against the vercel-technical-writing skill and
style-rules.md. Normalize sentence-case headings without changing
published anchors, remove prose em dashes and filler wording, improve
active voice and self-contained phrasing, standardize product/brand
capitalization, American English, list punctuation, units, and code
fence languages, and preserve exact runtime strings/table placeholders.
All executable code is unchanged. Modified skills have their metadata
versions bumped.
* docs: extend writing audit to repository Markdown
Apply the same technical-writing rules to design documents, compiler
specifications, workbench guides, package changelogs, and the remaining
tracked Markdown outside the deployed docs corpus. Preserve historical
meaning, commands, output literals, table placeholders, and heading
anchors.
* docs: exclude generated package changelogs from audit
2026-08-21 14:24:31 -07:00
## Common patterns
2026-03-11 12:56:25 -07:00
docs: apply Vercel technical writing standards (#3704)
* docs: apply Vercel technical writing standards
Audit the complete documentation corpus, package READMEs, skills, and
source TSDoc/comments against the vercel-technical-writing skill and
style-rules.md. Normalize sentence-case headings without changing
published anchors, remove prose em dashes and filler wording, improve
active voice and self-contained phrasing, standardize product/brand
capitalization, American English, list punctuation, units, and code
fence languages, and preserve exact runtime strings/table placeholders.
All executable code is unchanged. Modified skills have their metadata
versions bumped.
* docs: extend writing audit to repository Markdown
Apply the same technical-writing rules to design documents, compiler
specifications, workbench guides, package changelogs, and the remaining
tracked Markdown outside the deployed docs corpus. Preserve historical
meaning, commands, output literals, table placeholders, and heading
anchors.
* docs: exclude generated package changelogs from audit
2026-08-21 14:24:31 -07:00
### Build-time version injection
2026-03-11 12:56:25 -07:00
Use `genversion` to access package version at runtime. See `@workflow/core` and `@workflow/world-vercel` for examples:
- Add `genversion` as devDependency
- Update build script: `genversion --es6 src/version.ts && tsc`
- Add `src/version.ts` to `.gitignore` and `turbo.json` outputs
docs: apply Vercel technical writing standards (#3704)
* docs: apply Vercel technical writing standards
Audit the complete documentation corpus, package READMEs, skills, and
source TSDoc/comments against the vercel-technical-writing skill and
style-rules.md. Normalize sentence-case headings without changing
published anchors, remove prose em dashes and filler wording, improve
active voice and self-contained phrasing, standardize product/brand
capitalization, American English, list punctuation, units, and code
fence languages, and preserve exact runtime strings/table placeholders.
All executable code is unchanged. Modified skills have their metadata
versions bumped.
* docs: extend writing audit to repository Markdown
Apply the same technical-writing rules to design documents, compiler
specifications, workbench guides, package changelogs, and the remaining
tracked Markdown outside the deployed docs corpus. Preserve historical
meaning, commands, output literals, table placeholders, and heading
anchors.
* docs: exclude generated package changelogs from audit
2026-08-21 14:24:31 -07:00
### Turbo caching for generated files
2026-03-11 12:56:25 -07:00
When a build step generates files, add them to the package's `turbo.json` outputs array to ensure proper caching.
docs: apply Vercel technical writing standards (#3704)
* docs: apply Vercel technical writing standards
Audit the complete documentation corpus, package READMEs, skills, and
source TSDoc/comments against the vercel-technical-writing skill and
style-rules.md. Normalize sentence-case headings without changing
published anchors, remove prose em dashes and filler wording, improve
active voice and self-contained phrasing, standardize product/brand
capitalization, American English, list punctuation, units, and code
fence languages, and preserve exact runtime strings/table placeholders.
All executable code is unchanged. Modified skills have their metadata
versions bumped.
* docs: extend writing audit to repository Markdown
Apply the same technical-writing rules to design documents, compiler
specifications, workbench guides, package changelogs, and the remaining
tracked Markdown outside the deployed docs corpus. Preserve historical
meaning, commands, output literals, table placeholders, and heading
anchors.
* docs: exclude generated package changelogs from audit
2026-08-21 14:24:31 -07:00
## Architecture notes
2026-03-11 12:56:25 -07:00
docs: apply Vercel technical writing standards (#3704)
* docs: apply Vercel technical writing standards
Audit the complete documentation corpus, package READMEs, skills, and
source TSDoc/comments against the vercel-technical-writing skill and
style-rules.md. Normalize sentence-case headings without changing
published anchors, remove prose em dashes and filler wording, improve
active voice and self-contained phrasing, standardize product/brand
capitalization, American English, list punctuation, units, and code
fence languages, and preserve exact runtime strings/table placeholders.
All executable code is unchanged. Modified skills have their metadata
versions bumped.
* docs: extend writing audit to repository Markdown
Apply the same technical-writing rules to design documents, compiler
specifications, workbench guides, package changelogs, and the remaining
tracked Markdown outside the deployed docs corpus. Preserve historical
meaning, commands, output literals, table placeholders, and heading
anchors.
* docs: exclude generated package changelogs from audit
2026-08-21 14:24:31 -07:00
### executionContext field
2026-03-11 12:56:25 -07:00
The `executionContext` field on workflow runs is a flexible JSONB/CBOR object that can store arbitrary data without schema changes. It flows through all worlds (local, postgres, vercel).
docs: apply Vercel technical writing standards (#3704)
* docs: apply Vercel technical writing standards
Audit the complete documentation corpus, package READMEs, skills, and
source TSDoc/comments against the vercel-technical-writing skill and
style-rules.md. Normalize sentence-case headings without changing
published anchors, remove prose em dashes and filler wording, improve
active voice and self-contained phrasing, standardize product/brand
capitalization, American English, list punctuation, units, and code
fence languages, and preserve exact runtime strings/table placeholders.
All executable code is unchanged. Modified skills have their metadata
versions bumped.
* docs: extend writing audit to repository Markdown
Apply the same technical-writing rules to design documents, compiler
specifications, workbench guides, package changelogs, and the remaining
tracked Markdown outside the deployed docs corpus. Preserve historical
meaning, commands, output literals, table placeholders, and heading
anchors.
* docs: exclude generated package changelogs from audit
2026-08-21 14:24:31 -07:00
### Observability data hydration
2026-03-11 12:56:25 -07:00
`packages/core/src/observability.ts` contains `hydrateResourceIO` which strips certain fields (like `executionContext` ) before UI display. If you need to display data from stripped fields, extract it before the stripping occurs.
2026-06-19 07:02:35 -07:00
fix(world-vercel,world-local): hold process-wide state on globalThis (#3728)
* fix(world-vercel,world-local): hold process-wide state on globalThis
Both packages are bundled into the host application's server build, and a
bundler keys module identity on (resource, layer) — Next.js alone builds
`instrument`, app-route, `ssr` and `edge` layers, so one process holds one
copy of each of these modules per layer. Every module-scope `const`/`let` in
them was therefore per-copy state wearing the costume of a process singleton.
vercel/workflow#3493 made `@workflow/world-vercel` bundled rather than
external and the events WebSocket transport regressed to HTTP for exactly
this reason: the queue consumer registered its channel in the `instrument`
copy's `Map` and the write path looked it up in the route copy's empty one. A
deterministic miss, for the life of the process. `@workflow/world-local` had
the same exposure all along — including `runFileLocks`, where a duplicated
mutex simply stops mutually excluding.
Add `globalSingleton()` to `@workflow/utils` (the primitive `@workflow/core`
already hand-rolls for its World cache) and route every mutable module-scope
binding in both worlds through it.
Regression cover, in three layers:
- `global-singleton.test.ts` pins the primitive's semantics.
- `ws-transport-module-copies.test.ts` imports the module twice in one
process and asserts a transport registered by one copy is found by the
other — it fails on a plain module-scope `Map`, which is the shipped bug.
- `scripts/lint/module-scope-state.mjs` fails the class: an AST rule banning
mutable module-scope state in these packages, with `// per-copy-ok: <why>`
as the deliberate escape. Wired into both packages' `vitest run src`, with
fixture self-tests so it cannot rot into a no-op.
* test(world-postgres): pin the module-scope-state rule for the postgres world
It is deduped today only because `getRuntimeRequire()` loads it — a property
of how it is loaded, not how it is written, and exactly what changed for
world-vercel in #3493. The package is already clean; this keeps it that way.
* docs(worlds): codify "a world must not hold mutable module state"
A world package is loaded one of two ways, and only one of them gives it a
single module instance: a runtime `require()` (deduped by Node) or the host's
bundler (one copy per layer). Which one you get is a property of how the world
is loaded, not of how it is written, and it changed under `world-vercel` in
#3493 — so the rule has to be "never rely on module scope", not "rely on it
until someone flips a config".
Written down in the four places someone can meet it:
- `docs/content/worlds/{v4,v5}/building-a-world.mdx` — a "Process-wide state"
section for custom-world authors, with the loading modes spelled out and a
nudge to prefer World-instance state over a global.
- `packages/world/README.md` — the same constraint on the contract package.
- `CLAUDE.md` — so the next contributor working in these packages sees it.
- `packages/core/src/runtime/world.ts` — at the two static imports, which is
where the difference between a bundled world and a required one originates.
The rule's own error message now teaches it too, rather than naming a helper.
Consolidates the guard while here: `@workflow/utils` owns the rule and its
fixture self-tests, and sweeps every *published* `packages/world-*` discovered
at runtime, so a world package added later is covered without anyone
remembering. Each world keeps a one-assertion mirror for locality.
* style: drop prose em dashes from this branch's new text
#3704 landed a repo-wide writing pass hours after this branch was written and
took `world-vercel/src` from 406 em dashes to 130 (`ws-transport.ts` alone went
35 to 1). This branch's docs section, README, comments and lint messages were
written before that and would have put 36 of them straight back into the files
that were just cleaned.
Rewritten sentence by sentence rather than by substitution: an em dash becomes a
colon, a comma, a full stop or a parenthetical depending on what it was doing.
Also fixes a real defect the sweep surfaced: `world-postgres`'s guard test was
generated through a shell heredoc and had literal backslash-backticks in its
doc comment.
* Update .changeset/world-module-scope-state.md
Co-authored-by: Peter Wielander <mittgfu@gmail.com>
Signed-off-by: Pranay Prakash <pranay.gp@gmail.com>
* fix(core): build the entrypoint's queue handler from getWorld()
Adopted from #3666 by @MintedKenny, which implements #3665 and could not run
CI as a fork PR. One line of behavior: `workflowEntrypoint`'s lazy handler
init calls `getWorld()` rather than `getWorldHandlers()`.
`getWorldHandlers()` owns a second, build-time-safe cache, so calling it from
the runtime route built a *second* World in the same process. That costs a
stateful World duplicate resources on every instance — world-postgres eagerly
constructs a `pg.Pool` (default `max: 10`) and a nested world-local World in
`createWorld()`, so self-hosted users have been paying for two of each — and,
for a bundled world package, the two Worlds are built by two different module
copies, which is the mechanism behind the WS transport regression the rest of
this branch contains.
The public `getWorldHandlers()` and its separate build-time cache are
unchanged; only the runtime route stops using it.
Kept from the original: the regression test asserting the factory runs exactly
once, and the api-reference wording (re-applied over #3704's list punctuation).
Not taken: renaming the `workflow.route.get_world_handlers` span. It is a
distinct span from the per-request `workflow.route.get_world` at the top of the
flow route, and reusing that name would collide with it in traces and in
`runtime-trace-mode.test.ts`; a comment records why the name outlived the call.
Co-authored-by: Kenneth <kenneth@standardforensics.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: address AI review on the module-scope work
Two blocking findings, both real:
- **Cross-version state sharing** (`ws-transport.ts`). A process can hold two
*published versions* of `@workflow/world-vercel` (a transitive dependency
pinning an older `@workflow/core`, which depends on this package by exact
version). Both wrote to the same unversioned `Symbol.for` key, so one
version's write path could be handed a `WsEventsTransport` built by the
other's class and frame against a protocol it may not share — with no version
negotiation on the socket to catch it. `shapeVersion` cannot express this: the
container is stable, the hazard is its contents. The registry and the events
dispatcher recycler are now keyed by package version. The plain connection
pools stay unversioned; sharing those across copies is the point.
- **The documented pattern failed the rule this PR adds.** The custom-world docs
teach `store[StateKey] ??= …`, which the rule flagged as a field write. It now
recognizes state rooted at `globalThis`, following one alias hop, which is
also what `core/private.ts:23` and `next/src/index.ts:58` are already doing
correctly (core drops 26 findings to 22, next 7 to 6). The docs also now say
outright that `globalSingleton()` is the same thing, since AGENTS.md
prescribes it and the page did not mention it.
Rule precision, from the review's probes:
- `.mts`/`.cts` are scanned. `@workflow/world-testing` is authored in `.mts`, so
its entry in the sweep was passing vacuously — with the walk fixed it reports
a real finding, now annotated (it is a standalone `serve()` entry).
- Mutations in top-level statements no longer count. A table filled at module
evaluation is identical in every copy; divergence needs a later write.
- `static` class fields are collected, attributed to the class name.
- An *exported* binding initialized to an empty collection is a finding on its
own, which approximates the cross-file case the walk cannot resolve.
Six fixtures pin the new behavior. The rule's header now states what it does not
see, and AGENTS.md states where the sweep stops and why core is not gated yet.
Also tags `resetGlobalSingletonForTest` `@internal`.
* fix(lint): attribute a static-field write to the field, not the class
The static-field support added in the previous commit keyed `declared` on the
class name, so a class carrying more than one mutable static reported one
finding instead of one per field, and labelled the survivor with whichever
mutation was seen first. On a two-static fixture it reported
`static Registry.latch (`.set()`)`: the name of one field, the reason
belonging to the other, pointing the reader at the wrong line.
Key static fields `Class.field` and resolve a write to the same shape, via a
new `memberPath()` that takes the first two segments of a member chain and
tries that key before the bare root identifier. Two follow-ons fall out of
having the path:
- `this.field` inside a `static` member resolves to the class, which is the
ordinary way to write the mutation. `staticClassOf()` returns nothing for an
instance member, where `this` is an instance and the state is per-instance
rather than per-copy, and nothing inside a nested `function`, which rebinds
`this`.
- `state.count++` is now a finding, like the `state.count += 1` that
`assignment()` already reported.
Fixtures pin all four, including the instance-field case that must stay clean.
The four world packages still report zero, and the extracted `recordMutation()`
keeps the file at its previous two Biome complexity warnings.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: make module duplication inert across every bundled package
`@workflow/core` is bundled into the host server build the same way the worlds
are, and always has been — the original repro measured three live copies in
every arm, including the pre-#3493 external one. One instance is not reachable:
layers cannot share a module, and core cannot be external because it *is*
workflow code (`runtime/start.ts:253` and nine methods in `runtime/run.ts` are
`'use step'`), so it must go through the SWC loader. The Next integration
already encodes that rule by removing workflow-bearing packages from
`serverExternalPackages`.
So the duplication stays and the hazard is removed instead, everywhere the
duplication can happen.
`@workflow/core` (22 findings to 0): warn-once latches in `constants.ts`,
`start.ts` and `telemetry.ts`; the source-map tracer cache; the VM script cache;
the QuickJS compiled-assets and baseline caches; the dev-server port cache (its
own comment already said "per process"); the text codecs; the zstd browser
decoder; and the `useStep` closure brand, where a function marked by one copy
was invisible to another.
The one with teeth was `step-single-flight.ts`: a per-copy map is not
single-flight. Two invocations reaching it through different layers would each
believe they were alone in the process and both run the step body, silently
degrading in-process dedup to the cross-process residual its own doc scopes out
to the ownership lease.
Also `@workflow/world` (a warn-once set, hand-rolled onto `globalThis` to keep
that package dependency-free), `@workflow/ai` (the lazy OTel API), and
`@workflow/nest` (bootstrap config in a module-level `let` and two static class
fields — configure one copy, read another, and the controller is unconfigured
for the life of the process).
Five sites are deliberately per-copy and now say why: state keyed on objects
that never cross copies (the barrier safety-net `WeakSet`, the QuickJS pending
byte `WeakMap`), the synchronously-scoped guest-code sink, and the OTel
diagnostic that reports what *this* copy sees.
The sweep now covers all of it. Packages with a single module graph stay out
(build-time code, the CLI, the o11y UI, the test runner) and AGENTS.md records
which and why.
Found while doing this: two static fields on one class collapsed into a single
entry in the rule, so `WorkflowModule.options` was invisible behind
`WorkflowModule.outDir`. Statics are now keyed `Class.field`.
* fix(world): suppress noAssignInExpressions on the globalThis idiom
The hand-rolled form trips Biome, as it does in `packages/core/src/private.ts`,
which carries the same suppression. Restructuring it into a helper function
instead would hide the state behind a call the module-scope rule cannot follow,
so the binding would stop being recognized as off-module and the package would
report a finding for correct code.
* fix: sweep every bundled package, and mark utils side-effect free
@shalabhc asked on review whether `@workflow/utils` needs this too. It does,
and so do three others: `utils`, `errors`, `serde` and `workflow` all end up in
the host application's server build and none were in the sweep. All four report
zero today, which is exactly the state `world-testing` appeared to be in before
the `.mts` walk was fixed and it turned out to have a real finding. Being clean
and being *checked* are different properties, and only the second one survives
the next contributor.
`sideEffects: false` on `@workflow/utils`: verified that every module in the
package only declares (no import-time work), so a bundler can now drop the
unused parts of the barrel instead of keeping all ~64 KB of it because three
packages import one 476-byte function.
---------
Signed-off-by: Pranay Prakash <pranay.gp@gmail.com>
Co-authored-by: Peter Wielander <mittgfu@gmail.com>
Co-authored-by: Kenneth <kenneth@standardforensics.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Peter Wielander <peter.wielander@vercel.com>
2026-08-21 16:55:24 -07:00
### World packages must not hold mutable module state
`@workflow/world-local` and `@workflow/world-vercel` are bundled into the host
application's server build (see `VERCEL_WORLD_DEPENDENCY_PACKAGES` in
`packages/next/src/index.ts` ). Bundlers key module identity on
`(resource, layer)` , and Next.js alone compiles `instrument` , app-route, `ssr`
and `edge` as separate module graphs, so one process holds one copy of every
module in these packages **per bundler layer ** . A top-level `let` , or a `const`
holding a `Map` , is per-copy state, not the process singleton it reads as. A
duplicated mutex stops mutually excluding; a duplicated registry is a
deterministic miss; duplicated ID generators can fork a sequence.
Hold such state on the World instance where it is per-World, or on `globalThis`
via `globalSingleton()` from `@workflow/utils` where it is genuinely
process-wide. State that is deliberately per-copy needs a
`// per-copy-ok: <why>` annotation. `scripts/lint/module-scope-state.mjs`
enforces this across every published `packages/world-*` , run from
`@workflow/utils` 's test suite (with a local mirror in each world package), so
adding a new world package is covered automatically.
Custom worlds loaded through `WORKFLOW_TARGET_WORLD` are deduped by Node's
module cache and are safe today, but that is a property of how they are loaded,
not of how they are written, and it changed for world-vercel in #3493 . Keep them
clean too. The author-facing version of this rule is in
`docs/content/worlds/{v4,v5}/building-a-world.mdx` ; keep both versions in sync.
The sweep covers every package that ends up inside the host application's
server build: all published `packages/world-*` (discovered at runtime, so a new
world is covered the day it is added) plus `core` , `world` , `ai` and `nest` ,
which are named in `BUNDLED_RUNTIME_PACKAGES` in
`packages/utils/src/module-scope-state.test.ts` . Adding a package that runs in
the host server means adding it to that list: "does this run inside the host's
server bundle" is a judgement, not something to infer from a directory name.
Deliberately outside the sweep, because a single module graph makes the hazard
impossible: `next` , `builders` and `sveltekit` (build-time code), `cli` (its own
process), `web` and `web-shared` (the observability UI), `vitest` (the test
runner's process), and private packages such as `world-sim` .
2026-06-19 07:02:35 -07:00
### Trace context propagation (world-vercel HTTP requests)
docs: apply Vercel technical writing standards (#3704)
* docs: apply Vercel technical writing standards
Audit the complete documentation corpus, package READMEs, skills, and
source TSDoc/comments against the vercel-technical-writing skill and
style-rules.md. Normalize sentence-case headings without changing
published anchors, remove prose em dashes and filler wording, improve
active voice and self-contained phrasing, standardize product/brand
capitalization, American English, list punctuation, units, and code
fence languages, and preserve exact runtime strings/table placeholders.
All executable code is unchanged. Modified skills have their metadata
versions bumped.
* docs: extend writing audit to repository Markdown
Apply the same technical-writing rules to design documents, compiler
specifications, workbench guides, package changelogs, and the remaining
tracked Markdown outside the deployed docs corpus. Preserve historical
meaning, commands, output literals, table placeholders, and heading
anchors.
* docs: exclude generated package changelogs from audit
2026-08-21 14:24:31 -07:00
Every outgoing HTTP request from `@workflow/world-vercel` to workflow-server (or the queue) MUST explicitly inject W3C trace context so the server can parent its spans to the caller and traces stay correlated end to end. Call `injectTraceContextIntoHeaders(headers)` (from `packages/world-vercel/src/telemetry.ts` ) on the outgoing headers, inside the client span when one exists. `makeRequest` in `utils.ts` is the reference implementation. It is a no-op when no OpenTelemetry SDK is registered.
2026-06-19 07:02:35 -07:00
docs: apply Vercel technical writing standards (#3704)
* docs: apply Vercel technical writing standards
Audit the complete documentation corpus, package READMEs, skills, and
source TSDoc/comments against the vercel-technical-writing skill and
style-rules.md. Normalize sentence-case headings without changing
published anchors, remove prose em dashes and filler wording, improve
active voice and self-contained phrasing, standardize product/brand
capitalization, American English, list punctuation, units, and code
fence languages, and preserve exact runtime strings/table placeholders.
All executable code is unchanged. Modified skills have their metadata
versions bumped.
* docs: extend writing audit to repository Markdown
Apply the same technical-writing rules to design documents, compiler
specifications, workbench guides, package changelogs, and the remaining
tracked Markdown outside the deployed docs corpus. Preserve historical
meaning, commands, output literals, table placeholders, and heading
anchors.
* docs: exclude generated package changelogs from audit
2026-08-21 14:24:31 -07:00
Do **not ** rely on ambient OpenTelemetry auto-instrumentation to do this: world-vercel's request paths use custom undici dispatchers / `global fetch` , which auto-instrumentation does not reliably hook. When you add a new request path or API version (e.g. a future v5 events API), wire the injection in the same place you build the request headers. The v4 events path (`fetchV4` in `events-v4.ts` ) regressed cross-service correlation precisely by routing around `makeRequest` and skipping this step. Workflow-server spans stopped joining the flow-route invocation trace until the injection was added back. Cover new paths with a test in `trace-propagation.test.ts` .
feat(world-vercel): synthesize per-event client spans on the WS transport (#3452)
* feat(world-vercel): synthesize per-event client spans on the WS transport
PR #3084 added the opt-in `WORKFLOW_EVENTS_TRANSPORT=ws` path and listed
"no client-side span on the WS path" as a known limitation. Because event
writes become multiplexed frames on one long-lived socket rather than
individual `fetch` calls, the per-event `http POST` CLIENT span that the
HTTP transport produced simply disappeared — traces went from one span
per event to nothing between the invocation and the server.
Restore it by synthesizing a request-shaped span around each frame, and
give the upgrade its own span:
- Extract `withHttpClientSpan` / `recordClientSpanStatus` from
`instrumentedFetch` in `http-core.ts` so the synthetic span is emitted
by the same envelope as the real one and cannot drift from it.
`InstrumentedFetchOptions` now extends `HttpClientSpanOptions`.
- `postEventFrameOverWs` opens `http POST` with `url.full` pointing at the
v4 REST endpoint the frame is forwarded into, so per-event traces and
latency dashboards keep working across the flag. Extract `eventsV4Url`
so that URL cannot drift from the one the HTTP path actually requests.
- Tag both transports with `workflow.events.transport` (`http` | `ws`) and
`workflow.event.type`; the WS path additionally sets
`network.protocol.name=websocket`, `workflow.events.ws.url` (the real
wire destination) and `workflow.events.ws.req_id` (join key to the
server's log line for the frame), so the span is never mistaken for a
real HTTP request.
- Add a `workflow.events.ws.connect` span around the upgrade — the one
genuinely-HTTP request here, previously the invisible half of every WS
write's latency — carrying `workflow.events.ws.reconnect_attempt`. This
also puts `resolveUpgradeHeaders`' trace-context injection inside a
client span, as AGENTS.md requires.
- Fix `parseServer` to treat `wss:` as TLS (port 443, not 80).
Out of scope, deliberately: per-frame `traceparent` (needs a frame-meta
field plus a server change) and Vercel's outgoing-requests view (that
instruments global `fetch`, so a frame structurally cannot appear there).
Covered by `ws-transport-spans.test.ts`, which drives the real selection +
transport + adapter stack over a fake socket and asserts span shape,
failure reporting, retry behaviour and HTTP/WS parity.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: shalabhchaturvedi-7802 <shalabh.chaturvedi@vercel.com>
Co-Authored-By: shalabhc <shalabh.chaturvedi@vercel.com>
* chore: trim WS spans changeset to the user-facing summary
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: shalabhchaturvedi-7802 <shalabh.chaturvedi@vercel.com>
Co-Authored-By: shalabhc <shalabh.chaturvedi@vercel.com>
* fix(world-vercel): only tag event-write spans with transport
Signed-off-by: Shalabh Chaturvedi <shalabh.chaturvedi@vercel.com>
Co-Authored-By: shalabhchaturvedi-7802 <shalabh.chaturvedi@vercel.com>
* fix(world-vercel): format WS transport span regression test
Signed-off-by: Shalabh Chaturvedi <shalabh.chaturvedi@vercel.com>
Co-Authored-By: Shalabh Chaturvedi <shalabh.chaturvedi@vercel.com>
---------
Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com>
2026-08-13 00:06:59 -07:00
docs: apply Vercel technical writing standards (#3704)
* docs: apply Vercel technical writing standards
Audit the complete documentation corpus, package READMEs, skills, and
source TSDoc/comments against the vercel-technical-writing skill and
style-rules.md. Normalize sentence-case headings without changing
published anchors, remove prose em dashes and filler wording, improve
active voice and self-contained phrasing, standardize product/brand
capitalization, American English, list punctuation, units, and code
fence languages, and preserve exact runtime strings/table placeholders.
All executable code is unchanged. Modified skills have their metadata
versions bumped.
* docs: extend writing audit to repository Markdown
Apply the same technical-writing rules to design documents, compiler
specifications, workbench guides, package changelogs, and the remaining
tracked Markdown outside the deployed docs corpus. Preserve historical
meaning, commands, output literals, table placeholders, and heading
anchors.
* docs: exclude generated package changelogs from audit
2026-08-21 14:24:31 -07:00
The same rule covers a request path that is not an HTTP request. A non-`fetch` transport must still open the client span callers read a trace through: use `withHttpClientSpan` (`http-core.ts` ), the envelope `instrumentedFetch` is built on, so the span carries the same name, kind, and attributes rather than a hand-rolled parallel shape. The WS events transport is the worked example. `postEventFrameOverWs` synthesizes an `http POST` span per frame and tags it `workflow.events.transport: 'ws'` , and the handshake gets its own `workflow.events.ws.connect` span (`ws-transport-spans.test.ts` ). Adding a transport that writes events without one silently deletes the per-event view of a run.