Skip to content

Default the events transport to WebSockets - #3702

Open
shalabhc wants to merge 3 commits into
mainfrom
ws-transport-default-on
Open

Default the events transport to WebSockets#3702
shalabhc wants to merge 3 commits into
mainfrom
ws-transport-default-on

Conversation

@shalabhc

@shalabhc shalabhc commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator

Flip websockets to default on. It can be disabled by setting WORKFLOW_EVENTS_TRANSPORT=http

Known issues

  1. Having the proxy enabled means websockets is silently turned off.
  2. The WS e2e lanes do not assert the transport was used.

Tests

All existing e2e tests will now test websockets on by default.

This leaves a large gap for http coverage while we we want to keep a safe fallback. I'm adding a separate set of parallel tests to tests all e2e for http - separate PR.

WORKFLOW_EVENTS_TRANSPORT=http is the opt-out. Only that exact value
disables it, so a typo'd or empty value fails toward the default rather
than quietly pinning a deployment to HTTP.

The prerequisite the gate named for defaulting on is met:
postEventFrameOverWs opens a client span per frame. What is still missing
is Vercel's outgoing-requests view, which reads instrumented fetch calls
rather than spans and so cannot show a transport that issues no request.

Co-Authored-By: opencode <opencode@vercel.com>
@changeset-bot

changeset-bot Bot commented Aug 20, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: a8726db

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

This PR includes changesets to release 17 packages
Name Type
@workflow/world-vercel Minor
@workflow/cli Patch
@workflow/core Patch
@workflow/web Patch
workflow Patch
@workflow/world-testing Patch
@workflow/builders Patch
@workflow/next Patch
@workflow/nitro Patch
@workflow/vitest Patch
@workflow/web-shared Patch
@workflow/astro Patch
@workflow/nest Patch
@workflow/rollup Patch
@workflow/sveltekit Patch
@workflow/vite Patch
@workflow/nuxt Patch

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

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

@vercel

vercel Bot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

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

Project Deployment Actions Updated (UTC)
example-nextjs-workflow-turbopack Ready Ready Preview Aug 20, 2026 11:53pm
example-nextjs-workflow-webpack Ready Ready Preview Aug 20, 2026 11:53pm
example-workflow Ready Ready Preview Aug 20, 2026 11:53pm
workbench-astro-workflow Ready Ready Preview Aug 20, 2026 11:53pm
workbench-express-workflow Ready Ready Preview Aug 20, 2026 11:53pm
workbench-fastify-workflow Ready Ready Preview Aug 20, 2026 11:53pm
workbench-hono-workflow Ready Ready Preview Aug 20, 2026 11:53pm
workbench-nestjs-workflow Ready Ready Preview Aug 20, 2026 11:53pm
workbench-nitro-workflow Ready Ready Preview Aug 20, 2026 11:53pm
workbench-nuxt-workflow Ready Ready Preview Aug 20, 2026 11:53pm
workbench-python-workflow Ready Ready Preview Aug 20, 2026 11:53pm
workbench-sveltekit-workflow Ready Ready Preview Aug 20, 2026 11:53pm
workbench-tanstack-start-workflow Ready Ready Preview Aug 20, 2026 11:53pm
workbench-vite-workflow Ready Ready Preview Aug 20, 2026 11:53pm
workflow-docs Ready Ready Preview, v0 Aug 20, 2026 11:53pm
workflow-swc-playground Ready Ready Preview Aug 20, 2026 11:53pm
workflow-tarballs Ready Ready Preview Aug 20, 2026 11:53pm
workflow-web Ready Ready Preview Aug 20, 2026 11:53pm

@github-actions

github-actions Bot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

🧪 E2E Test Results

Some tests failed

❌ Failed E2E Tests

▲ Vercel Production (171 failed)

astro-node (3 failed):

  • hookCleanupTestWorkflow - hook token reuse after workflow completion | wrun_41M0GSS35B0GM3T0HKX3DXF7Z9 | 🔍 observability
  • hookGetConflictWorkflow - hook.getConflict() resolves with the conflicting run when token is already registered | wrun_41M0GST7A30GQEBNGHM9W6JKFW | 🔍 observability
  • setAttributes Promise.all of disjoint-key writes: every key lands

