Skip to content

Fix stable CI test harness failures#1986

Draft
pranaygp wants to merge 17 commits into
stablefrom
pranaygp/codex/fix-stable-ci
Draft

Fix stable CI test harness failures#1986
pranaygp wants to merge 17 commits into
stablefrom
pranaygp/codex/fix-stable-ci

Conversation

@pranaygp
Copy link
Copy Markdown
Contributor

@pranaygp pranaygp commented May 14, 2026

Summary

Fixes CI stability issues observed on the current stable branch:

  • Avoids deleting newly-added workflow files while the dev server can still rebuild against imports that reference them. The dev-test cleanup now keeps placeholders in place for dev-server rebuilds and avoids the missing-file race.
  • Speeds up local workflow port detection by probing with a real libuv-backed server listen attempt instead of waiting on slow HTTP probes.
  • Makes generated workflow health endpoints respond to HEAD, so health checks no longer need to probe with POST.
  • Wraps generated framework route exports so SvelteKit/Astro route functions keep the workflow route wrapper instead of leaking workflow queue triggers onto framework-owned functions.
  • Materializes manual webhook response bodies before returning from the webhook handler. In the Nitro Vercel prod failure, the workflow run completed in ~5s and all hooks were received, but the test still timed out at 120s; this keeps the HTTP response from depending on a secondary cross-context body stream after the handler returns.
  • Waits for step return-value stream serialization before recording step_completed. The Nuxt failure had readableStreamWorkflow complete before stream chunks were persisted, so the client observed an empty stream.
  • Gives remote Vercel e2e CLI inspections a Vercel-specific timeout budget. The Vite failure had both addTenWorkflow runs complete in ~5s, then workflow inspect --withData was killed by the harness' old 20s subprocess timeout while fetching/decrypting remote run data.
  • Makes sleep e2e assertions use persisted event timing instead of Date.now() values returned from replayed workflow code. The Express failure showed run_started to wait_completed was >10s, but the replayed return value measured only the latter portion of the event stream.
  • Makes the hook-dispose e2e wait for the hook token to actually be released/re-owned instead of relying on fixed sleeps. The Nitro failure started workflow 2 before workflow 1 had persisted hook_disposed, so the runtime correctly produced hook_conflict.
  • Keeps the remote addTenWorkflow test timeout aligned with observed Vercel prod queue/cold-start latency where the workflow completed after the old 60s test timeout.

Includes a changeset for the touched packages.

CI notes

  • Run 25894395244 failed only E2E Vercel Prod Tests (nitro) plus the aggregate required check. The failed webhookWorkflow run wrun_01KRMJH5E2V02Y9KC4NJ0EHB0P was completed; event timeline reached run_completed at +5.3s, so the remaining failure was in the webhook HTTP response path, not workflow execution.
  • Run 25895081248 fixed Nitro and all local e2e jobs passed. The only app-specific failure was E2E Vercel Prod Tests (vite), where both failed addTenWorkflow runs were already completed (wrun_01KRMKS6SH17MSH902CATGVGYH and wrun_01KRMKTGK9AYX2S228DAWD4GHV reached run_completed in ~5s). The failure was the e2e harness killing workflow inspect --withData with SIGTERM after 20s.
  • Run 25898693068 fixed Vite. Remaining failures were E2E Vercel Prod Tests (express) and E2E Vercel Prod Tests (nitro): Express failed sleepingWorkflow because replayed Date.now() returned a 5509ms delta while the event timeline showed run_started at +0.5s and wait_completed at +11.3s; Nitro failed hookDisposeTestWorkflow because workflow 2 started before workflow 1 had disposed the shared token, producing a correct hook_conflict.
  • Run 25902464337 fixed Vite, Express, and Nitro. Remaining failure was E2E Vercel Prod Tests (nuxt): readableStreamWorkflow returned an empty stream even though the step/run completed; the step event timeline completed in ~1s while the stream-producing step should take ~10s, showing step_completed was racing ahead of return stream serialization.
  • Current run on e3a7f8e71 is in progress: https://github.com/vercel/workflow/actions/runs/25905802133

