Skip to content

refactor: switch from express to srvx - #3193

Merged
RihanArfan merged 9 commits into
mainfrom
rihan/replace-express-srvx
Sep 28, 2026
Merged

RihanArfan merged 9 commits into
mainfrom
rihan/replace-express-srvx

Conversation

@RihanArfan

Copy link
Copy Markdown
Member

Drops express from @workflow/web. srvx now provides the HTTP listener and static asset serving (srvx/static), and React Router's request handler is invoked directly instead of through the @react-router/express adapter.

This works because srvx and React Router both speak the Web-standard Request/Response

@RihanArfan
RihanArfan requested review from a team and ijjk as code owners July 29, 2026 20:37
@changeset-bot

changeset-bot Bot commented Jul 29, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 2b5fd8b

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

This PR includes changesets to release 16 packages
Name Type
@workflow/cli Patch
@workflow/web Major
workflow Patch
@workflow/world-testing Patch
@workflow/nitro Patch
@workflow/nuxt Patch
@workflow/core Patch
@workflow/web-shared Major
@workflow/builders Patch
@workflow/next Patch
@workflow/vitest Patch
@workflow/astro Patch
@workflow/nest Patch
@workflow/rollup Patch
@workflow/sveltekit Patch
@workflow/vite 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 Jul 29, 2026 •

Copy link
Copy Markdown
Contributor

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

Project Deployment Actions Updated
example-nextjs-workflow-turbopack Ready Ready Preview, v0 Sep 25, 2026 2:54pm UTC
example-nextjs-workflow-webpack Ready Ready Preview, v0 Sep 25, 2026 2:54pm UTC
example-workflow Ready Ready Preview, v0 Sep 25, 2026 2:54pm UTC
workbench-astro-workflow Ready Ready Preview, v0 Sep 25, 2026 2:54pm UTC
workbench-express-workflow Ready Ready Preview, v0 Sep 25, 2026 2:54pm UTC
workbench-fastify-workflow Ready Ready Preview, v0 Sep 25, 2026 2:54pm UTC
workbench-hono-workflow Ready Ready Preview, v0 Sep 25, 2026 2:54pm UTC
workbench-nestjs-workflow Ready Ready Preview, v0 Sep 25, 2026 2:54pm UTC
workbench-nitro-workflow Ready Ready Preview, v0 Sep 25, 2026 2:54pm UTC
workbench-nuxt-workflow Ready Ready Preview, v0 Sep 25, 2026 2:54pm UTC
workbench-python-workflow Ready Ready Preview, v0 Sep 25, 2026 2:54pm UTC
workbench-sveltekit-workflow Ready Ready Preview, v0 Sep 25, 2026 2:54pm UTC
workbench-tanstack-start-workflow Ready Ready Preview, v0 Sep 25, 2026 2:54pm UTC
workbench-vite-workflow Ready Ready Preview, v0 Sep 25, 2026 2:54pm UTC
workflow-docs Ready Ready Preview, v0 Sep 25, 2026 2:54pm UTC
workflow-swc-playground Ready Ready Preview, v0 Sep 25, 2026 2:54pm UTC
workflow-tarballs Ready Ready Preview, v0 Sep 25, 2026 2:54pm UTC
workflow-web Ready Ready Preview, v0 Sep 25, 2026 2:54pm UTC

Base automatically changed from pgp/nitro-web-integration to main July 29, 2026 20:59
@RihanArfan
RihanArfan force-pushed the rihan/replace-express-srvx branch from f018aaf to 956769e Compare July 29, 2026 23:05
@github-actions

github-actions Bot commented Jul 29, 2026 •

Copy link
Copy Markdown
Contributor

🧪 E2E Test Results

❌ Some tests failed

❌ Failed E2E Tests

▲ Vercel Production (62 failed)