astro-quickjs (10 failed):

  • hookCleanupTestWorkflow - hook token reuse after workflow completion | wrun_41M0GSS35B0GM3T0HKX3DXF7Z9 | 🔍 observability
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_41M0GSRBK50GVKS7FMV1CY1M8R | 🔍 observability
  • hookGetConflictWorkflow - hook.getConflict() resolves with the conflicting run when token is already registered | wrun_41M0GST7A30GQEBNGHM9W6JKFW | 🔍 observability
  • hookMinRetentionWorkflow - terminal Hook cannot resume and its token stays unavailable | wrun_41M0GSTC1M0GNS3HBGX79CNQ8A | 🔍 observability
  • setAttributes start: initial attributes are seeded on run creation
  • setAttributes start: reserved-prefix initial attributes are seeded with allowReservedAttributes
  • setAttributes setAttributesWorkflow: workflow-body calls append native attr_set events and merge correctly
  • setAttributes setAttributesInsideStepWorkflow: step-body calls append attributed native events
  • setAttributes Promise.all of disjoint-key writes: every key lands
  • setAttributes workflow throws after awaited setAttributes: attribute still persists on the failed run

example-node (4 failed):

  • hookCleanupTestWorkflow - hook token reuse after workflow completion | wrun_41M0GSS35B0GM3T0HKX3DXF7Z9 | 🔍 observability
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_41M0GSRBK50GVKS7FMV1CY1M8R | 🔍 observability
  • setAttributes start: initial attributes are seeded on run creation
  • setAttributes fire-and-forget: void setAttributes lands without awaiting

example-quickjs (8 failed):

  • hookCleanupTestWorkflow - hook token reuse after workflow completion | wrun_41M0GSS35B0GM3T0HKX3DXF7Z9 | 🔍 observability
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_41M0GSRBK50GVKS7FMV1CY1M8R | 🔍 observability
  • hookGetConflictWorkflow - hook.getConflict() resolves with the conflicting run when token is already registered | wrun_41M0GST7A30GQEBNGHM9W6JKFW | 🔍 observability
  • setAttributes start: initial attributes are seeded on run creation
  • setAttributes start: reserved-prefix initial attributes are seeded with allowReservedAttributes
  • setAttributes setAttributesWorkflow: workflow-body calls append native attr_set events and merge correctly
  • setAttributes fire-and-forget: void setAttributes lands without awaiting
  • setAttributes validation DX: invalid writes throw catchable FatalErrors naming rule and limit

express-node (3 failed):

  • hookCleanupTestWorkflow - hook token reuse after workflow completion | wrun_41M0GSS35B0GM3T0HKX3DXF7Z9 | 🔍 observability
  • hookGetConflictWorkflow - hook.getConflict() resolves with the conflicting run when token is already registered | wrun_41M0GST7A30GQEBNGHM9W6JKFW | 🔍 observability
  • setAttributes start: reserved-prefix initial attributes are seeded with allowReservedAttributes

express-quickjs (9 failed):

  • hookCleanupTestWorkflow - hook token reuse after workflow completion | wrun_41M0GSS35B0GM3T0HKX3DXF7Z9 | 🔍 observability
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_41M0GSRBK50GVKS7FMV1CY1M8R | 🔍 observability
  • setAttributes start: initial attributes are seeded on run creation
  • setAttributes start: reserved-prefix initial attributes are seeded with allowReservedAttributes
  • setAttributes setAttributesWorkflow: workflow-body calls append native attr_set events and merge correctly
  • setAttributes setAttributesInsideStepWorkflow: step-body calls append attributed native events
  • setAttributes fire-and-forget: void setAttributes lands without awaiting
  • setAttributes Promise.all of disjoint-key writes: every key lands
  • setAttributes validation DX: invalid writes throw catchable FatalErrors naming rule and limit

fastify-node (5 failed):

  • hookCleanupTestWorkflow - hook token reuse after workflow completion | wrun_41M0GSS35B0GM3T0HKX3DXF7Z9 | 🔍 observability
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_41M0GSRBK50GVKS7FMV1CY1M8R | 🔍 observability
  • hookGetConflictWorkflow - hook.getConflict() resolves with the conflicting run when token is already registered | wrun_41M0GST7A30GQEBNGHM9W6JKFW | 🔍 observability
  • setAttributes start: initial attributes are seeded on run creation
  • setAttributes fire-and-forget: void setAttributes lands without awaiting

fastify-quickjs (10 failed):

  • hookCleanupTestWorkflow - hook token reuse after workflow completion | wrun_41M0GSS35B0GM3T0HKX3DXF7Z9 | 🔍 observability
  • hookMinRetentionWorkflow - terminal Hook cannot resume and its token stays unavailable | wrun_41M0GSTC1M0GNS3HBGX79CNQ8A | 🔍 observability
  • setAttributes start: initial attributes are seeded on run creation
  • setAttributes start: reserved-prefix initial attributes are seeded with allowReservedAttributes
  • setAttributes setAttributesWorkflow: workflow-body calls append native attr_set events and merge correctly
  • setAttributes setAttributesInsideStepWorkflow: step-body calls append attributed native events
  • setAttributes fire-and-forget: void setAttributes lands without awaiting
  • setAttributes Promise.all of disjoint-key writes: every key lands
  • setAttributes workflow throws after awaited setAttributes: attribute still persists on the failed run
  • setAttributes validation DX: invalid writes throw catchable FatalErrors naming rule and limit