Validation

  • fnm exec --using v22.18.0 pnpm --filter @workflow/core build
  • fnm exec --using v22.18.0 pnpm vitest run packages/core/src/runtime/step-handler.test.ts packages/core/src/writable-stream.test.ts packages/core/src/step/writable-stream.test.ts
  • fnm exec --using v22.18.0 pnpm turbo run build --filter='@workflow/nitro' --filter='@workflow/builders' --filter='@workflow/core'
  • fnm exec --using v22.18.0 env NITRO_PRESET=vercel WORKFLOW_PUBLIC_MANIFEST=1 pnpm --dir workbench/nitro-v3 build
  • fnm exec --using v22.18.0 pnpm exec biome check packages/core/src/runtime/step-handler.ts packages/core/e2e/e2e.test.ts packages/core/e2e/utils.ts (only pre-existing warnings)
  • fnm exec --using v22.18.0 pnpm exec biome check packages/core/src/runtime/resume-hook.ts packages/core/e2e/e2e.test.ts packages/builders/src/base-builder.ts packages/nitro/src/index.ts (only pre-existing warnings)
  • Earlier validation on this PR also covered @workflow/utils tests, builder package builds, SvelteKit/Astro production builds, and Fastify dev rebuild smoke coverage.

@pranaygp pranaygp requested a review from a team as a code owner May 14, 2026 18:21
Copilot AI review requested due to automatic review settings May 14, 2026 18:21
@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented May 14, 2026

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

Project Deployment Actions Updated (UTC)
example-nextjs-workflow-turbopack Building Building Preview, Comment May 15, 2026 7:26am
example-nextjs-workflow-webpack Ready Ready Preview, Comment May 15, 2026 7:26am
example-workflow Ready Ready Preview, Comment May 15, 2026 7:26am
workbench-astro-workflow Ready Ready Preview, Comment May 15, 2026 7:26am
workbench-express-workflow Ready Ready Preview, Comment May 15, 2026 7:26am
workbench-fastify-workflow Ready Ready Preview, Comment May 15, 2026 7:26am
workbench-hono-workflow Ready Ready Preview, Comment May 15, 2026 7:26am
workbench-nitro-workflow Ready Ready Preview, Comment May 15, 2026 7:26am
workbench-nuxt-workflow Ready Ready Preview, Comment May 15, 2026 7:26am
workbench-sveltekit-workflow Ready Ready Preview, Comment May 15, 2026 7:26am
workbench-tanstack-start-workflow Ready Ready Preview, Comment May 15, 2026 7:26am
workbench-vite-workflow Ready Ready Preview, Comment May 15, 2026 7:26am
workflow-docs Ready Ready Preview, Comment, Open in v0 May 15, 2026 7:26am
workflow-swc-playground Ready Ready Preview, Comment May 15, 2026 7:26am
workflow-tarballs Ready Ready Preview, Comment May 15, 2026 7:26am
workflow-web Ready Ready Preview, Comment May 15, 2026 7:26am

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 14, 2026

🦋 Changeset detected

Latest commit: e3a7f8e

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

This PR includes changesets to release 23 packages
Name Type
@workflow/astro Patch
@workflow/builders Patch
@workflow/core Patch
@workflow/nest Patch
@workflow/next Patch
@workflow/sveltekit Patch
@workflow/utils Patch
workflow Patch
tarballs Patch
@workflow/cli Patch
@workflow/nitro Patch
@workflow/rollup Patch
@workflow/vite Patch
@workflow/vitest Patch
@workflow/web-shared Patch
@workflow/web Patch
@workflow/world-testing Patch
@workflow/errors Patch
@workflow/world-local Patch
@workflow/world-postgres Patch
@workflow/ai Patch
@workflow/nuxt Patch
@workflow/world-vercel 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

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 14, 2026

🧪 E2E Test Results

Some tests failed

Summary

Passed Failed Skipped Total
❌ ▲ Vercel Production 900 1 67 968
❌ 💻 Local Development 969 1 86 1056
❌ 📦 Local Production 969 1 86 1056
✅ 🐘 Local Postgres 970 0 86 1056
✅ 🪟 Windows 88 0 0 88
❌ 🌍 Community Worlds 137 85 0 222
✅ 📋 Other 492 0 36 528
Total 4525 88 361 4974

❌ Failed Tests

▲ Vercel Production (1 failed)

sveltekit (1 failed):

  • DurableAgent e2e core single tool call
💻 Local Development (1 failed)

hono-stable (1 failed):

  • hookWorkflow | wrun_01KRN8BQXHEHK3JZB00S99STGM