python-node (62 failed):

  • promiseAllWorkflow | wrun_41M3CGX17P0GQVS889XQM3VK0T | 🔍 observability
  • promiseRaceWorkflow | wrun_41M3CGX17P0GQVS889XQM3VK0V | 🔍 observability
  • promiseAnyWorkflow | wrun_41M3CGX17P0GQVS889XQM3VK0W | 🔍 observability
  • retainedInterleavingWorkflow | wrun_41M3CGX7WW0GMSCPFXDEP9KATM | 🔍 observability
  • hookWorkflow | wrun_41M3CGXD730GN30FX42HKE82Z2 | 🔍 observability
  • hookWorkflow is not resumable via public webhook endpoint | wrun_41M3CGXDAG0GXZYMYZSVFEK0VY | 🔍 observability
  • sleepingWorkflow | wrun_41M3CGXQ660GRD6AC2XCK40R00 | 🔍 observability
  • parallelSleepWorkflow | wrun_41M3CGXQP80GWV631HWPM3BY08 | 🔍 observability
  • sleepWinsRaceWorkflow | wrun_41M3CGXVTM0GH1CS0MSRRF0R95 | 🔍 observability
  • stepWinsRaceWorkflow | wrun_41M3CGXWH80GPTFFF163SV7TDQ | 🔍 observability
  • nullByteWorkflow | wrun_41M3CGXY8K0GXRC912V285CTGD | 🔍 observability
  • outputStreamWorkflow no startIndex (reads all chunks)
  • outputStreamWorkflow positive startIndex (skips first chunk)
  • outputStreamWorkflow negative startIndex (reads from end)
  • outputStreamWorkflow - getTailIndex and getChunks getTailIndex returns correct index after stream completes
  • outputStreamWorkflow - getTailIndex and getChunks getChunks returns same content as reading the stream
  • outputStreamInsideStepWorkflow - getWritable() called inside step functions | wrun_41M3CGYKE60GTDX36NYTA8WPSR | 🔍 observability
  • utf8StreamWorkflow | wrun_41M3CGYKWQ0GW8DPHSJZPYMEYJ | 🔍 observability
  • writableForwardedFromWorkflowWorkflow | wrun_41M3CGYMWC0GHKYD1GD56TYAQ6 | 🔍 observability
  • writableForwardedFromStepWorkflow | wrun_41M3CGYQBC0GQ7YK9BJJC677V6 | 🔍 observability
  • promiseRaceStressTestWorkflow | wrun_41M3CGYSKY0GJZYT6SY51M5QNN | 🔍 observability
  • error handling retry behavior regular Error retries until success
  • error handling retry behavior FatalError fails immediately without retries
  • error handling retry behavior RetryableError respects custom retryAfter delay
  • error handling retry behavior maxRetries=0 disables retries
  • error handling catchability FatalError can be caught and detected with FatalError.is()
  • error handling catchability step throw round-trips FatalError with cause chain to workflow catch
  • error handling catchability workflow throw round-trips FatalError + cause through run_failed event
  • error handling not registered StepNotRegisteredError fails the step but workflow can catch it
  • error handling not registered StepNotRegisteredError fails the run when not caught in workflow
  • hookCleanupTestWorkflow - hook token reuse after workflow completion | wrun_41M3CH0FZ30GXE8VWG52YJAE4W | 🔍 observability
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_41M3CH09PD0GRSMZ260PCS06N5 | 🔍 observability
  • hookGetConflictWorkflow - awaiting hook.getConflict() registers hook without payload | wrun_41M3CH0E6T0GXXWAAE7VDCXWE0 | 🔍 observability
  • 'hookGetConflictWithPriorStepWorkflow' - hook.getConflict() does not block step execution | wrun_41M3CH0J930GVSMJVF5VZ0V1F9 | 🔍 observability
  • 'hookGetConflictWithParallelStepWorkfl…' - hook.getConflict() does not block step execution | wrun_41M3CH0MWK0GZY6D8BDYNCV4NP | 🔍 observability
  • hookGetConflictThenStepParallelWorkflow - hook.getConflict() continuation step runs alongside other steps | wrun_41M3CH0MWX0GJSKWZPHSKYB9CN | 🔍 observability
  • hookGetConflictWorkflow - hook.getConflict() resolves with the conflicting run when token is already registered | wrun_41M3CH0T1F0GTBQSNVQRNC7E67 | 🔍 observability
  • hookClaimOnlyMutexWorkflow - hook works as a pure run mutex without payload data | wrun_41M3CH1JDK0GKAS9AHA187CBBE | 🔍 observability
  • hookAdoptOwnerResultWorkflow - duplicate adopts the owner result via conflict.returnValue | wrun_41M3CH12580GX0N8G4DN1H650B | 🔍 observability
  • hookSignalOwnerWorkflow - duplicate forwards its payload to the owner via resumeHook | wrun_41M3CH16JM0GV5GN2BDVCPPWAR | 🔍 observability
  • resume-or-start route pattern - resumeHook retried after start() reaches the new run | wrun_41M3CH1VH30GJ5NS8KKKMZEXTH | 🔍 observability
  • hookDisposeTestWorkflow - hook token reuse after explicit disposal while workflow still running | wrun_41M3CH21GK0GTSDHB47SEYNGSV | 🔍 observability
  • hookTokenReuseLoopWorkflow - same run recreates a hook with the same token after dispose() | wrun_41M3CH22V20GNVC7TMGMHDH1WE | 🔍 observability
  • spawnWorkflowFromStepWorkflow - spawning a child workflow using start() inside a step | wrun_41M3CH2PR20GX023K84QXK56BP | 🔍 observability
  • cancelRun - cancelling a running workflow | wrun_41M3CH3SP30GPRGM5HYBJ3PP9Y | 🔍 observability
  • cancelRun via CLI - cancelling a running workflow | wrun_41M3CH3SPQ0GSVN9Y7YDPS0MRW | 🔍 observability
  • hookWithSleepWorkflow - hook payloads delivered correctly with concurrent sleep | wrun_41M3CH3SWJ0GJVW1C4GX6TN44N | 🔍 observability
  • hookWithSleepFinalStepWorkflow - step only on final payload | wrun_41M3CH41FF0GJRQ17N6WRTQB8M | 🔍 observability
  • sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration | wrun_41M3CH422Q0GN8NQ30HZWEBXN2 | 🔍 observability
  • sleepWithSequentialStepsWorkflow - sequential steps work with concurrent sleep (control) | wrun_41M3CH42MV0GNRSF86NF062GMB | 🔍 observability
  • AbortController abortTimeoutWorkflow: timeout cancels long-running step
  • AbortController abortParallelWorkflow: abort cancels all parallel steps
  • AbortController abortReasonWorkflow: abort reason preserved across boundaries
  • AbortController abortViaHookWorkflow: external hook triggers abort on in-flight step
  • metadataFromHelperWorkflow - getWorkflowMetadata/getStepMetadata work from module-level helper (#1577) | wrun_41M3CH4KSJ0GHAS1CMNJ5R23G1 | 🔍 observability
  • resilient start: addTenWorkflow completes when run_created returns 500 | wrun_41M3CH4M780GZS7CQWQHRP2ZS1 | 🔍 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

⚠️ 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.

  • fires constructor + stream callbacks in order (nextjs-webpack · vercel-prod / vercel / node / production)

🛠 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.

124 infra events
  • cold-start-warmup · suite warmup (python) · at 14:54:56Z · abandoned wrun_41M3CGW82R0GVHS7RQ2MWKA69T · (+7 more)
  • run-pickup-stall · promiseAllWorkflow (python) · at 14:55:12Z · abandoned wrun_41M3CGZX1Y0GMWQXCBPAX2SG8E
  • run-pickup-stall · promiseAnyWorkflow (python) · at 14:55:13Z · abandoned wrun_41M3CGZX1Y0GMWQXCBPAX2SG8G
  • run-pickup-stall · hookWorkflow (python) · at 14:55:13Z · abandoned wrun_41M3CGZX230GSFCQ22H2JQ14KW
  • run-pickup-stall · promiseRaceWorkflow (python) · at 14:55:13Z · abandoned wrun_41M3CGZX1Y0GMWQXCBPAX2SG8F
  • run-pickup-stall · retainedInterleavingWorkflow (python) · at 14:55:13Z · abandoned wrun_41M3CGZX1Y0GMWQXCBPAX2SG8H
  • run-pickup-stall · hookWorkflow (python) · at 14:56:00Z · abandoned wrun_41M3CH1BHH0GR38E2GJW8PC80C
  • run-pickup-stall · retainedInterleavingWorkflow (python) · at 14:56:00Z · abandoned wrun_41M3CH1BGJ0GGNMVN6N7FTE358
  • run-pickup-stall · promiseRaceWorkflow (python) · at 14:56:13Z · abandoned wrun_41M3CH1RE60GJMYM70ZT2KSAE2
  • run-pickup-stall · promiseAllWorkflow (python) · at 14:56:13Z · abandoned wrun_41M3CH1RGB0GRZK8JRJBK58TAJ
  • run-pickup-stall · promiseAnyWorkflow (python) · at 14:56:13Z · abandoned wrun_41M3CH1RK30GNYRQDA0A3P7FW5
  • cold-start-warmup · suite warmup (tanstack-start) · at 14:56:38Z · abandoned wrun_01M3CH2AA51H3SJAH87MA8PQE7
  • run-pickup-stall · hookWorkflow is not resumable via public webhook endpoint (python) · at 14:56:47Z · abandoned wrun_41M3CH2SXJ0GZHSGTK2VHSB2SF
  • run-pickup-stall · sleepingWorkflow (python) · at 14:56:48Z · abandoned wrun_41M3CH2SYN0GWV88MFECXRQWME
  • run-pickup-stall · hookWorkflow (nuxt) · at 14:57:02Z · abandoned wrun_01M3CH39FS65D9359KJZXEDNQ7
  • run-pickup-stall · parallelSleepWorkflow (python) · at 14:57:16Z · abandoned wrun_41M3CH3M9H0GJQJJHYNAPKYFT1
  • run-pickup-stall · sleepWinsRaceWorkflow (python) · at 14:57:17Z · abandoned wrun_41M3CH3MH30GVKD0ZP2E59YNHE
  • run-pickup-stall · stepWinsRaceWorkflow (python) · at 14:57:17Z · abandoned wrun_41M3CH3N0X0GHC4XBM68THYAS1
  • run-pickup-stall · hookWorkflow is not resumable via public webhook endpoint (python) · at 14:58:44Z · abandoned wrun_41M3CH5B6B0GQEX0G2EK80YHJ0
  • run-pickup-stall · sleepingWorkflow (python) · at 14:58:44Z · abandoned wrun_41M3CH5BCS0GSKK80T2338MMB9
  • run-pickup-stall · sleepWinsRaceWorkflow (python) · at 14:58:51Z · abandoned wrun_41M3CH6CDN0GTFQZ76BTGWDSMK
  • run-pickup-stall · parallelSleepWorkflow (python) · at 14:58:51Z · abandoned wrun_41M3CH6C640GHAFTGBWFRDY4H6
  • run-pickup-stall · stepWinsRaceWorkflow (python) · at 14:58:51Z · abandoned wrun_41M3CH6CXD0GVQXTFV9RDB448T
  • run-pickup-stall · no startIndex (reads all chunks) (python) · at 14:59:12Z · abandoned wrun_41M3CH76RC0GKAF1GT7N7B2EZH
  • run-pickup-stall · nullByteWorkflow (python) · at 14:59:12Z · abandoned wrun_41M3CH76MN0GW5YGG8E6S4MTFB
  • run-pickup-stall · negative startIndex (reads from end) (python) · at 14:59:45Z · abandoned wrun_41M3CH870P0GWMKSEF9EQWV0Z7
  • run-pickup-stall · positive startIndex (skips first chunk) (python) · at 14:59:45Z · abandoned wrun_41M3CH86S40GSC3X41W4Q7CWST
  • run-pickup-stall · getTailIndex returns correct index after stream completes (python) · at 14:59:47Z · abandoned wrun_41M3CH89RM0GXAPSESF5P0TF9R
  • run-pickup-stall · getTailIndex returns -1 before any chunks are written (python) · at 15:00:12Z · abandoned wrun_41M3CH917N0GQ3AG0VQXNGT8EX
  • run-pickup-stall · getChunks returns same content as reading the stream (python) · at 15:00:12Z · abandoned wrun_41M3CH91BB0GJT2Q54RQRKD128
  • run-pickup-stall · outputStreamInsideStepWorkflow - getWritable() called inside step functions (python) · at 15:00:28Z · abandoned wrun_41M3CH9HGV0GK5PN370TJGDEGH
  • run-pickup-stall · utf8StreamWorkflow (python) · at 15:00:45Z · abandoned wrun_41M3CHA1C40GH61Y9AGQ92V06T
  • run-pickup-stall · nullByteWorkflow (python) · at 15:00:48Z · abandoned wrun_41M3CHA4BN0GKAPR6QW6KT22WF
  • run-pickup-stall · no startIndex (reads all chunks) (python) · at 15:00:48Z · abandoned wrun_41M3CHA4TC0GMQ21J02CGSRQ2N
  • run-pickup-stall · positive startIndex (skips first chunk) (python) · at 15:01:12Z · abandoned wrun_41M3CHAVYC0GW65C8CWQZY1EA0
  • run-pickup-stall · negative startIndex (reads from end) (python) · at 15:01:29Z · abandoned wrun_41M3CHBCWN0GH4R234WT53RNPM
  • run-pickup-stall · getTailIndex returns correct index after stream completes (python) · at 15:01:48Z · abandoned wrun_41M3CHBZPX0GH16JDGAXVH0NTV
  • run-pickup-stall · getChunks returns same content as reading the stream (python) · at 15:01:50Z · abandoned wrun_41M3CHC1JR0GKD9DCYQE644KPV
  • run-pickup-stall · outputStreamInsideStepWorkflow - getWritable() called inside step functions (python) · at 15:02:12Z · abandoned wrun_41M3CHCPHC0GY0V57T0376NCAT
  • run-pickup-stall · writableForwardedFromWorkflowWorkflow (python) · at 15:02:29Z · abandoned wrun_41M3CHD7FP0GVWWG3MHH0V4XC0
  • run-pickup-stall · writableForwardedFromStepWorkflow (python) · at 15:02:47Z · abandoned wrun_41M3CHDRZK0GYFVPXANQF2XG9P
  • run-pickup-stall · utf8StreamWorkflow (python) · at 15:02:48Z · abandoned wrun_41M3CHDT9X0GWWDQQJ29B0M4A4
  • run-pickup-stall · promiseRaceStressTestWorkflow (python) · at 15:02:52Z · abandoned wrun_41M3CHDXTR0GTVR6Q7XWT2YYAZ
  • run-pickup-stall · regular Error retries until success (python) · at 15:03:13Z · abandoned wrun_41M3CHEHVT0GKBSPF89S26YSM4
  • run-pickup-stall · FatalError fails immediately without retries (python) · at 15:03:52Z · abandoned wrun_41M3CHFRDR0GM7BXJBJ9G12YSH
  • run-pickup-stall · RetryableError respects custom retryAfter delay (python) · at 15:04:12Z · abandoned wrun_41M3CHGCEV0GXZ33DAJF168FMH
  • run-pickup-stall · maxRetries=0 disables retries (python) · at 15:04:29Z · abandoned wrun_41M3CHGWNP0GW48C14X4DD22D4
  • run-pickup-stall · FatalError can be caught and detected with FatalError.is() (python) · at 15:04:47Z · abandoned wrun_41M3CHHE5J0GJTG1FHM3FQ513C
  • run-pickup-stall · step throw round-trips FatalError with cause chain to workflow catch (python) · at 15:04:48Z · abandoned wrun_41M3CHHFFX0GW40766SNS59YSP
  • run-pickup-stall · workflow throw round-trips FatalError + cause through run_failed event (python) · at 15:04:52Z · abandoned wrun_41M3CHHK0R0GTBWZF4HE44KDVS
  • run-pickup-stall · StepNotRegisteredError fails the step but workflow can catch it (python) · at 15:05:13Z · abandoned wrun_41M3CHJ71W0GQWNMA7R0CHF8B6
  • run-pickup-stall · StepNotRegisteredError fails the run when not caught in workflow (python) · at 15:05:32Z · abandoned wrun_41M3CHJQ8Q0GXTKFXSRR8MN7KF
  • run-pickup-stall · writableForwardedFromWorkflowWorkflow (python) · at 15:07:01Z · abandoned wrun_41M3CHMNTP0GT1XSM44YQB4HBN
  • run-pickup-stall · promiseRaceStressTestWorkflow (python) · at 15:07:06Z · abandoned wrun_41M3CHMHVR0GN16NFQM942ZDZ6
  • run-pickup-stall · regular Error retries until success (python) · at 15:07:07Z · abandoned wrun_41M3CHMKMD0GGYC5S17EN31WG3
  • run-pickup-stall · writableForwardedFromStepWorkflow (python) · at 15:07:11Z · abandoned wrun_41M3CHN55E0GZ8CJEV4ZQMY5BF
  • run-pickup-stall · hookCleanupTestWorkflow - hook token reuse after workflow completion (python) · at 15:07:23Z · abandoned wrun_41M3CHN7480GH5TFG7WHYJ802M
  • run-pickup-stall · FatalError fails immediately without retries (python) · at 15:08:10Z · abandoned wrun_41M3CHPE7D0GN8YSK5MWR07XMW
  • run-pickup-stall · RetryableError respects custom retryAfter delay (python) · at 15:08:31Z · abandoned wrun_41M3CHQ1Q80GQ2MY1JWSNC4CGZ
  • run-pickup-stall · maxRetries=0 disables retries (python) · at 15:08:43Z · abandoned wrun_41M3CHR71S0GN4NPHKFSEWFERK
  • run-pickup-stall · FatalError can be caught and detected with FatalError.is() (python) · at 15:08:43Z · abandoned wrun_41M3CHR8TD0GNGVJFK6SFR1YK2
  • run-pickup-stall · workflow throw round-trips FatalError + cause through run_failed event (python) · at 15:08:43Z · abandoned wrun_41M3CHRB0N0GTNSXGBE2FCNNMG
  • run-pickup-stall · step throw round-trips FatalError with cause chain to workflow catch (python) · at 15:08:51Z · abandoned wrun_41M3CHRTBE0GPQ172K81VTKAJ9
  • run-pickup-stall · StepNotRegisteredError fails the step but workflow can catch it (python) · at 15:08:55Z · abandoned wrun_41M3CHS0MB0GGNRK3BWGF0R7A0
  • run-pickup-stall · StepNotRegisteredError fails the run when not caught in workflow (python) · at 15:09:29Z · abandoned wrun_41M3CHT1MR0GNZQCF3VCYA1GGT
  • run-pickup-stall · hookCleanupTestWorkflow - hook token reuse after workflow completion (python) · at 15:09:34Z · abandoned wrun_41M3CHT69N0GTMNGPF6G925N4B
  • run-pickup-stall · hookGetConflictWorkflow - awaiting hook.getConflict() registers hook without payload (python) · at 15:09:50Z · abandoned wrun_41M3CHTPB90GWQS67A6FEE3E1M
  • run-pickup-stall · 'hookGetConflictWithPriorStepWorkflow' - hook.getConflict() does not block step execution (python) · at 15:09:56Z · abandoned wrun_41M3CHTVXB0GMBYYWVR2JRYCSR
  • run-pickup-stall · 'hookGetConflictWithParallelStepWorkfl…' - hook.getConflict() does not block step execution (python) · at 15:10:21Z · abandoned wrun_41M3CHVMBK0GHT9QNY4BXH7ZJ7
  • run-pickup-stall · hookGetConflictThenStepParallelWorkflow - hook.getConflict() continuation step runs alongside other steps (python) · at 15:10:30Z · abandoned wrun_41M3CHVWX30GS636YTZMZT5ZQC
  • run-pickup-stall · hookGetConflictWorkflow - hook.getConflict() resolves with the conflicting run when token is already registered (python) · at 15:10:37Z · abandoned wrun_41M3CHW43Q0GTNM8X7DFKQ56NT
  • run-pickup-stall · hookGetConflictWorkflow - awaiting hook.getConflict() registers hook without payload (python) · at 15:10:51Z · abandoned wrun_41M3CHWHNA0GMSSQP6QK2M8VPH
  • run-pickup-stall · 'hookGetConflictWithPriorStepWorkflow' - hook.getConflict() does not block step execution (python) · at 15:10:57Z · abandoned wrun_41M3CHWQ9G0GN4GPBGE5H2646V
  • run-pickup-stall · 'hookGetConflictWithParallelStepWorkfl…' - hook.getConflict() does not block step execution (python) · at 15:11:22Z · abandoned wrun_41M3CHXFNM0GVMNZYYCB2BQ988
  • run-pickup-stall · hookGetConflictWorkflow - hook.getConflict() resolves with the conflicting run when token is already registered (python) · at 15:11:24Z · abandoned wrun_41M3CHXJ1A0GY3DT5XAJ8KC5MS
  • run-pickup-stall · hookClaimOnlyMutexWorkflow - hook works as a pure run mutex without payload data (python) · at 15:11:52Z · abandoned wrun_41M3CHYCYQ0GNHTJ1BPXY164WX
  • run-pickup-stall · hookAdoptOwnerResultWorkflow - duplicate adopts the owner result via conflict.returnValue (python) · at 15:11:57Z · abandoned wrun_41M3CHYJK10GZM3XBHWDWYVX43
  • run-pickup-stall · hookGetConflictThenStepParallelWorkflow - hook.getConflict() continuation step runs alongside other steps (python) · at 15:12:01Z · abandoned wrun_41M3CHYNHM0GT7CJ2YS8G39SWD
  • run-pickup-stall · hookSignalOwnerWorkflow - duplicate forwards its payload to the owner via resumeHook (python) · at 15:12:11Z · abandoned wrun_41M3CHZ00B0GXBKER1NSZ4PBA3
  • run-pickup-stall · resume-or-start route pattern - resumeHook retried after start() reaches the new run (python) · at 15:12:23Z · abandoned wrun_41M3CHZB7M0GTEETR58QFVCDPF
  • run-pickup-stall · hookClaimOnlyMutexWorkflow - hook works as a pure run mutex without payload data (python) · at 15:12:39Z · abandoned wrun_41M3CHZV3R0GGNE974VPR30QWQ
  • run-pickup-stall · hookAdoptOwnerResultWorkflow - duplicate adopts the owner result via conflict.returnValue (python) · at 15:12:45Z · abandoned wrun_41M3CJ00RG0GXND58VFNK0ACVT
  • run-pickup-stall · hookSignalOwnerWorkflow - duplicate forwards its payload to the owner via resumeHook (python) · at 15:12:59Z · abandoned wrun_41M3CJ0E6J0GJK8BAZ4GVBX6VC
  • run-pickup-stall · resume-or-start route pattern - resumeHook retried after start() reaches the new run (python) · at 15:13:10Z · abandoned wrun_41M3CJ0SBY0GH9V30ZJN9RC16B
  • run-pickup-stall · hookDisposeTestWorkflow - hook token reuse after explicit disposal while workflow still running (python) · at 15:13:26Z · abandoned wrun_41M3CJ199W0GZVJBDZFNTFGTB4
  • run-pickup-stall · hookTokenReuseLoopWorkflow - same run recreates a hook with the same token after dispose() (python) · at 15:13:31Z · abandoned wrun_41M3CJ1E560GTMH7W3A7M99SMY
  • run-pickup-stall · spawnWorkflowFromStepWorkflow - spawning a child workflow using start() inside a step (python) · at 15:13:32Z · abandoned wrun_41M3CJ1ERZ0GJ3YTF02PCBSK0R
  • run-pickup-stall · cancelRun - cancelling a running workflow (python) · at 15:13:52Z · abandoned wrun_41M3CJ22CM0GWS0SB10GTPN29Z
  • run-pickup-stall · cancelRun via CLI - cancelling a running workflow (python) · at 15:13:57Z · abandoned wrun_41M3CJ27HC0GKHKZNDSW0HZDDX
  • run-pickup-stall · hookDisposeTestWorkflow - hook token reuse after explicit disposal while workflow still running (python) · at 15:14:14Z · abandoned wrun_41M3CJ2QT50GZ1F7ECTPTK86GE
  • run-pickup-stall · hookTokenReuseLoopWorkflow - same run recreates a hook with the same token after dispose() (python) · at 15:14:18Z · abandoned wrun_41M3CJ2W3J0GMS4N8YQHN6RQFZ
  • run-pickup-stall · cancelRun - cancelling a running workflow (python) · at 15:14:24Z · abandoned wrun_41M3CJ31VQ0GNE5G2NHTBTVNMP
  • run-pickup-stall · cancelRun via CLI - cancelling a running workflow (python) · at 15:14:29Z · abandoned wrun_41M3CJ36WZ0GY3SVGNP5RCEN31
  • run-pickup-stall · hookWithSleepWorkflow - hook payloads delivered correctly with concurrent sleep (python) · at 15:14:56Z · abandoned wrun_41M3CJ41390GVRNQ8Q1JJGET9B
  • run-pickup-stall · hookWithSleepFinalStepWorkflow - step only on final payload (python) · at 15:15:01Z · abandoned wrun_41M3CJ46230GJ4Q1YVTM2ESGCK
  • run-pickup-stall · sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration (python) · at 15:15:01Z · abandoned wrun_41M3CJ46880GW53PERDP0ZG17A
  • run-pickup-stall · sleepWithSequentialStepsWorkflow - sequential steps work with concurrent sleep (control) (python) · at 15:15:06Z · abandoned wrun_41M3CJ4A7S0GSSVEFYNCGD0XWS
  • run-pickup-stall · spawnWorkflowFromStepWorkflow - spawning a child workflow using start() inside a step (python) · at 15:15:33Z · abandoned wrun_41M3CJ55300GJNTHWZWH660PV0
  • run-pickup-stall · hookWithSleepWorkflow - hook payloads delivered correctly with concurrent sleep (python) · at 15:15:45Z · abandoned wrun_41M3CJ5FF90GQFEVKEN1QMFRHF
  • run-pickup-stall · hookWithSleepFinalStepWorkflow - step only on final payload (python) · at 15:15:49Z · abandoned wrun_41M3CJ5MFJ0GHCGWYV7RHGB39N
  • run-pickup-stall · sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration (python) · at 15:16:03Z · abandoned wrun_41M3CJ61X00GNFJSDRBF7E6XY8
  • run-pickup-stall · sleepWithSequentialStepsWorkflow - sequential steps work with concurrent sleep (control) (python) · at 15:16:07Z · abandoned wrun_41M3CJ65V40GMNGZV6YHYTBH3M
  • run-pickup-stall · abortTimeoutWorkflow: timeout cancels long-running step (python) · at 15:16:34Z · abandoned wrun_41M3CJ70PW0GKJAH28M3RPSJR2
  • run-pickup-stall · abortParallelWorkflow: abort cancels all parallel steps (python) · at 15:16:36Z · abandoned wrun_41M3CJ71WN0GG6PJNNN3B7X6AE
  • run-pickup-stall · abortReasonWorkflow: abort reason preserved across boundaries (python) · at 15:17:26Z · abandoned wrun_41M3CJ7WG00GH5PGFAX59WZQ1A
  • run-pickup-stall · abortViaHookWorkflow: external hook triggers abort on in-flight step (python) · at 15:17:55Z · abandoned wrun_41M3CJ8T900GK0ZC240NK6N67Q
  • run-pickup-stall · metadataFromHelperWorkflow - getWorkflowMetadata/getStepMetadata work from module-level helper (Vercel World Regression: getWorkflowMetadata() fully breaking runs #1577) (python) · at 15:17:58Z · abandoned wrun_41M3CJ8WFN0GJNPSKGKYVE4WH2
  • run-pickup-stall · abortTimeoutWorkflow: timeout cancels long-running step (python) · at 15:18:56Z · abandoned wrun_41M3CJAG0F0GZQ6JC8E1XW0ECT
  • run-pickup-stall · start: initial attributes are seeded on run creation (python) · at 15:19:00Z · abandoned wrun_41M3CJAMW00GTBW55FYBM7K6P7
  • run-pickup-stall · start: reserved-prefix initial attributes are seeded with allowReservedAttributes (python) · at 15:19:03Z · abandoned wrun_41M3CJAQ2K0GV9JF5K2ZC9GC1F
  • run-pickup-stall · setAttributesWorkflow: workflow-body calls append native attr_set events and merge correctly (python) · at 15:19:29Z · abandoned wrun_41M3CJAXKM0GRY1PRVP47B4K17
  • run-pickup-stall · setAttributesInsideStepWorkflow: step-body calls append attributed native events (python) · at 15:19:36Z · abandoned wrun_41M3CJBHP10GW2EB40KB606KAK
  • run-pickup-stall · abortParallelWorkflow: abort cancels all parallel steps (python) · at 15:19:36Z · abandoned wrun_41M3CJBJ5G0GMXZ5AFHT9EHBEV
  • run-pickup-stall · abortReasonWorkflow: abort reason preserved across boundaries (python) · at 15:19:48Z · abandoned wrun_41M3CJCAKE0GJV93J111CKGT5X
  • run-pickup-stall · Promise.all of disjoint-key writes: every key lands (python) · at 15:19:55Z · abandoned wrun_41M3CJCR6K0GZPXXFEYM5F14M2
  • run-pickup-stall · abortViaHookWorkflow: external hook triggers abort on in-flight step (python) · at 15:20:07Z · abandoned wrun_41M3CJDEYH0GNDHA76RBETWD74
  • run-pickup-stall · metadataFromHelperWorkflow - getWorkflowMetadata/getStepMetadata work from module-level helper (Vercel World Regression: getWorkflowMetadata() fully breaking runs #1577) (python) · at 15:20:08Z · abandoned wrun_41M3CJDH7R0GHK9JNWKP1G4QHY
  • run-pickup-stall · start: initial attributes are seeded on run creation (python) · at 15:20:12Z · abandoned wrun_41M3CJDNG50GSNY57G4FKKZDNY
  • run-pickup-stall · start: reserved-prefix initial attributes are seeded with allowReservedAttributes (python) · at 15:20:21Z · abandoned wrun_41M3CJDY5E0GNB8P476GBEY686
  • run-pickup-stall · setAttributesWorkflow: workflow-body calls append native attr_set events and merge correctly (python) · at 15:20:29Z · abandoned wrun_41M3CJE5XG0GPR31K1SRGW01VH
  • run-pickup-stall · setAttributesInsideStepWorkflow: step-body calls append attributed native events (python) · at 15:20:42Z · abandoned wrun_41M3CJEJSN0GKC846PK4HRA45E
  • run-pickup-stall · Promise.all of disjoint-key writes: every key lands (python) · at 15:20:54Z · abandoned wrun_41M3CJEYGK0GNH6PGJRRMR6X8J
  • run-pickup-stall · workflow throws after awaited setAttributes: attribute still persists on the failed run (python) · at 15:20:54Z · abandoned wrun_41M3CJEYQX0GPXFKREQH4JCY2C
  • run-pickup-stall · workflow throws after awaited setAttributes: attribute still persists on the failed run (python) · at 15:21:25Z · abandoned wrun_41M3CJFWRT0GPRBT1X821MYQ7C

E2E Test Summary

Summary
Passed Failed Skipped Total
❌ ▲ Vercel Production 3816 62 739 4617
✅ 💻 Local Development 4238 0 550 4788
✅ 📦 Local Production 4238 0 550 4788
✅ 🐘 Local Postgres 4238 0 550 4788
✅ 🪟 Windows 340 0 2 342
✅ vercel-http-transport 873 0 153 1026
✅ vercel-multi-region 27 0 0 27
✅ vercel-ws-transport 591 0 93 684
Total 18361 62 2637 21060
Details by Category

❌ ▲ Vercel Production

App Passed Failed Skipped
✅ astro-node 141 0 30
✅ astro-quickjs 141 0 30
✅ example-node 141 0 30
✅ example-quickjs 141 0 30
✅ express-node 141 0 30
✅ express-quickjs 141 0 30
✅ fastify-node 141 0 30
✅ fastify-quickjs 141 0 30
✅ hono-node 141 0 30
✅ hono-quickjs 141 0 30
✅ nest-node 141 0 30
✅ nest-quickjs 141 0 30
✅ nextjs-turbopack-node 168 0 3
✅ nextjs-turbopack-quickjs 168 0 3
✅ nextjs-webpack-node 168 0 3
✅ nextjs-webpack-quickjs 168 0 3
✅ nitro-node 141 0 30
✅ nitro-quickjs 141 0 30
✅ nuxt-node 141 0 30
✅ nuxt-quickjs 141 0 30
❌ python-node 4 62 105
✅ sveltekit-node 160 0 11
✅ sveltekit-quickjs 160 0 11
✅ tanstack-start-node 141 0 30
✅ tanstack-start-quickjs 141 0 30
✅ vite-node 141 0 30
✅ vite-quickjs 141 0 30

✅ 💻 Local Development

App Passed Failed Skipped
✅ astro-stable-node 142 0 29
✅ astro-stable-quickjs 142 0 29
✅ express-stable-node 142 0 29
✅ express-stable-quickjs 142 0 29
✅ fastify-stable-node 142 0 29
✅ fastify-stable-quickjs 142 0 29
✅ hono-stable-node 142 0 29
✅ hono-stable-quickjs 142 0 29
✅ nest-stable-node 142 0 29
✅ nest-stable-quickjs 142 0 29
✅ nextjs-turbopack-canary-node 170 0 1
✅ nextjs-turbopack-canary-quickjs 170 0 1
✅ nextjs-turbopack-stable-node 170 0 1
✅ nextjs-turbopack-stable-quickjs 170 0 1
✅ nextjs-webpack-canary-node 170 0 1
✅ nextjs-webpack-canary-quickjs 170 0 1
✅ nextjs-webpack-stable-node 170 0 1
✅ nextjs-webpack-stable-quickjs 170 0 1
✅ nitro-stable-node 142 0 29
✅ nitro-stable-quickjs 142 0 29
✅ nuxt-stable-node 142 0 29
✅ nuxt-stable-quickjs 142 0 29
✅ sveltekit-stable-node 161 0 10
✅ sveltekit-stable-quickjs 161 0 10
✅ tanstack-start-node 142 0 29
✅ tanstack-start-quickjs 142 0 29
✅ vite-stable-node 142 0 29
✅ vite-stable-quickjs 142 0 29

✅ 📦 Local Production

App Passed Failed Skipped
✅ astro-stable-node 142 0 29
✅ astro-stable-quickjs 142 0 29
✅ express-stable-node 142 0 29
✅ express-stable-quickjs 142 0 29
✅ fastify-stable-node 142 0 29
✅ fastify-stable-quickjs 142 0 29
✅ hono-stable-node 142 0 29
✅ hono-stable-quickjs 142 0 29
✅ nest-stable-node 142 0 29
✅ nest-stable-quickjs 142 0 29
✅ nextjs-turbopack-canary-node 170 0 1
✅ nextjs-turbopack-canary-quickjs 170 0 1
✅ nextjs-turbopack-stable-node 170 0 1
✅ nextjs-turbopack-stable-quickjs 170 0 1
✅ nextjs-webpack-canary-node 170 0 1
✅ nextjs-webpack-canary-quickjs 170 0 1
✅ nextjs-webpack-stable-node 170 0 1
✅ nextjs-webpack-stable-quickjs 170 0 1
✅ nitro-stable-node 142 0 29
✅ nitro-stable-quickjs 142 0 29
✅ nuxt-stable-node 142 0 29
✅ nuxt-stable-quickjs 142 0 29
✅ sveltekit-stable-node 161 0 10
✅ sveltekit-stable-quickjs 161 0 10
✅ tanstack-start-node 142 0 29
✅ tanstack-start-quickjs 142 0 29
✅ vite-stable-node 142 0 29
✅ vite-stable-quickjs 142 0 29

✅ 🐘 Local Postgres

App Passed Failed Skipped
✅ astro-stable-node 142 0 29
✅ astro-stable-quickjs 142 0 29
✅ express-stable-node 142 0 29
✅ express-stable-quickjs 142 0 29
✅ fastify-stable-node 142 0 29
✅ fastify-stable-quickjs 142 0 29
✅ hono-stable-node 142 0 29
✅ hono-stable-quickjs 142 0 29
✅ nest-stable-node 142 0 29
✅ nest-stable-quickjs 142 0 29
✅ nextjs-turbopack-canary-node 170 0 1
✅ nextjs-turbopack-canary-quickjs 170 0 1
✅ nextjs-turbopack-stable-node 170 0 1
✅ nextjs-turbopack-stable-quickjs 170 0 1
✅ nextjs-webpack-canary-node 170 0 1
✅ nextjs-webpack-canary-quickjs 170 0 1
✅ nextjs-webpack-stable-node 170 0 1
✅ nextjs-webpack-stable-quickjs 170 0 1
✅ nitro-stable-node 142 0 29
✅ nitro-stable-quickjs 142 0 29
✅ nuxt-stable-node 142 0 29
✅ nuxt-stable-quickjs 142 0 29
✅ sveltekit-stable-node 161 0 10
✅ sveltekit-stable-quickjs 161 0 10
✅ tanstack-start-node 142 0 29
✅ tanstack-start-quickjs 142 0 29
✅ vite-stable-node 142 0 29
✅ vite-stable-quickjs 142 0 29

✅ 🪟 Windows

App Passed Failed Skipped
✅ nextjs-turbopack-node 170 0 1
✅ nextjs-turbopack-quickjs 170 0 1

✅ vercel-http-transport

App Passed Failed Skipped
✅ example 141 0 30
✅ express 141 0 30
✅ hono 141 0 30
✅ nextjs-turbopack 168 0 3
✅ nitro 141 0 30
✅ vite 141 0 30

✅ vercel-multi-region

App Passed Failed Skipped
✅ nextjs-turbopack 27 0 0

✅ vercel-ws-transport

App Passed Failed Skipped
✅ example 141 0 30
✅ express 141 0 30
✅ nextjs-turbopack 168 0 3
✅ vite 141 0 30

📋 View full workflow run

@github-actions

github-actions Bot commented Jul 29, 2026 •

Copy link
Copy Markdown
Contributor

📊 Workflow Benchmarks

commit 2b5fd8b · Fri, 25 Sep 2026 15:18:26 GMT · run logs

Backend: vercel · app: nextjs-turbopack

Metric Scenario Best (ms) P75 (ms) P90 (ms) P99 (ms) Samples
TTFS step 215 (-84%) 💚 2171 🔴 (+48%) 🔻 2226 🔴 (+46%) 🔻 2738 🔴 (+76%) 🔻 30
TTFS stream 181 (+13%) 2268 🔴 (+59%) 🔻 2328 🔴 (+55%) 🔻 2730 🔴 (+72%) 🔻 30
TTFS hook + stream 580 (-18%) 💚 2765 🔴 (+44%) 🔻 2852 🔴 (+47%) 🔻 7396 🔴 (+252%) 🔻 30
Fan-out TTFS Promise.all(100 steps) 559 (+15%) 🔻 2720 (+283%) 🔻 2752 (+201%) 🔻 3329 (+70%) 🔻 10
Fan-out TTLS Promise.all(100 steps) 2274 (+17%) 🔻 6161 (+151%) 🔻 8097 (+213%) 🔻 10102 (+15%) 10
STSO 1020 steps (inline) 121 (-19%) 💚 164 (-14%) 186 (-13%) 285 (-6.6%) 1019
WO 1020 steps 163752 (-14%) 163752 (-14%) 163752 (-14%) 163752 (-14%) 1
CRTT first chunk (pooled) 84 (-3.4%) 121 (-11%) 175 (-1.1%) 207 (+1.5%) 28

Streams

Scenario CRTT 1st p75 p90 p99 CDV max iters
paced control (100/s, 60B) 110 (+4%) 171 (-35%) 240 (-27%) 497 (+15%) 177 (-18%) 10
size sweep (100/s, 160B-12KB) 97.5 (-23%) 160 (-65%) 223 (-68%) 610 (-58%) 132 (-48%) 10
replay gateway-gpt-5.4-nano-2000t (1x) 169 (+46%) 149 (-43%) 239 (-39%) 652 (+2%) 421 (-1%) 3
replay eve-gpt-5.6-sol-2000t (1x) 158 (+15%) 162 (-41%) 205 (-68%) 442 (-85%) 249 (-85%) 2
replay eve-gpt-5.6-sol-2000t (2x) 96 (-36%) 182 (-70%) 238 (-75%) 383 (-85%) 228 (-69%) 3
📈 STSO distribution vs main (inline / queue-hop histograms)

1020 steps (inline)

Cumulative STSO time: main 190196ms → this run 163404ms (Δ -26792ms, -14%)

100-150 ms  █░░░░░░░░░░┃              main   1  this 418  +417
150-200 ms  ██████████████┃█████████  main 828  this 531  -297
200-250 ms  ┃████                     main 160  this  46  -114
250-300 ms  ┃                         main  18  this  15    -3
300-350 ms  ┃                         main   5  this   7    +2
350-400 ms  ┃                         main   3  this   0    -3
400-450 ms  ┃                         main   1  this   2    +1
450-500 ms  ┃                         main   1  this   0    -1
550-600 ms  ┃                         main   1  this   0    -1
600-650 ms  ┃                         main   1  this   0    -1
📈 CRTT drill-down vs main (RTT distributions & profiles)
variant  RTT 1ms→5s+             avg         p50         p90         p99     n
control  ······▂█▂▁···  142.8 (-32%)  131 (-31%)  240 (-27%)  497 (+15%)  3000
sweep    ······▂█▁▁···  143.8 (-50%)  127 (-47%)  223 (-68%)  610 (-58%)  3000
gw 1x    ······▃█▂▁···  138.4 (-36%)  121 (-37%)  239 (-39%)   652 (+2%)  5295
eve 1x   ······▃█▁▁···  138.1 (-52%)  123 (-37%)  205 (-68%)  442 (-85%)  5186
eve 2x   ······▂█▂····  154.4 (-62%)  144 (-55%)  238 (-75%)  383 (-85%)  7779

RTT over stream progress (avg per tenth of stream, bars scaled min→max):

control  ▃▃▁▂█▂▂▂▃▂  132–176ms
sweep    ▅▄▂▁▂▁█▃▁▂  133–171ms
gw 1x    ▃▃▁▂▅▃▄▂▇█  113–176ms
eve 1x   ▁▂█▃▅▂▄▃▅▂  129–155ms
eve 2x   ▁▁▁▂▃▂▄▇█▃  134–197ms

RTT by chunk size (avg per log size bin, ~160B → ~12KB serialized, bars scaled min→max):

sweep  █▅▆▃▁▄█  142–145ms

Delivery jitter over stream progress (avg positive CDV per tenth of stream, bars scaled min→max):

control  ▁▂▅█▅▂▁▄▅▄  39–51ms
sweep    ▂▄▁▃▂█▅▃▂▆  51–72ms
gw 1x    ▃▅▃▁▆▅▆▂█▆  32–51ms
eve 1x   ▅▇▂▄▆█▅▁▃▃  24–32ms
eve 2x   ▆▇▁▄▇▁▃▁▅█  21–29ms
ℹ️ Metric definitions & methodology

Streams: first-chunk RTT (the stream-open path, before any buffering/backpressure), CRTT percentiles, and worst delivery stall (CDV max). Cells are medians across iterations; per-run values in the artifacts. No 🔴/🟢 marks until targets attach.

The collapsed STSO distribution section above buckets every step gap, split inline (same warm process — pure framework overhead) vs queue-hop (fresh process — dispatch, reinit, replay). █ = main, ┃ = this run, ░ = fill.

The collapsed CRTT drill-down: per-variant RTT histograms (fixed log bins, · = empty) and mean RTT/positive-CDV profile lines over stream progress and chunk size. Histograms, avgs, and profiles merge exactly across runs; p50–p99 are percentile-of-percentiles. Per-index rows live in the artifacts.

Best/P75/P90/P99 deltas compare against the most recent benchmark run on main at the time of this run. 🔻 flags a delta worse than +15%, 💚 one better than −15%.

Metrics — TTFS: time to first step body (in-deployment start() → first step body) · Fan-out TTFS: fan-out time to first step (in-deployment start() → first of the parallel step bodies to complete) · Fan-out TTLS: fan-out time to last step (in-deployment start() → last of the parallel step bodies to complete, i.e. when the Promise.all resolves) · STSO: step-to-step overhead (gap between consecutive step bodies) · WO: workflow overhead (whole-run time outside step bodies, in-deployment anchored) · CRTT: chunk round-trip time (per-chunk write → read latency, one clock domain: deployment → stream backend → same deployment) · CDV: chunk delay variation / delivery jitter (inter-arrival gap minus inter-write gap per seq-adjacent pair; skew-free; the row is each run's MAX positive value, so one stall moves it)

Scenarios — step: one trivial no-op step, no stream; no hooks, so the run stays in turbo mode (in-process fast path) · stream: one streaming step; no hooks, so the run stays in turbo mode (in-process fast path) · hook + stream: registers a hook before one step, which exits turbo mode (dispatch path) · 1020 steps: 1020 trivial sequential steps; STSO is measured between consecutive steps in the given step ranges, and WO is the whole-run overhead outside step bodies · Promise.all(100 steps): 100 trivial no-op steps started together in a single Promise.all; Fan-out TTFS is the first of them to complete and Fan-out TTLS the last, both from the in-deployment clientStart, so their gap is the spread the runtime adds across the fan-out · paced control (100/s, 60B): the control: 300 tiny (~60B) deltas metronome-paced at 100/s — zero workload structure, so it reads the transport floor and flush cadence, and disambiguates transport-wide vs workload-specific when a replay row moves · size sweep (100/s, 160B-12KB): same pacing as the control with deltas padded in rotation across seven log-spaced sizes (~160B–12KB) — rotation decouples size from stream position, so it isolates whether chunk size causes latency · replay gateway-gpt-5.4-nano-2000t (1x): raw provider SSE cadence captured at the AI gateway boundary (gpt-5.4-nano, the most popular gateway model; per-token deltas p50 208B = the modal production chunk size), replayed exactly as measured — the typical customer's workload; its CDV is the typical customer's real delivery jitter · replay eve-gpt-5.6-sol-2000t (1x): a captured eve turn (gpt-5.6-sol, the most-used demanding eve model; ~2000 output tokens = production p50 turn length) replayed exactly as measured — eve's envelope protocol re-ships the cumulative message so sizes ramp 142B→13KB; the demanding outlier tenant's reality · replay eve-gpt-5.6-sol-2000t (2x): the same eve capture at 2x — the headroom/stress row; real fast-tier models emit the same chunk sizes at proportionally higher rate, so time compression is a faithful speed model · first chunk (pooled): every run's seq-0 RTT pooled across all stream scenarios — the first chunk precedes any workload differentiation, so pooling samples one shared stream-open path with exact percentiles

Replay cadences (semantic sha256) — eve-gpt-5.6-sol-2000t eaf22f5946e7c61f3c65c7006d550df180cfabd4e706254a09f22aec0cfb420d · gateway-gpt-5.4-nano-2000t 6f24ac518b6b83ff1d0e85a5fe78230db192716d66a7fc6b2fe022752001d041

🔴 marks a percentile over its target (within target is left unmarked). Targets (p75/p90/p99, ms) — TTFS 200/300/600

All timestamps are deployment-side; runs are triggered in-deployment, so the CI runner and api.vercel.com sit outside every measured window. TTFS = 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.

@socket-security

socket-security Bot commented Jul 29, 2026 •

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Updatednpm/​srvx@​0.11.15 ⏵ 0.12.8100 +110096 +196 +2100

View full report

@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 Suggestion:

Floating "monaco-editor": "latest" re-resolved to 0.56.0, whose changed exports map breaks monaco-vim@0.4.4's deep imports, failing the workflow-sdk-compiler-playground build.

Fix on Vercel

@RihanArfan
RihanArfan force-pushed the rihan/replace-express-srvx branch from 956769e to 8441d26 Compare July 29, 2026 23:36
@vercel
vercel Bot temporarily deployed to Preview – workflow-docs July 29, 2026 23:36 Inactive
@github-actions

github-actions Bot commented Sep 10, 2026 •

Copy link
Copy Markdown
Contributor

Sim World

Simulated world deterministic testing for races. Traces

🟠 world-sim scenario book — 1 fail of 42 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
✅ step-vs-timer-early-settlement completed 8 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

@github-actions

github-actions Bot commented Sep 10, 2026 •

Copy link
Copy Markdown
Contributor
Framework Flow route Step reg. Framework output
hono 252.0 KiB (±0) 94.9 KiB (±0) 1.91 MiB (±0)
nextjs-turbopack 259.3 KiB (±0) 426 B (±0) 908.2 KiB (±0)
About these numbers

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

2b5fd8b · run

cursoragent and others added 2 commits September 24, 2026 19:33
Resolve the lockfile conflict from the express→srvx migration by regenerating against the merged package manifests.
@github-actions

Copy link
Copy Markdown
Contributor

No backport to stable for ad0fcc7 (AI decision).

This is a refactor that swaps Express for srvx in @workflow/web's standalone server and static handling, not a fix for any defect on stable. It carries a major changeset and adds new behavior (ETag/304, Last-Modified, byte ranges, on-the-fly compression) plus a new internal static.js module and a changed public return type for startServer, all of which is feature/dependency churn that a maintenance line should not take on.

To override, re-run the Backport to stable workflow manually via workflow_dispatch and paste this commit SHA into the ref input:

ad0fcc7e52cf27247daed86edad9f6635a23fc08

This branch was successfully deployed

18 active deployments
Preview – workflow-swc-playground — 2b5fd8bb Deployed Sep 25, 2026 by vercel[bot]
Preview – workflow-docs — 2b5fd8bb Deployed Sep 25, 2026 by vercel[bot]
Preview – example-nextjs-workflow-webpack — 2b5fd8bb Deployed Sep 25, 2026 by vercel[bot]
Preview – workbench-sveltekit-workflow — 2b5fd8bb Deployed Sep 25, 2026 by vercel[bot]
Preview – workbench-nuxt-workflow — 2b5fd8bb Deployed Sep 25, 2026 by vercel[bot]
Preview – example-workflow — 2b5fd8bb Deployed Sep 25, 2026 by vercel[bot]
Preview – workbench-fastify-workflow — 2b5fd8bb Deployed Sep 25, 2026 by vercel[bot]
Preview – workbench-nestjs-workflow — 2b5fd8bb Deployed Sep 25, 2026 by vercel[bot]
Preview – example-nextjs-workflow-turbopack — 2b5fd8bb Deployed Sep 25, 2026 by vercel[bot]
Preview – workbench-nitro-workflow — 2b5fd8bb Deployed Sep 25, 2026 by vercel[bot]
Preview – workbench-tanstack-start-workflow — 2b5fd8bb Deployed Sep 25, 2026 by vercel[bot]
Preview – workbench-vite-workflow — 2b5fd8bb Deployed Sep 25, 2026 by vercel[bot]
Preview – workflow-tarballs — 2b5fd8bb Deployed Sep 25, 2026 by vercel[bot]
Preview – workbench-astro-workflow — 2b5fd8bb Deployed Sep 25, 2026 by vercel[bot]
Preview – workbench-express-workflow — 2b5fd8bb Deployed Sep 25, 2026 by vercel[bot]
Preview – workbench-hono-workflow — 2b5fd8bb Deployed Sep 25, 2026 by vercel[bot]
Preview – workflow-web — 2b5fd8bb Deployed Sep 25, 2026 by vercel[bot]
Preview – workbench-python-workflow — 2b5fd8bb Deployed Sep 25, 2026 by vercel[bot]
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.

3 participants