hono-node (2 failed):

  • hookCleanupTestWorkflow - hook token reuse after workflow completion | wrun_41M0GSS35B0GM3T0HKX3DXF7Z9 | 🔍 observability
  • hookGetConflictWorkflow - hook.getConflict() resolves with the conflicting run when token is already registered | wrun_41M0GST7A30GQEBNGHM9W6JKFW | 🔍 observability

hono-quickjs (8 failed):

  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_41M0GSRBK50GVKS7FMV1CY1M8R | 🔍 observability
  • hookMinRetentionWorkflow - terminal Hook cannot resume and its token stays unavailable | wrun_41M0GSTC1M0GNS3HBGX79CNQ8A | 🔍 observability
  • setAttributes start: reserved-prefix initial attributes are seeded with allowReservedAttributes
  • setAttributes setAttributesWorkflow: workflow-body calls append native attr_set events and merge correctly
  • setAttributes setAttributesInsideStepWorkflow: step-body calls append attributed native events
  • setAttributes fire-and-forget: void setAttributes lands without awaiting
  • setAttributes Promise.all of disjoint-key writes: every key lands
  • setAttributes workflow throws after awaited setAttributes: attribute still persists on the failed run

nest-node (7 failed):

  • hookCleanupTestWorkflow - hook token reuse after workflow completion | wrun_41M0GSS35B0GM3T0HKX3DXF7Z9 | 🔍 observability
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_41M0GSRBK50GVKS7FMV1CY1M8R | 🔍 observability
  • hookMinRetentionWorkflow - terminal Hook cannot resume and its token stays unavailable | wrun_41M0GSTC1M0GNS3HBGX79CNQ8A | 🔍 observability
  • setAttributes start: initial attributes are seeded on run creation
  • setAttributes start: reserved-prefix initial attributes are seeded with allowReservedAttributes
  • setAttributes setAttributesWorkflow: workflow-body calls append native attr_set events and merge correctly
  • setAttributes fire-and-forget: void setAttributes lands without awaiting

nest-quickjs (6 failed):

  • hookCleanupTestWorkflow - hook token reuse after workflow completion | wrun_41M0GSS35B0GM3T0HKX3DXF7Z9 | 🔍 observability
  • hookGetConflictWorkflow - hook.getConflict() resolves with the conflicting run when token is already registered | wrun_41M0GST7A30GQEBNGHM9W6JKFW | 🔍 observability
  • setAttributes start: reserved-prefix initial attributes are seeded with allowReservedAttributes
  • setAttributes setAttributesWorkflow: workflow-body calls append native attr_set events and merge correctly
  • setAttributes setAttributesInsideStepWorkflow: step-body calls append attributed native events
  • setAttributes fire-and-forget: void setAttributes lands without awaiting

nextjs-turbopack-node (2 failed):

  • hookCleanupTestWorkflow - hook token reuse after workflow completion | wrun_41M0GSS35B0GM3T0HKX3DXF7Z9 | 🔍 observability
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_41M0GSRBK50GVKS7FMV1CY1M8R | 🔍 observability

nextjs-turbopack-quickjs (7 failed):

  • hookCleanupTestWorkflow - hook token reuse after workflow completion | wrun_41M0GSS35B0GM3T0HKX3DXF7Z9 | 🔍 observability
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_41M0GSRBK50GVKS7FMV1CY1M8R | 🔍 observability
  • hookGetConflictWorkflow - hook.getConflict() resolves with the conflicting run when token is already registered | wrun_41M0GST7A30GQEBNGHM9W6JKFW | 🔍 observability
  • setAttributes start: initial attributes are seeded on run creation
  • setAttributes start: reserved-prefix initial attributes are seeded with allowReservedAttributes
  • setAttributes setAttributesInsideStepWorkflow: step-body calls append attributed native events
  • setAttributes fire-and-forget: void setAttributes lands without awaiting

nextjs-webpack-node (5 failed):

  • hookCleanupTestWorkflow - hook token reuse after workflow completion | wrun_41M0GSS35B0GM3T0HKX3DXF7Z9 | 🔍 observability
  • hookGetConflictWorkflow - hook.getConflict() resolves with the conflicting run when token is already registered | wrun_41M0GST7A30GQEBNGHM9W6JKFW | 🔍 observability
  • setAttributes start: initial attributes are seeded on run creation
  • setAttributes start: reserved-prefix initial attributes are seeded with allowReservedAttributes
  • setAttributes setAttributesWorkflow: workflow-body calls append native attr_set events and merge correctly