📦 Local Production (1 failed)

nitro-stable (1 failed):

  • hookWorkflow | wrun_01KRN8BQXHEHK3JZB00S99STGM
🌍 Community Worlds (85 failed)

mongodb (11 failed):

  • hookWorkflow is not resumable via public webhook endpoint | wrun_01KRN8C23Z19KB13S2KSDJ3Q06
  • sleepingWorkflow | wrun_01KRN8CG3ED03YT6NGX8K7PYVC
  • outputStreamWorkflow no startIndex (reads all chunks)
  • outputStreamWorkflow negative startIndex (reads from end)
  • outputStreamWorkflow - getTailIndex and getStreamChunks getTailIndex returns correct index after stream completes
  • outputStreamWorkflow - getTailIndex and getStreamChunks getTailIndex returns -1 before any chunks are written
  • outputStreamWorkflow - getTailIndex and getStreamChunks getStreamChunks returns same content as reading the stream
  • outputStreamInsideStepWorkflow - getWritable() called inside step functions | wrun_01KRN8FC5C6ECVW465RS32EVAX
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_01KRN8KWNEKHD79B2FZ2BA4T3E
  • pages router sleepingWorkflow via pages router
  • resilient start: addTenWorkflow completes when run_created returns 500 | wrun_01KRN8SJ4M4MP8FNSX29Y5B44H

redis (9 failed):

  • hookWorkflow is not resumable via public webhook endpoint | wrun_01KRN8C23Z19KB13S2KSDJ3Q06
  • sleepingWorkflow | wrun_01KRN8CG3ED03YT6NGX8K7PYVC
  • outputStreamWorkflow negative startIndex (reads from end)
  • outputStreamWorkflow - getTailIndex and getStreamChunks getTailIndex returns correct index after stream completes
  • outputStreamWorkflow - getTailIndex and getStreamChunks getTailIndex returns -1 before any chunks are written
  • outputStreamWorkflow - getTailIndex and getStreamChunks getStreamChunks returns same content as reading the stream
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_01KRN8KWNEKHD79B2FZ2BA4T3E
  • pages router sleepingWorkflow via pages router
  • resilient start: addTenWorkflow completes when run_created returns 500 | wrun_01KRN8SJ4M4MP8FNSX29Y5B44H