nextjs-webpack-quickjs (10 failed):

  • hookCleanupTestWorkflow - hook token reuse after workflow completion | wrun_41M0GSS35B0GM3T0HKX3DXF7Z9 | 🔍 observability
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_41M0GSRBK50GVKS7FMV1CY1M8R | 🔍 observability
  • hookGetConflictWorkflow - hook.getConflict() resolves with the conflicting run when token is already registered | wrun_41M0GST7A30GQEBNGHM9W6JKFW | 🔍 observability
  • hookMinRetentionWorkflow - terminal Hook cannot resume and its token stays unavailable | wrun_41M0GSTC1M0GNS3HBGX79CNQ8A | 🔍 observability
  • setAttributes start: initial attributes are seeded on run creation
  • setAttributes start: reserved-prefix initial attributes are seeded with allowReservedAttributes
  • setAttributes setAttributesWorkflow: workflow-body calls append native attr_set events and merge correctly
  • setAttributes fire-and-forget: void setAttributes lands without awaiting
  • setAttributes Promise.all of disjoint-key writes: every key lands
  • setAttributes validation DX: invalid writes throw catchable FatalErrors naming rule and limit

nitro-node (5 failed):

  • hookCleanupTestWorkflow - hook token reuse after workflow completion | wrun_41M0GSS35B0GM3T0HKX3DXF7Z9 | 🔍 observability
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_41M0GSRBK50GVKS7FMV1CY1M8R | 🔍 observability
  • hookMinRetentionWorkflow - terminal Hook cannot resume and its token stays unavailable | wrun_41M0GSTC1M0GNS3HBGX79CNQ8A | 🔍 observability
  • setAttributes start: initial attributes are seeded on run creation
  • setAttributes start: reserved-prefix initial attributes are seeded with allowReservedAttributes

nitro-quickjs (10 failed):

  • hookCleanupTestWorkflow - hook token reuse after workflow completion | wrun_41M0GSS35B0GM3T0HKX3DXF7Z9 | 🔍 observability
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_41M0GSRBK50GVKS7FMV1CY1M8R | 🔍 observability
  • hookGetConflictWorkflow - hook.getConflict() resolves with the conflicting run when token is already registered | wrun_41M0GST7A30GQEBNGHM9W6JKFW | 🔍 observability
  • setAttributes start: reserved-prefix initial attributes are seeded with allowReservedAttributes
  • setAttributes setAttributesWorkflow: workflow-body calls append native attr_set events and merge correctly
  • setAttributes setAttributesInsideStepWorkflow: step-body calls append attributed native events
  • setAttributes fire-and-forget: void setAttributes lands without awaiting
  • setAttributes Promise.all of disjoint-key writes: every key lands
  • setAttributes workflow throws after awaited setAttributes: attribute still persists on the failed run
  • setAttributes validation DX: invalid writes throw catchable FatalErrors naming rule and limit

nuxt-node (6 failed):

  • hookCleanupTestWorkflow - hook token reuse after workflow completion | wrun_41M0GSS35B0GM3T0HKX3DXF7Z9 | 🔍 observability
  • hookGetConflictWorkflow - hook.getConflict() resolves with the conflicting run when token is already registered | wrun_41M0GST7A30GQEBNGHM9W6JKFW | 🔍 observability
  • setAttributes start: initial attributes are seeded on run creation
  • setAttributes setAttributesWorkflow: workflow-body calls append native attr_set events and merge correctly
  • setAttributes fire-and-forget: void setAttributes lands without awaiting
  • setAttributes Promise.all of disjoint-key writes: every key lands

nuxt-quickjs (9 failed):

  • hookCleanupTestWorkflow - hook token reuse after workflow completion | wrun_41M0GSS35B0GM3T0HKX3DXF7Z9 | 🔍 observability
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_41M0GSRBK50GVKS7FMV1CY1M8R | 🔍 observability
  • hookGetConflictWorkflow - hook.getConflict() resolves with the conflicting run when token is already registered | wrun_41M0GST7A30GQEBNGHM9W6JKFW | 🔍 observability
  • setAttributes start: initial attributes are seeded on run creation
  • setAttributes start: reserved-prefix initial attributes are seeded with allowReservedAttributes
  • setAttributes setAttributesWorkflow: workflow-body calls append native attr_set events and merge correctly
  • setAttributes setAttributesInsideStepWorkflow: step-body calls append attributed native events
  • setAttributes fire-and-forget: void setAttributes lands without awaiting
  • setAttributes Promise.all of disjoint-key writes: every key lands

sveltekit-node (5 failed):

  • hookCleanupTestWorkflow - hook token reuse after workflow completion | wrun_41M0GSS35B0GM3T0HKX3DXF7Z9 | 🔍 observability
  • hookGetConflictWorkflow - hook.getConflict() resolves with the conflicting run when token is already registered | wrun_41M0GST7A30GQEBNGHM9W6JKFW | 🔍 observability
  • setAttributes start: reserved-prefix initial attributes are seeded with allowReservedAttributes
  • setAttributes setAttributesWorkflow: workflow-body calls append native attr_set events and merge correctly
  • setAttributes fire-and-forget: void setAttributes lands without awaiting

sveltekit-quickjs (9 failed):

  • hookCleanupTestWorkflow - hook token reuse after workflow completion | wrun_41M0GSS35B0GM3T0HKX3DXF7Z9 | 🔍 observability
  • hookGetConflictWorkflow - hook.getConflict() resolves with the conflicting run when token is already registered | wrun_41M0GST7A30GQEBNGHM9W6JKFW | 🔍 observability
  • setAttributes start: initial attributes are seeded on run creation
  • setAttributes start: reserved-prefix initial attributes are seeded with allowReservedAttributes
  • setAttributes setAttributesWorkflow: workflow-body calls append native attr_set events and merge correctly
  • setAttributes setAttributesInsideStepWorkflow: step-body calls append attributed native events
  • setAttributes fire-and-forget: void setAttributes lands without awaiting
  • setAttributes Promise.all of disjoint-key writes: every key lands
  • setAttributes validation DX: invalid writes throw catchable FatalErrors naming rule and limit

tanstack-start-node (4 failed):

  • hookCleanupTestWorkflow - hook token reuse after workflow completion | wrun_41M0GSS35B0GM3T0HKX3DXF7Z9 | 🔍 observability
  • setAttributes start: reserved-prefix initial attributes are seeded with allowReservedAttributes
  • setAttributes fire-and-forget: void setAttributes lands without awaiting
  • setAttributes Promise.all of disjoint-key writes: every key lands

tanstack-start-quickjs (10 failed):

  • hookCleanupTestWorkflow - hook token reuse after workflow completion | wrun_41M0GSS35B0GM3T0HKX3DXF7Z9 | 🔍 observability
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_41M0GSRBK50GVKS7FMV1CY1M8R | 🔍 observability
  • hookGetConflictWorkflow - hook.getConflict() resolves with the conflicting run when token is already registered | wrun_41M0GST7A30GQEBNGHM9W6JKFW | 🔍 observability
  • setAttributes start: initial attributes are seeded on run creation
  • setAttributes start: reserved-prefix initial attributes are seeded with allowReservedAttributes
  • setAttributes setAttributesWorkflow: workflow-body calls append native attr_set events and merge correctly
  • setAttributes setAttributesInsideStepWorkflow: step-body calls append attributed native events
  • setAttributes fire-and-forget: void setAttributes lands without awaiting
  • setAttributes Promise.all of disjoint-key writes: every key lands
  • setAttributes workflow throws after awaited setAttributes: attribute still persists on the failed run

vite-node (7 failed):

  • hookCleanupTestWorkflow - hook token reuse after workflow completion | wrun_41M0GSS35B0GM3T0HKX3DXF7Z9 | 🔍 observability
  • hookGetConflictWorkflow - hook.getConflict() resolves with the conflicting run when token is already registered | wrun_41M0GST7A30GQEBNGHM9W6JKFW | 🔍 observability
  • hookMinRetentionWorkflow - terminal Hook cannot resume and its token stays unavailable | wrun_41M0GSTC1M0GNS3HBGX79CNQ8A | 🔍 observability
  • setAttributes start: initial attributes are seeded on run creation
  • setAttributes start: reserved-prefix initial attributes are seeded with allowReservedAttributes
  • setAttributes setAttributesWorkflow: workflow-body calls append native attr_set events and merge correctly
  • setAttributes fire-and-forget: void setAttributes lands without awaiting

vite-quickjs (7 failed):

  • hookGetConflictWorkflow - hook.getConflict() resolves with the conflicting run when token is already registered | wrun_41M0GST7A30GQEBNGHM9W6JKFW | 🔍 observability
  • hookMinRetentionWorkflow - terminal Hook cannot resume and its token stays unavailable | wrun_41M0GSTC1M0GNS3HBGX79CNQ8A | 🔍 observability
  • setAttributes start: initial attributes are seeded on run creation
  • setAttributes start: reserved-prefix initial attributes are seeded with allowReservedAttributes
  • setAttributes setAttributesWorkflow: workflow-body calls append native attr_set events and merge correctly
  • setAttributes setAttributesInsideStepWorkflow: step-body calls append attributed native events
  • setAttributes Promise.all of disjoint-key writes: every key lands

⚠️ Flaky E2E Tests (passed on retry)

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