turso (65 failed):

  • addTenWorkflow | wrun_01KRN8ASBYMTRNMJP0A0FQF49W
  • addTenWorkflow | wrun_01KRN8ASBYMTRNMJP0A0FQF49W
  • wellKnownAgentWorkflow (.well-known/agent) | wrun_01KRN8C223VTNJJ7D4T1KTJBS4
  • should work with react rendering in step
  • promiseAllWorkflow | wrun_01KRN8B0G6FBAM8JRK37B2AE73
  • promiseRaceWorkflow | wrun_01KRN8B6WZCT5ADQ7F1J4CYGBG
  • promiseAnyWorkflow | wrun_01KRN8B8TP95QKAY0SXGSJV72Q
  • importedStepOnlyWorkflow | wrun_01KRN8CEFBEGGX7K4SAMJ3DA56
  • readableStreamWorkflow | wrun_01KRN8BBTR606M8S1EV2S8K86Y
  • hookWorkflow | wrun_01KRN8BQXHEHK3JZB00S99STGM
  • hookWorkflow is not resumable via public webhook endpoint | wrun_01KRN8C23Z19KB13S2KSDJ3Q06
  • webhookWorkflow | wrun_01KRN8CACY62FFH87V6JKKRSE0
  • sleepingWorkflow | wrun_01KRN8CG3ED03YT6NGX8K7PYVC
  • parallelSleepWorkflow | wrun_01KRN8CZ2G8N4XPXYE9VTEDPYT
  • nullByteWorkflow | wrun_01KRN8D344TEAACHW5D4WKCSPB
  • workflowAndStepMetadataWorkflow | wrun_01KRN8D57KXKYXET1JW5P97MQ9
  • outputStreamWorkflow no startIndex (reads all chunks)
  • outputStreamWorkflow positive startIndex (skips first chunk)
  • outputStreamWorkflow negative startIndex (reads from end)
  • outputStreamWorkflow - getTailIndex and getStreamChunks getTailIndex returns correct index after stream completes
  • outputStreamWorkflow - getTailIndex and getStreamChunks getTailIndex returns -1 before any chunks are written
  • outputStreamWorkflow - getTailIndex and getStreamChunks getStreamChunks returns same content as reading the stream
  • outputStreamInsideStepWorkflow - getWritable() called inside step functions | wrun_01KRN8FC5C6ECVW465RS32EVAX
  • fetchWorkflow | wrun_01KRN8FSD3XCRJHVC44VK2QEY4
  • promiseRaceStressTestWorkflow | wrun_01KRN8FWASERDE7GFFE4STK34Z
  • error handling error propagation workflow errors nested function calls preserve message and stack trace
  • error handling error propagation workflow errors cross-file imports preserve message and stack trace
  • error handling error propagation step errors basic step error preserves message and stack trace
  • error handling error propagation step errors cross-file step error preserves message and function names in stack
  • 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 not registered WorkflowNotRegisteredError fails the run when workflow does not exist
  • 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_01KRN8K9NFN6WBCPWC95NVW52V
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_01KRN8KWNEKHD79B2FZ2BA4T3E
  • hookDisposeTestWorkflow - hook token reuse after explicit disposal while workflow still running | wrun_01KRN8MA477S40DX5C0QRY44C1
  • stepFunctionPassingWorkflow - step function references can be passed as arguments (without closure vars) | wrun_01KRN8MS8WPBMVAHBP3C8YJPEA
  • stepFunctionWithClosureWorkflow - step function with closure variables passed as argument | wrun_01KRN8N0Z43CENAV7SYFEEANYQ
  • closureVariableWorkflow - nested step functions with closure variables | wrun_01KRN8N6X9D1PHXHMTJQZ5S251
  • spawnWorkflowFromStepWorkflow - spawning a child workflow using start() inside a step | wrun_01KRN8N8R9BMV4C730MK5AYK3J
  • health check (queue-based) - workflow and step endpoints respond to health check messages
  • pathsAliasWorkflow - TypeScript path aliases resolve correctly | wrun_01KRN8NPK3ZK0E82JWYQP7DQ2D
  • Calculator.calculate - static workflow method using static step methods from another class | wrun_01KRN8NVHQYHJQ9TJ1GTX952JX
  • AllInOneService.processNumber - static workflow method using sibling static step methods | wrun_01KRN8P1MR3M6BA0W8XC4F1RZR
  • ChainableService.processWithThis - static step methods using this to reference the class | wrun_01KRN8P7RN7FFBXS9B891ERJT7
  • thisSerializationWorkflow - step function invoked with .call() and .apply() | wrun_01KRN8PDMEDZ84NPKK1AEDCKPC
  • customSerializationWorkflow - custom class serialization with WORKFLOW_SERIALIZE/WORKFLOW_DESERIALIZE | wrun_01KRN8PMJSX5CB1T645F0KCY2Y
  • instanceMethodStepWorkflow - instance methods with "use step" directive | wrun_01KRN8PVKQM12YX5SY52Q7AJJ6
  • crossContextSerdeWorkflow - classes defined in step code are deserializable in workflow context | wrun_01KRN8Q5KPEJ06N2GAQHG4SWSM
  • stepFunctionAsStartArgWorkflow - step function reference passed as start() argument | wrun_01KRN8QERRMRWADVSNZKH5XVJE
  • cancelRun - cancelling a running workflow | wrun_01KRN8QNR616F8887GFFGJJTD7
  • cancelRun via CLI - cancelling a running workflow | wrun_01KRN8QYAES222BD0Q961936M8
  • pages router addTenWorkflow via pages router
  • pages router promiseAllWorkflow via pages router
  • pages router sleepingWorkflow via pages router
  • hookWithSleepWorkflow - hook payloads delivered correctly with concurrent sleep | wrun_01KRN8R9HVEX5XF87TTJ8WPX3Z
  • sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration | wrun_01KRN8RWF0G6GAHVQ32JJ17RVC
  • sleepWithSequentialStepsWorkflow - sequential steps work with concurrent sleep (control) | wrun_01KRN8S7AY1CA7N1JPRJF62XBW
  • importMetaUrlWorkflow - import.meta.url is available in step bundles | wrun_01KRN8SEE9N8VJ2XK65XNGMNM9
  • metadataFromHelperWorkflow - getWorkflowMetadata/getStepMetadata work from module-level helper (#1577) | wrun_01KRN8SG7CS59NXDMD04BBYAH8
  • resilient start: addTenWorkflow completes when run_created returns 500 | wrun_01KRN8SJ4M4MP8FNSX29Y5B44H

Details by Category

❌ ▲ Vercel Production
App Passed Failed Skipped
✅ astro 81 0 7
✅ example 81 0 7
✅ express 81 0 7
✅ fastify 81 0 7
✅ hono 81 0 7
✅ nextjs-turbopack 86 0 2
✅ nextjs-webpack 86 0 2
✅ nitro 81 0 7
✅ nuxt 81 0 7
❌ sveltekit 80 1 7
✅ vite 81 0 7
❌ 💻 Local Development
App Passed Failed Skipped
✅ astro-stable 82 0 6
✅ express-stable 82 0 6
✅ fastify-stable 82 0 6
❌ hono-stable 81 1 6
✅ nextjs-turbopack-canary 69 0 19
✅ nextjs-turbopack-stable 88 0 0
✅ nextjs-webpack-canary 69 0 19
✅ nextjs-webpack-stable 88 0 0
✅ nitro-stable 82 0 6
✅ nuxt-stable 82 0 6
✅ sveltekit-stable 82 0 6
✅ vite-stable 82 0 6
❌ 📦 Local Production
App Passed Failed Skipped
✅ astro-stable 82 0 6
✅ express-stable 82 0 6
✅ fastify-stable 82 0 6
✅ hono-stable 82 0 6
✅ nextjs-turbopack-canary 69 0 19
✅ nextjs-turbopack-stable 88 0 0
✅ nextjs-webpack-canary 69 0 19
✅ nextjs-webpack-stable 88 0 0
❌ nitro-stable 81 1 6
✅ nuxt-stable 82 0 6
✅ sveltekit-stable 82 0 6
✅ vite-stable 82 0 6
✅ 🐘 Local Postgres
App Passed Failed Skipped
✅ astro-stable 82 0 6
✅ express-stable 82 0 6
✅ fastify-stable 82 0 6
✅ hono-stable 82 0 6
✅ nextjs-turbopack-canary 69 0 19
✅ nextjs-turbopack-stable 88 0 0
✅ nextjs-webpack-canary 69 0 19
✅ nextjs-webpack-stable 88 0 0
✅ nitro-stable 82 0 6
✅ nuxt-stable 82 0 6
✅ sveltekit-stable 82 0 6
✅ vite-stable 82 0 6
✅ 🪟 Windows
App Passed Failed Skipped
✅ nextjs-turbopack 88 0 0
❌ 🌍 Community Worlds
App Passed Failed Skipped
✅ mongodb-dev 5 0 0
❌ mongodb 58 11 0
✅ redis-dev 5 0 0
❌ redis 60 9 0
✅ turso-dev 5 0 0
❌ turso 4 65 0
✅ 📋 Other
App Passed Failed Skipped
✅ e2e-local-dev-nest-stable 82 0 6
✅ e2e-local-dev-tanstack-start-stable 82 0 6
✅ e2e-local-postgres-nest-stable 82 0 6
✅ e2e-local-postgres-tanstack-start-stable 82 0 6
✅ e2e-local-prod-nest-stable 82 0 6
✅ e2e-local-prod-tanstack-start-stable 82 0 6

📋 View full workflow run


Some E2E test jobs failed:

  • Vercel Prod: failure
  • Local Dev: failure
  • Local Prod: failure
  • Local Postgres: success
  • Windows: success

Check the workflow run for details.

Comment thread packages/utils/src/get-port.test.ts Outdated
expect(port).toBe(fastAddr.port);
// Should complete reasonably quickly (Windows CI can be slow)
expect(elapsed).toBeLessThan(2000);
expect(elapsed).toBeLessThan(5000);
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

5s is too long - what's actually causing the get port to take so long and can we make this faster?

Copy link
Copy Markdown
Contributor Author

@pranaygp pranaygp May 14, 2026

Choose a reason for hiding this comment

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

Yep, that 5s bump was masking the wrong thing. The slow part was Windows netstat / process-port discovery, not the HTTP probe timeout itself.

I changed the test to pass explicit candidatePorts, so it bypasses OS discovery and measures the custom probe timeout directly. The assertion is back to less than 2000ms.

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