24 flaky tests
  • addTenWorkflow (express)
  • addTenWorkflow (nitro)
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously (astro)
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously (fastify)
  • fire-and-forget: void setAttributes lands without awaiting (nextjs-webpack)
  • fire-and-forget: void setAttributes lands without awaiting (nitro)
  • hookCleanupTestWorkflow - hook token reuse after workflow completion (hono)
  • hookGetConflictWorkflow - hook.getConflict() resolves with the conflicting run when token is already registered (tanstack-start)
  • hookMinRetentionWorkflow - terminal Hook cannot resume and its token stays unavailable (astro)
  • hookMinRetentionWorkflow - terminal Hook cannot resume and its token stays unavailable (example)
  • hookMinRetentionWorkflow - terminal Hook cannot resume and its token stays unavailable (nextjs-turbopack)
  • hookMinRetentionWorkflow - terminal Hook cannot resume and its token stays unavailable (nextjs-webpack)
  • hookMinRetentionWorkflow - terminal Hook cannot resume and its token stays unavailable (tanstack-start)
  • Promise.all of disjoint-key writes: every key lands (example)
  • Promise.all of disjoint-key writes: every key lands (nitro)
  • setAttributesInsideStepWorkflow: step-body calls append attributed native events (example)
  • setAttributesInsideStepWorkflow: step-body calls append attributed native events (nextjs-webpack)
  • setAttributesWorkflow: workflow-body calls append native attr_set events and merge correctly (astro)
  • setAttributesWorkflow: workflow-body calls append native attr_set events and merge correctly (nextjs-turbopack)
  • sleepWinsRaceWorkflow (vite)
  • start: initial attributes are seeded on run creation (hono)
  • start: reserved-prefix initial attributes are seeded with allowReservedAttributes (example)
  • validation DX: invalid writes throw catchable FatalErrors naming rule and limit (example)
  • workflow throws after awaited setAttributes: attribute still persists on the failed run (tanstack-start)

🛠 Infra Events (absorbed by the harness)

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

  • cold-start-warmup · suite warmup (tanstack-start) · at 23:55:00Z · abandoned wrun_01M0GSJ24W06RJ478WRZ45G278

E2E Test Summary

Summary
Passed Failed Skipped Total
❌ ▲ Vercel Production 3407 171 742 4320
✅ 💻 Local Development 3922 0 558 4480
✅ 📦 Local Production 3922 0 558 4480
✅ 🐘 Local Postgres 3922 0 558 4480
✅ 🪟 Windows 320 0 0 320
✅ 🌐 Cross-language Conformance 9 0 132 141
✅ vercel-multi-region 27 0 0 27
Total 15529 171 2548 18248
Details by Category

❌ ▲ Vercel Production

App Passed Failed Skipped
❌ astro-node 129 3 28
❌ astro-quickjs 122 10 28
❌ example-node 128 4 28
❌ example-quickjs 124 8 28
❌ express-node 129 3 28
❌ express-quickjs 123 9 28
❌ fastify-node 127 5 28
❌ fastify-quickjs 122 10 28
❌ hono-node 130 2 28
❌ hono-quickjs 124 8 28
❌ nest-node 125 7 28
❌ nest-quickjs 126 6 28
❌ nextjs-turbopack-node 155 2 3
❌ nextjs-turbopack-quickjs 150 7 3
❌ nextjs-webpack-node 152 5 3
❌ nextjs-webpack-quickjs 147 10 3
❌ nitro-node 127 5 28
❌ nitro-quickjs 122 10 28
❌ nuxt-node 126 6 28
❌ nuxt-quickjs 123 9 28
✅ python-node 8 0 152
❌ sveltekit-node 146 5 9
❌ sveltekit-quickjs 142 9 9
❌ tanstack-start-node 128 4 28
❌ tanstack-start-quickjs 122 10 28
❌ vite-node 125 7 28
❌ vite-quickjs 125 7 28

✅ 💻 Local Development

App Passed Failed Skipped
✅ astro-stable-node 134 0 26
✅ astro-stable-quickjs 134 0 26
✅ express-stable-node 134 0 26
✅ express-stable-quickjs 134 0 26
✅ fastify-stable-node 134 0 26
✅ fastify-stable-quickjs 134 0 26
✅ hono-stable-node 134 0 26
✅ hono-stable-quickjs 134 0 26
✅ nest-stable-node 134 0 26
✅ nest-stable-quickjs 134 0 26
✅ nextjs-turbopack-canary-node 141 0 19
✅ nextjs-turbopack-canary-quickjs 141 0 19
✅ nextjs-turbopack-stable-node 160 0 0
✅ nextjs-turbopack-stable-quickjs 160 0 0
✅ nextjs-webpack-canary-node 141 0 19
✅ nextjs-webpack-canary-quickjs 141 0 19
✅ nextjs-webpack-stable-node 160 0 0
✅ nextjs-webpack-stable-quickjs 160 0 0
✅ nitro-stable-node 134 0 26
✅ nitro-stable-quickjs 134 0 26
✅ nuxt-stable-node 134 0 26
✅ nuxt-stable-quickjs 134 0 26
✅ sveltekit-stable-node 153 0 7
✅ sveltekit-stable-quickjs 153 0 7
✅ tanstack-start-node 134 0 26
✅ tanstack-start-quickjs 134 0 26
✅ vite-stable-node 134 0 26
✅ vite-stable-quickjs 134 0 26

✅ 📦 Local Production

App Passed Failed Skipped
✅ astro-stable-node 134 0 26
✅ astro-stable-quickjs 134 0 26
✅ express-stable-node 134 0 26
✅ express-stable-quickjs 134 0 26
✅ fastify-stable-node 134 0 26
✅ fastify-stable-quickjs 134 0 26
✅ hono-stable-node 134 0 26
✅ hono-stable-quickjs 134 0 26
✅ nest-stable-node 134 0 26
✅ nest-stable-quickjs 134 0 26
✅ nextjs-turbopack-canary-node 141 0 19
✅ nextjs-turbopack-canary-quickjs 141 0 19
✅ nextjs-turbopack-stable-node 160 0 0
✅ nextjs-turbopack-stable-quickjs 160 0 0
✅ nextjs-webpack-canary-node 141 0 19
✅ nextjs-webpack-canary-quickjs 141 0 19
✅ nextjs-webpack-stable-node 160 0 0
✅ nextjs-webpack-stable-quickjs 160 0 0
✅ nitro-stable-node 134 0 26
✅ nitro-stable-quickjs 134 0 26
✅ nuxt-stable-node 134 0 26
✅ nuxt-stable-quickjs 134 0 26
✅ sveltekit-stable-node 153 0 7
✅ sveltekit-stable-quickjs 153 0 7
✅ tanstack-start-node 134 0 26
✅ tanstack-start-quickjs 134 0 26
✅ vite-stable-node 134 0 26
✅ vite-stable-quickjs 134 0 26

✅ 🐘 Local Postgres

App Passed Failed Skipped
✅ astro-stable-node 134 0 26
✅ astro-stable-quickjs 134 0 26
✅ express-stable-node 134 0 26
✅ express-stable-quickjs 134 0 26
✅ fastify-stable-node 134 0 26
✅ fastify-stable-quickjs 134 0 26
✅ hono-stable-node 134 0 26
✅ hono-stable-quickjs 134 0 26
✅ nest-stable-node 134 0 26
✅ nest-stable-quickjs 134 0 26
✅ nextjs-turbopack-canary-node 141 0 19
✅ nextjs-turbopack-canary-quickjs 141 0 19
✅ nextjs-turbopack-stable-node 160 0 0
✅ nextjs-turbopack-stable-quickjs 160 0 0
✅ nextjs-webpack-canary-node 141 0 19
✅ nextjs-webpack-canary-quickjs 141 0 19
✅ nextjs-webpack-stable-node 160 0 0
✅ nextjs-webpack-stable-quickjs 160 0 0
✅ nitro-stable-node 134 0 26
✅ nitro-stable-quickjs 134 0 26
✅ nuxt-stable-node 134 0 26
✅ nuxt-stable-quickjs 134 0 26
✅ sveltekit-stable-node 153 0 7
✅ sveltekit-stable-quickjs 153 0 7
✅ tanstack-start-node 134 0 26
✅ tanstack-start-quickjs 134 0 26
✅ vite-stable-node 134 0 26
✅ vite-stable-quickjs 134 0 26

✅ 🪟 Windows

App Passed Failed Skipped
✅ nextjs-turbopack-node 160 0 0
✅ nextjs-turbopack-quickjs 160 0 0

✅ 🌐 Cross-language Conformance

App Passed Failed Skipped
✅ python 9 0 132

✅ vercel-multi-region

App Passed Failed Skipped
✅ nextjs-turbopack 27 0 0

📋 View full workflow run

@github-actions

github-actions Bot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

📊 Workflow Benchmarks

The benchmark run for a8726db failed. See the run logs for details.

No benchmark results were produced.

ℹ️ Metric definitions & methodology

Metrics —

All timestamps are deployment-side; runs are triggered in-deployment, so the CI runner and api.vercel.com sit outside every measured window. TTFS = start() → first step body (includes dispatch + any cold start); Fan-out TTFS/TTLS = first/last step completion of one Promise.all from the same anchor (the gap is the runtime’s fan-out spread); STSO/WO between step bodies; CRTT inside the workflow (excludes the api.vercel.com read path).

Cold starts stay in the numbers (real bursty-workload latency, inflates P75+); Best is the warm floor.

@vercel vercel Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional Suggestions:

  1. Docs state WORKFLOW_EVENTS_TRANSPORT default is http, but the code now defaults to WebSocket unless the value is exactly http.
  1. isWsEventsTransportEnabled unit tests still assert the old opt-in defaults, so they fail after the transport default flipped to WS (!== 'http').

Fix on Vercel

@github-actions

github-actions Bot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Sim World

Simulated world deterministic testing for races. Traces

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

fence=per-spec

scenario outcome events virt replay violations
smoke-no-steps completed 3 0ms ok 0
smoke-one-step completed 6 0ms ok 0
hook-at-step-started completed 12 0ms ok 0
hook-at-step-completed completed 12 0ms ok 0
hook-at-hook-created completed 12 0ms ok 0
deadline-hook-wins completed 7 1.0h ok 0
deadline-expires completed 7 1.0h ok 0
long-sleep completed 11 30.0d ok 0
hook-never-arrives stalled 3 0ms skipped 0
step-retries-twice completed 10 2.0s ok 0
parallel-steps completed 9 0ms ok 0
hook-on-execution-state completed 12 0ms ok 0
peek-hook-before-branch completed 12 0ms ok 0
peek-hook-after-branch completed 12 0ms ok 0
peek-hook-at-registration completed 12 0ms ok 0
race-hook-before-probe completed 12 0ms ok 0
race-hook-after-probe completed 12 0ms ok 0
race-duplicate-delivery completed 13 0ms ok 0
attr-hook-before-step completed 11 0ms ok 0
attr-hook-after-step completed 11 0ms ok 0
attr-from-step-body completed 13 0ms ok 0
fork-hook-after-timeout completed 14 1.0m ok 0
fork-hook-before-timeout completed 14 1.0m ok 0
count-hook-after-timeout completed 17 1.0m ok 0
count-hook-before-timeout completed 20 1.0m ok 0
stale-read-step-count-fork completed 20 1.0m ok 0
stale-read-equal-step-counts completed 14 1.0m ok 0
step-vs-step-fork completed 12 0ms ok 0
step-vs-step-fork-fenced completed 12 0ms ok 0
fence-catches-benign-direction completed 12 5ms ok 0
in-flight-before-decision completed 17 1.0m ok 0
in-flight-before-decision-counted completed 17 1.0m ok 0
in-flight-after-decision completed 19 2.0m ok 0
stale-read-step-count-fork-fenced completed 20 1.0m ok 0
fork-hook-wins completed 13 1.0m ok 0
fork-timeout-wins completed 13 1.0m ok 0
unclaimed-payload-under-fork completed 17 1.0m ok 0
claimed-payload-under-fork completed 17 1.0m ok 0
writers-independent-step-bodies completed 12 0ms ok 0
writers-scripted-tempo completed 12 0ms ok 0
cancel-mid-step cancelled 7 0ms skipped 0

Full trace: world-sim.txt

Three places still documented http as the default. Each now states the
opt-out is the exact value http, rather than leaving 'default: ws' to
imply that anything non-ws disables it — the asymmetry is deliberate in
the code and is the part a reader would otherwise get wrong.

Also drops 'Experimental' from the Vercel World page: a setting that is
on for everyone by default is not opt-in experimental, whatever else it
is.

Co-Authored-By: opencode <opencode@vercel.com>
Five tests in ws-transport.test.ts still encoded the opt-in semantics.
Three were the isWsEventsTransportEnabled table itself; the other two
(openWsChannel 'does nothing when the gate is off', and the channel
release equivalent) relied on the suite's ambient unset environment
meaning 'off', which it no longer does. Both now set http explicitly.

Two tests in ws-transport-spans.test.ts asserted HTTP-side span
behaviour the same way. The write one would have kept passing by
falling through resolveWsTransport's null rather than because the gate
was off - passing for the wrong reason, which is what this file exists
to catch.

Also makes the opt-out case-insensitive and trimmed. The gate is
deliberately asymmetric - unrecognized values take the default - but
that asymmetry should not extend to swallowing HTTP or ' http '.
Whoever reaches for the escape hatch is plausibly mid-incident, and
silently ignoring their opt-out over a capital letter is the same class
of silent-wrong-transport bug this flip is meant to stop shipping.

554 tests pass in packages/world-vercel.

Co-Authored-By: opencode <opencode@vercel.com>

shalabhc commented Aug 21, 2026

Copy link
Copy Markdown
Collaborator Author

Both bot suggestions are fixed.

e2e failures look preexisting on main.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant