Skip to content

[e2e] Separate event-log-race-repro harness noise from real regressions - #2190

Merged
VaguelySerious merged 1 commit into
mainfrom
peter/event-log-race-repro-classify-infra
Jun 1, 2026
Merged

[e2e] Separate event-log-race-repro harness noise from real regressions#2190
VaguelySerious merged 1 commit into
mainfrom
peter/event-log-race-repro-classify-infra

Conversation

@VaguelySerious

Copy link
Copy Markdown
Member

Summary

The event-log-race-repro job is currently red for the wrong reason. In a recent run, it reported 1231 of 2000 runs "did not complete cleanly" — yet CORRUPTED_EVENT_LOG / USER_ERROR / RUNTIME_ERROR were all 0. The entire count was harness-side noise.

What the other column was

The repro sorts each run into completed, CORRUPTED_EVENT_LOG, USER_ERROR, RUNTIME_ERROR, stuck, or other. Only the three named error codes mapped to their own bucket; everything else fell into other, and the --check gate failed the job on any non-completed run. So other conflated genuine corruption with:

  • HOOK_RESUME_FAILED — the run completed fine, but the harness's own resumeHook() rejected (typically because the sleep branch already finished the run and disposed the hook).
  • NO_WAKE_BRANCH — the run completed but the sleep branch won every iteration, so the wake path was never taken.
  • transport errors / timeouts thrown in the driver, and cancellations.

What was actually going wrong

A timing race in the test harness, not an SDK bug. The workflow's sleep budget is iterations × sleepMs = 5 × 5000 = 25000ms; the harness resumes the hook at resumeDelayMs + rand(resumeJitterMs) = up to 25000ms — the resume ceiling exactly equals the budget. On a fast/warm deployment the workflow exhausts its sleeps before the resume lands, so the resume hits a disposed hook and/or the wake branch is never taken.

The smoking gun: the #2 retry against the same already-warm deployment jumped 767→1231 other while stuck dropped to 0 and the step scenarios stayed perfect. Faster execution = the resume misses the window more often. It also means most "green" runs weren't even exercising the wake-branch shape the repro is meant to stress.

Changes

  1. Reclassify harness-side, non-corruption outcomes into a dedicated non-gating infra bucket (test + renderer). The job now gates only on regression-class outcomes (CORRUPTED_EVENT_LOG / USER_ERROR / RUNTIME_ERROR / stuck / other); infra is reported but never fails the job. The PR comment now reads "No event-log regressions… N runs hit harness-side infra outcomes (… do not fail the job)."
  2. Surface regressions ahead of infra in the failures table so the 20-row cap never hides a real failure behind a flood of timing rows.
  3. Restore wake-branch coverage: raise the default iterations ceiling (5 → 8). Because the run short-circuits via returnOnWake the moment the hook wins, a higher ceiling widens the window for the resume to land before sleep-budget exhaustion at ~no runtime cost. Added a beforeAll guard that warns when the resume ceiling is not below the sleep budget.
  4. Testability: the renderer's pure helpers are now exported and covered by node:test (run via a new lightweight Lint job).

Tests

node --test .github/scripts/**/*.test.js (8 tests) covers: infra is non-gating; regressionCount ignores completed/infra; an all-infra results file (mirroring the production comment) yields 0 regressions; regressions sort ahead of infra; --check exits 0 on infra-only and 1 on a corruption-class outcome.

Note: the full 2000-run repro only runs against a deployment behind the event-log-race-repro label, so the reclassification's end-to-end effect is best confirmed by adding that label to this PR.

🤖 Generated with Claude Code

The event-log-race-repro job classified every non-completed run into an
`other` grab-bag and gated on it. Hook-resume timing races (HOOK_RESUME_FAILED,
NO_WAKE_BRANCH) and transport errors in the repro driver — none of which are
event-log corruption — landed there and failed the job, drowning the signal it
exists to detect.
- Route harness-side, non-corruption outcomes to a dedicated non-gating `infra`
bucket (test + renderer). The job now gates only on regression-class outcomes
(CORRUPTED_EVENT_LOG / USER_ERROR / RUNTIME_ERROR / stuck / other).
- Sort regressions ahead of infra rows so the 20-row cap never hides a real
failure behind a flood of harness-timing rows.
- Raise the default hook/sleep iteration ceiling (5 -> 8). Because the run
short-circuits via returnOnWake the moment the hook wins, this widens the
window for the delayed resume to land before the sleep budget is exhausted,
at ~no runtime cost — restoring the wake-branch coverage the scenario exists
to exercise. Add a beforeAll guard that warns when the resume ceiling is not
below the sleep budget.
- Make the renderer's pure helpers unit-testable and add node:test coverage,
wired into the Lint workflow.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@changeset-bot

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: e100a60

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

This PR includes changesets to release 0 packages

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

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

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

@vercel

vercelBot commented May 31, 2026

Copy link
Copy Markdown
Contributor

@github-actions

github-actionsBot commented May 31, 2026

Copy link
Copy Markdown
Contributor

🧪 E2E Test Results

Some tests failed

Summary

PassedFailedSkippedTotal
❌ ▲ Vercel Production126332191485
❌ 💻 Local Development167012191890
✅ 📦 Local Production167102191890
✅ 🐘 Local Postgres167102191890
✅ 🪟 Windows13500135
❌ 📋 Other7681176945
Total7178510528235

❌ Failed Tests

▲ Vercel Production (3 failed)

express (1 failed):

  • instanceMethodStepWorkflow - instance methods with "use step" directive | wrun_01KSZ4H8N0DE044HA3WQ2AG25H | 🔍 observability

nextjs-webpack (2 failed):

  • AbortController abortHookOrderingWorkflow [listener-first-abort-first]: addEventListener → hook.then → abort() → resumeHook
  • AbortController abortHookOrderingWorkflow [listener-first-hook-first]: addEventListener → hook.then → resumeHook → abort()
💻 Local Development (1 failed)

express-stable (1 failed):

  • hookWithSleepFinalStepWorkflow - step only on final payload | wrun_01KSZ4NB8SC1XKHH9GSXQEKXZR
📋 Other (1 failed)

e2e-vercel-prod-tanstack-start (1 failed):

  • AbortController abortHookOrderingWorkflow [listener-first-abort-first]: addEventListener → hook.then → abort() → resumeHook

Details by Category

❌ ▲ Vercel Production
AppPassedFailedSkipped
✅ astro109026
✅ example109026
❌ express108126
✅ fastify109026
✅ hono109026
✅ nextjs-turbopack13302
❌ nextjs-webpack13122
✅ nitro109026
✅ nuxt109026
✅ sveltekit12807
✅ vite109026
❌ 💻 Local Development
AppPassedFailedSkipped
✅ astro-stable110025
❌ express-stable109125
✅ fastify-stable110025
✅ hono-stable110025
✅ nextjs-turbopack-canary116019
✅ nextjs-turbopack-stable-lazy-discovery-disabled13500
✅ nextjs-turbopack-stable-lazy-discovery-enabled13500
✅ nextjs-webpack-canary116019
✅ nextjs-webpack-stable-lazy-discovery-disabled13500
✅ nextjs-webpack-stable-lazy-discovery-enabled13500
✅ nitro-stable110025
✅ nuxt-stable110025
✅ sveltekit-stable12906
✅ vite-stable110025
✅ 📦 Local Production
AppPassedFailedSkipped
✅ astro-stable110025
✅ express-stable110025
✅ fastify-stable110025
✅ hono-stable110025
✅ nextjs-turbopack-canary116019
✅ nextjs-turbopack-stable-lazy-discovery-disabled13500
✅ nextjs-turbopack-stable-lazy-discovery-enabled13500
✅ nextjs-webpack-canary116019
✅ nextjs-webpack-stable-lazy-discovery-disabled13500
✅ nextjs-webpack-stable-lazy-discovery-enabled13500
✅ nitro-stable110025
✅ nuxt-stable110025
✅ sveltekit-stable12906
✅ vite-stable110025
✅ 🐘 Local Postgres
AppPassedFailedSkipped
✅ astro-stable110025
✅ express-stable110025
✅ fastify-stable110025
✅ hono-stable110025
✅ nextjs-turbopack-canary116019
✅ nextjs-turbopack-stable-lazy-discovery-disabled13500
✅ nextjs-turbopack-stable-lazy-discovery-enabled13500
✅ nextjs-webpack-canary116019
✅ nextjs-webpack-stable-lazy-discovery-disabled13500
✅ nextjs-webpack-stable-lazy-discovery-enabled13500
✅ nitro-stable110025
✅ nuxt-stable110025
✅ sveltekit-stable12906
✅ vite-stable110025
✅ 🪟 Windows
AppPassedFailedSkipped
✅ nextjs-turbopack13500
❌ 📋 Other
AppPassedFailedSkipped
✅ e2e-local-dev-nest-stable110025
✅ e2e-local-dev-tanstack-start-110025
✅ e2e-local-postgres-nest-stable110025
✅ e2e-local-postgres-tanstack-start-110025
✅ e2e-local-prod-nest-stable110025
✅ e2e-local-prod-tanstack-start-110025
❌ e2e-vercel-prod-tanstack-start108126

📋 View full workflow run


Some E2E test jobs failed:

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

Check the workflow run for details.

@github-actions

github-actionsBot commented May 31, 2026

Copy link
Copy Markdown
Contributor

📊 Benchmark Results

📈 Comparing against baseline from main branch. Green 🟢 = faster, Red 🔺 = slower.

workflow with no steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Express0.042s (-5.9% 🟢)1.006s (~)0.964s101.00x
💻 LocalNitro0.045s (+5.3% 🔺)1.006s (~)0.961s101.09x
💻 LocalNext.js (Turbopack)0.059s1.007s0.947s101.42x
🐘 PostgresExpress0.060s (+2.8%)1.012s (~)0.952s101.43x
🐘 PostgresNitro0.062s (-35.2% 🟢)1.012s (-2.9%)0.951s101.48x
🐘 PostgresNext.js (Turbopack)0.071s1.013s0.941s101.71x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express0.304s (+29.2% 🔺)9.230s (+332.2% 🔺)8.926s101.00x
▲ VercelNitro0.467s (+14.0% 🔺)8.212s (+227.3% 🔺)7.745s101.54x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

workflow with 1 step

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Nitro1.090s (-3.6%)2.007s (~)0.917s101.00x
💻 LocalExpress1.094s (-2.8%)2.006s (~)0.912s101.00x
🐘 PostgresNitro1.100s (-3.5%)2.008s (~)0.909s101.01x
🐘 PostgresExpress1.108s (-3.4%)2.011s (~)0.903s101.02x
💻 LocalNext.js (Turbopack)1.137s2.006s0.869s101.04x
🐘 PostgresNext.js (Turbopack)1.154s2.011s0.856s101.06x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro1.951s (-49.9% 🟢)8.918s (+50.9% 🔺)6.967s101.00x
▲ VercelExpress2.816s (+50.2% 🔺)11.043s (+190.0% 🔺)8.227s101.44x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

workflow with 10 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Express10.509s (-3.8%)11.022s (~)0.513s31.00x
🐘 PostgresExpress10.527s (-4.0%)11.018s (~)0.490s31.00x
🐘 PostgresNitro10.543s (-3.0%)11.018s (~)0.475s31.00x
💻 LocalNitro10.549s (-3.6%)11.023s (~)0.475s31.00x
💻 LocalNext.js (Turbopack)10.771s11.022s0.251s31.02x
🐘 PostgresNext.js (Turbopack)10.864s11.019s0.155s31.03x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro13.250s (-44.2% 🟢)17.759s (-29.3% 🟢)4.509s31.00x
▲ VercelExpress18.536s (+9.2% 🔺)25.082s (+25.3% 🔺)6.546s21.40x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

workflow with 25 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro13.713s (-6.0% 🟢)14.018s (-6.7% 🟢)0.304s51.00x
💻 LocalExpress13.737s (-8.2% 🟢)14.027s (-6.7% 🟢)0.290s51.00x
🐘 PostgresExpress13.748s (-5.7% 🟢)14.016s (-6.7% 🟢)0.268s51.00x
💻 LocalNitro13.768s (-8.6% 🟢)14.027s (-12.5% 🟢)0.260s51.00x
💻 LocalNext.js (Turbopack)14.375s15.031s0.656s41.05x
🐘 PostgresNext.js (Turbopack)14.516s15.019s0.503s41.06x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro22.401s (-65.2% 🟢)41.317s (-38.0% 🟢)18.916s21.00x
▲ VercelExpress22.701s (-54.9% 🟢)31.002s (-41.0% 🟢)8.301s21.01x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

workflow with 50 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro12.332s (-11.7% 🟢)13.018s (-9.0% 🟢)0.687s71.00x
🐘 PostgresExpress12.367s (-11.7% 🟢)13.017s (-10.8% 🟢)0.649s71.00x
💻 LocalExpress12.445s (-25.0% 🟢)13.025s (-23.5% 🟢)0.580s71.01x
💻 LocalNitro12.686s (-24.4% 🟢)13.168s (-22.7% 🟢)0.482s71.03x
💻 LocalNext.js (Turbopack)13.628s14.028s0.400s71.11x
🐘 PostgresNext.js (Turbopack)13.797s14.164s0.367s71.12x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express27.762s (-77.1% 🟢)31.197s (-74.8% 🟢)3.435s31.00x
▲ VercelNitro28.303s (-93.3% 🟢)36.682s (-91.4% 🟢)8.379s31.02x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

Promise.all with 10 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express1.186s (-5.9% 🟢)2.008s (~)0.822s151.00x
💻 LocalExpress1.198s (-19.6% 🟢)2.006s (~)0.808s151.01x
💻 LocalNitro1.206s (-26.1% 🟢)2.007s (-3.2%)0.800s151.02x
🐘 PostgresNitro1.214s (-4.8%)2.007s (~)0.794s151.02x
🐘 PostgresNext.js (Turbopack)1.258s2.007s0.750s151.06x
💻 LocalNext.js (Turbopack)1.347s2.005s0.659s151.14x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express2.716s (-5.0% 🟢)19.336s (+318.3% 🔺)16.620s21.00x
▲ VercelNitro2.825s (~)9.853s (+127.9% 🔺)7.027s41.04x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

Promise.all with 25 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express1.236s (-47.7% 🟢)2.008s (-33.3% 🟢)0.772s151.00x
🐘 PostgresNitro1.255s (-46.6% 🟢)2.007s (-33.3% 🟢)0.752s151.02x
🐘 PostgresNext.js (Turbopack)1.428s2.008s0.579s151.16x
💻 LocalNext.js (Turbopack)1.687s2.074s0.387s151.36x
💻 LocalExpress1.717s (-41.9% 🟢)2.006s (-41.9% 🟢)0.289s151.39x
💻 LocalNitro2.000s (-36.4% 🟢)2.365s (-39.1% 🟢)0.365s141.62x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro3.186s (-21.4% 🟢)11.331s (+91.4% 🔺)8.145s31.00x
▲ VercelExpress6.602s (+82.4% 🔺)18.243s (+257.0% 🔺)11.642s32.07x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

Promise.all with 50 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express1.383s (-60.3% 🟢)2.007s (-50.0% 🟢)0.624s151.00x
🐘 PostgresNitro1.398s (-59.8% 🟢)2.007s (-49.9% 🟢)0.609s151.01x
🐘 PostgresNext.js (Turbopack)1.735s2.315s0.580s131.25x
💻 LocalNext.js (Turbopack)4.602s5.298s0.696s73.33x
💻 LocalExpress4.827s (-42.1% 🟢)5.514s (-38.9% 🟢)0.687s63.49x
💻 LocalNitro6.170s (-26.1% 🟢)6.617s (-26.6% 🟢)0.447s54.46x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express5.289s (+24.7% 🔺)7.700s (+25.7% 🔺)2.411s41.00x
▲ VercelNitro5.461s (+54.9% 🔺)11.366s (+105.4% 🔺)5.905s31.03x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

Promise.race with 10 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.178s (-6.3% 🟢)2.009s (~)0.831s151.00x
🐘 PostgresExpress1.193s (-5.1% 🟢)2.008s (~)0.815s151.01x
🐘 PostgresNext.js (Turbopack)1.249s2.009s0.760s151.06x
💻 LocalNext.js (Turbopack)1.407s2.006s0.599s151.19x
💻 LocalExpress1.456s (-23.1% 🟢)2.007s (-15.1% 🟢)0.551s151.24x
💻 LocalNitro1.681s (-9.9% 🟢)2.073s (-11.4% 🟢)0.392s151.43x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express2.482s (-3.8%)8.298s (+90.8% 🔺)5.816s41.00x
▲ VercelNitro2.653s (+7.9% 🔺)5.245s (+25.8% 🔺)2.592s61.07x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

Promise.race with 25 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.242s (-46.9% 🟢)2.009s (-33.3% 🟢)0.767s151.00x
🐘 PostgresExpress1.261s (-46.1% 🟢)2.010s (-33.3% 🟢)0.748s151.02x
🐘 PostgresNext.js (Turbopack)1.403s2.008s0.605s151.13x
💻 LocalExpress1.970s (-37.1% 🟢)2.392s (-36.4% 🟢)0.423s131.59x
💻 LocalNext.js (Turbopack)2.017s2.591s0.574s121.62x
💻 LocalNitro2.086s (-31.9% 🟢)2.591s (-33.3% 🟢)0.505s121.68x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro3.436s (+6.3% 🔺)10.457s (+106.0% 🔺)7.020s31.00x
▲ VercelExpress3.725s (+16.7% 🔺)8.451s (+76.3% 🔺)4.726s41.08x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

Promise.race with 50 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.382s (-60.3% 🟢)2.008s (-49.9% 🟢)0.626s151.00x
🐘 PostgresExpress1.385s (-60.4% 🟢)2.008s (-49.9% 🟢)0.622s151.00x
🐘 PostgresNext.js (Turbopack)1.746s2.156s0.411s141.26x
💻 LocalExpress4.650s (-47.2% 🟢)5.180s (-44.1% 🟢)0.530s63.36x
💻 LocalNext.js (Turbopack)5.127s5.683s0.557s63.71x
💻 LocalNitro5.886s (-35.6% 🟢)6.413s (-36.0% 🟢)0.527s54.26x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro6.106s (+19.9% 🔺)10.232s (+50.1% 🔺)4.125s51.00x
▲ VercelExpress10.634s (+65.7% 🔺)15.236s (+86.3% 🔺)4.602s21.74x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

workflow with 10 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express0.565s (-32.6% 🟢)1.007s (-1.6%)0.442s601.00x
💻 LocalExpress0.578s (-41.3% 🟢)1.005s (-6.6% 🟢)0.427s601.02x
🐘 PostgresNitro0.593s (-27.7% 🟢)1.040s (+3.4%)0.447s591.05x
💻 LocalNitro0.697s (-29.0% 🟢)1.096s (~)0.399s551.23x
🐘 PostgresNext.js (Turbopack)0.837s1.007s0.170s601.48x
💻 LocalNext.js (Turbopack)0.868s1.004s0.136s601.54x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro4.851s (-78.0% 🟢)7.522s (-68.7% 🟢)2.672s81.00x
▲ VercelExpress4.974s (-73.8% 🟢)12.581s (-41.0% 🟢)7.606s61.03x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

workflow with 25 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express1.325s (-33.0% 🟢)2.008s (-11.1% 🟢)0.682s451.00x
🐘 PostgresNitro1.351s (-29.9% 🟢)2.030s (-3.4%)0.679s451.02x
💻 LocalNitro1.510s (-50.3% 🟢)2.006s (-46.6% 🟢)0.497s451.14x
💻 LocalExpress1.515s (-49.8% 🟢)2.006s (-44.1% 🟢)0.491s451.14x
🐘 PostgresNext.js (Turbopack)2.084s2.468s0.384s371.57x
💻 LocalNext.js (Turbopack)2.112s3.008s0.896s301.59x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express12.360s (-64.2% 🟢)17.479s (-52.5% 🟢)5.119s61.00x
▲ VercelNitro12.401s (-68.6% 🟢)15.005s (-63.7% 🟢)2.605s71.00x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

workflow with 50 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro2.594s (-36.8% 🟢)3.033s (-34.1% 🟢)0.439s401.00x
🐘 PostgresExpress2.702s (-32.3% 🟢)3.137s (-28.2% 🟢)0.434s391.04x
💻 LocalNitro3.229s (-65.3% 🟢)4.009s (-60.0% 🟢)0.780s301.24x
💻 LocalExpress3.324s (-63.9% 🟢)4.043s (-59.6% 🟢)0.719s301.28x
🐘 PostgresNext.js (Turbopack)3.925s4.010s0.085s301.51x
💻 LocalNext.js (Turbopack)4.452s5.052s0.601s241.72x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro25.276s (-73.9% 🟢)30.878s (-68.6% 🟢)5.602s41.00x
▲ VercelExpress26.350s (-79.7% 🟢)32.626s (-75.3% 🟢)6.276s41.04x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

workflow with 10 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.217s (-23.3% 🟢)1.006s (~)0.788s601.00x
🐘 PostgresExpress0.227s (-19.6% 🟢)1.006s (~)0.779s601.05x
🐘 PostgresNext.js (Turbopack)0.305s1.023s0.719s591.40x
💻 LocalNitro0.424s (-29.9% 🟢)1.004s (-1.7%)0.581s601.95x
💻 LocalExpress0.441s (-21.3% 🟢)1.004s (~)0.563s602.03x
💻 LocalNext.js (Turbopack)0.627s1.022s0.395s592.89x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express2.394s (+22.5% 🔺)12.031s (+230.8% 🔺)9.638s51.00x
▲ VercelNitro3.625s (+118.3% 🔺)10.359s (+209.1% 🔺)6.733s61.51x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

workflow with 25 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.339s (-31.7% 🟢)1.006s (~)0.668s901.00x
🐘 PostgresExpress0.361s (-29.1% 🟢)1.006s (~)0.645s901.07x
🐘 PostgresNext.js (Turbopack)0.515s1.007s0.492s901.52x
💻 LocalNitro2.152s (-15.2% 🟢)2.638s (-12.3% 🟢)0.486s356.35x
💻 LocalExpress2.471s (-1.7%)2.979s (-1.0%)0.508s317.29x
💻 LocalNext.js (Turbopack)2.513s3.225s0.712s287.42x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro4.568s (+41.6% 🔺)10.630s (+120.5% 🔺)6.062s91.00x
▲ VercelExpress5.640s (+85.1% 🔺)10.451s (+117.4% 🔺)4.811s101.23x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

workflow with 50 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.683s (-13.6% 🟢)1.006s (~)0.323s1201.00x
🐘 PostgresExpress0.705s (-13.9% 🟢)1.015s (~)0.310s1191.03x
🐘 PostgresNext.js (Turbopack)1.048s1.960s0.912s621.53x
💻 LocalNitro9.742s (-12.9% 🟢)10.277s (-11.9% 🟢)0.534s1214.27x
💻 LocalNext.js (Turbopack)10.810s11.575s0.766s1115.83x
💻 LocalExpress11.232s (~)11.856s (-0.7%)0.624s1116.45x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express13.763s (+85.5% 🔺)17.466s (+88.9% 🔺)3.702s71.00x
▲ VercelNitro15.302s (+98.1% 🔺)21.654s (+130.4% 🔺)6.352s61.11x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

Stream Benchmarks(includes TTFB metrics)
workflow with stream

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.156s (+463.8% 🔺)2.000s (+100.1% 🔺)0.001s (-6.7% 🟢)2.010s (+98.8% 🔺)0.855s101.00x
💻 LocalExpress1.163s (+484.4% 🔺)2.005s (+99.6% 🔺)0.011s (-13.2% 🟢)2.018s (+98.2% 🔺)0.854s101.01x
💻 LocalNitro1.165s (+445.3% 🔺)2.005s (+99.6% 🔺)0.012s (-0.8%)2.020s (+98.2% 🔺)0.854s101.01x
🐘 PostgresExpress1.169s (+469.8% 🔺)1.995s (+99.8% 🔺)0.001s (-31.3% 🟢)2.010s (+98.7% 🔺)0.841s101.01x
💻 LocalNext.js (Turbopack)1.214s2.003s0.011s2.017s0.804s101.05x
🐘 PostgresNext.js (Turbopack)1.233s2.003s0.001s2.012s0.779s101.07x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express2.318s (-7.5% 🟢)6.376s (+55.9% 🔺)1.539s (+60.1% 🔺)8.459s (+51.3% 🔺)6.140s101.00x
▲ VercelNitro3.129s (-18.4% 🟢)6.747s (+27.9% 🔺)1.486s (+100.3% 🔺)9.559s (+47.4% 🔺)6.431s101.35x
▲ VercelNext.js (Turbopack)⚠️missing-----

🔍 Observability: Express | Nitro

stream pipeline with 5 transform steps (1MB)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Nitro1.584s (+88.9% 🔺)2.010s (+98.6% 🔺)0.011s (+14.5% 🔺)2.022s (+81.2% 🔺)0.438s301.00x
🐘 PostgresNitro1.588s (+154.4% 🔺)2.007s (+99.4% 🔺)0.004s (-9.7% 🟢)2.026s (+98.1% 🔺)0.438s301.00x
🐘 PostgresExpress1.621s (+157.3% 🔺)2.001s (+98.8% 🔺)0.004s (~)2.027s (+98.1% 🔺)0.406s301.02x
💻 LocalExpress1.722s (+127.5% 🔺)2.043s (+98.6% 🔺)0.013s (+36.7% 🔺)2.059s (+98.0% 🔺)0.336s301.09x
🐘 PostgresNext.js (Turbopack)1.809s2.011s0.004s2.029s0.220s301.14x
💻 LocalNext.js (Turbopack)1.917s2.008s0.010s2.201s0.284s281.21x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express6.501s (~)13.670s (+70.7% 🔺)0.154s (-62.3% 🟢)14.972s (+69.5% 🔺)8.471s51.00x
▲ VercelNitro7.642s (-74.0% 🟢)7.694s (-75.0% 🟢)0.328s (+192.9% 🔺)10.227s (-67.8% 🟢)2.585s61.18x
▲ VercelNext.js (Turbopack)⚠️missing-----

🔍 Observability: Express | Nitro

10 parallel streams (1MB each)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express0.699s (-27.3% 🟢)1.012s (-20.8% 🟢)0.000s (-22.0% 🟢)1.027s (-21.4% 🟢)0.328s591.00x
🐘 PostgresNitro0.704s (-27.3% 🟢)1.015s (-18.6% 🟢)0.000s (+22.0% 🔺)1.032s (-18.0% 🟢)0.328s591.01x
🐘 PostgresNext.js (Turbopack)0.835s1.091s0.000s1.099s0.264s551.19x
💻 LocalNitro1.375s (+12.5% 🔺)2.013s (~)0.000s (+100.0% 🔺)2.015s (~)0.640s301.97x
💻 LocalNext.js (Turbopack)1.497s2.013s0.001s2.016s0.520s302.14x
💻 LocalExpress1.602s (+30.8% 🔺)2.018s (~)0.000s (-40.0% 🟢)2.020s (~)0.418s302.29x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro3.997s (+31.0% 🔺)8.575s (+95.2% 🔺)0.000s (-100.0% 🟢)9.792s (+103.6% 🔺)5.796s71.00x
▲ VercelExpress5.270s (+40.9% 🔺)8.952s (+75.4% 🔺)0.001s (+358.3% 🔺)10.718s (+93.8% 🔺)5.448s61.32x
▲ VercelNext.js (Turbopack)⚠️missing-----

🔍 Observability: Nitro | Express

fan-out fan-in 10 streams (1MB each)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.409s (-21.3% 🟢)2.142s (~)0.000s (-100.0% 🟢)2.154s (-0.9%)0.745s281.00x
🐘 PostgresExpress1.513s (-14.6% 🟢)2.174s (~)0.000s (+Infinity% 🔺)2.189s (~)0.677s281.07x
🐘 PostgresNext.js (Turbopack)1.650s2.145s0.000s2.162s0.512s281.17x
💻 LocalNitro3.097s (-8.6% 🟢)3.775s (-6.4% 🟢)0.001s (+40.6% 🔺)3.777s (-6.4% 🟢)0.681s162.20x
💻 LocalNext.js (Turbopack)3.186s3.674s0.000s3.678s0.492s172.26x
💻 LocalExpress3.351s (-3.4%)4.028s (~)0.001s (+41.7% 🔺)4.032s (~)0.681s152.38x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express5.775s (+25.9% 🔺)12.656s (+110.2% 🔺)0.001s (+Infinity% 🔺)15.088s (+133.7% 🔺)9.313s41.00x
▲ VercelNitro5.828s (+42.4% 🔺)17.093s (+218.1% 🔺)0.000s (-100.0% 🟢)17.759s (+206.5% 🔺)11.931s41.01x
▲ VercelNext.js (Turbopack)⚠️missing-----

🔍 Observability: Express | Nitro

Summary

Fastest Framework by World

Winner determined by most benchmark wins

World🥇 Fastest FrameworkWins
💻 LocalExpress9/21
🐘 PostgresNitro13/21
▲ VercelExpress11/21
Fastest World by Framework

Winner determined by most benchmark wins

Framework🥇 Fastest WorldWins
Express🐘 Postgres16/21
Next.js (Turbopack)🐘 Postgres15/21
Nitro🐘 Postgres17/21
Column Definitions
  • Workflow Time: Runtime reported by workflow (completedAt - createdAt) - primary metric
  • TTFB: Time to First Byte - time from workflow start until first stream byte received (stream benchmarks only)
  • Slurp: Time from first byte to complete stream consumption (stream benchmarks only)
  • Wall Time: Total testbench time (trigger workflow + poll for result)
  • Overhead: Testbench overhead (Wall Time - Workflow Time)
  • Samples: Number of benchmark iterations run
  • vs Fastest: How much slower compared to the fastest configuration for this benchmark

Worlds:

  • 💻 Local: In-memory filesystem world (local development)
  • 🐘 Postgres: PostgreSQL database world (local development)
  • ▲ Vercel: Vercel production/preview deployment
  • 🌐 Turso: Community world (local development)
  • 🌐 MongoDB: Community world (local development)
  • 🌐 Redis: Community world (local development)
  • 🌐 Jazz: Community world (local development)
  • 🌐 Redis: Community world (local development)
  • 🌐 Redis + BullMQ: Community world (local development)
  • 🌐 Cloudflare: Community world (local development)
  • 🌐 MySQL: Community world (local development)
  • 🌐 Azure: Community world (local development)
  • 🌐 NATS JetStream: Community world (local development)
  • 🌐 Upstash: Community world (local development)

📋 View full workflow run


Some benchmark jobs failed:

  • Local: success
  • Postgres: success
  • Vercel: failure

Check the workflow run for details.

@VaguelySerious
VaguelySerious marked this pull request as ready for review June 1, 2026 09:06
@VaguelySerious
VaguelySerious requested a review from a team as a code ownerJune 1, 2026 09:06
@VaguelySerious
VaguelySerious merged commit ae3c833 into mainJun 1, 2026
112 of 122 checks passed
@VaguelySerious
VaguelySerious deleted the peter/event-log-race-repro-classify-infra branch June 1, 2026 09:07
VaguelySerious added a commit that referenced this pull request Jun 1, 2026
(cherry picked from commit ae3c833)
(cherry picked from commit c1d7bab)
pranaygp added a commit that referenced this pull request Jun 2, 2026
* origin/main:
[world-vercel] Retry transient response-body parse failures in the HTTP client (#2204)
Add virtualization to the trace viewer (#2205)
Trace viewer: scroll-load events past an auto-load cap (#2200)
fix(core): resolve forwarded stream keys across deployments (#2191)
[e2e] Improve error labeling in event-log-race-repro CI job (#2190)
[core] Harden event pagination response parsing (#2180) (#2179)
Add loading skeleton to the new trace viewer (#2164)
Add tooltip components + apply on up/down detail pane (#2163)
fix(swc-plugin): allow wasm host imports during link (#2174)
[test] Forward-port reused-sleep replay divergence test (#2172)
[e2e] Add `event-log-race-repro` label for triggering CI stress-test (#2159)
Version Packages (beta) (#2162)
fix(world-local): skip Nov 2025 ghost versions on npm (#2168)
fix(core,errors): classify SDK encryption failures as RUNTIME_ERROR (#2145)
[web-shared][web] Fix events tab search (#2107)
Version Packages (beta) (#2147)
Allow setting workflow attributes from steps (#2157)
Better search handling on the trace viewer (#2144)
[docs] Document experimental attributes feature (#2141)
Sign up for freeto 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

@VaguelySerious
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
[e2e] Separate event-log-race-repro harness noise from real regressions by VaguelySerious · Pull Request #2190 · vercel/workflow · GitHub
Skip to content

[e2e] Separate event-log-race-repro harness noise from real regressions - #2190

Merged
VaguelySerious merged 1 commit into
mainfrom
peter/event-log-race-repro-classify-infra
Jun 1, 2026
Merged

[e2e] Separate event-log-race-repro harness noise from real regressions#2190
VaguelySerious merged 1 commit into
mainfrom
peter/event-log-race-repro-classify-infra

Conversation

@VaguelySerious

Copy link
Copy Markdown
Member

Summary

The event-log-race-repro job is currently red for the wrong reason. In a recent run, it reported 1231 of 2000 runs "did not complete cleanly" — yet CORRUPTED_EVENT_LOG / USER_ERROR / RUNTIME_ERROR were all 0. The entire count was harness-side noise.

What the other column was

The repro sorts each run into completed, CORRUPTED_EVENT_LOG, USER_ERROR, RUNTIME_ERROR, stuck, or other. Only the three named error codes mapped to their own bucket; everything else fell into other, and the --check gate failed the job on any non-completed run. So other conflated genuine corruption with:

  • HOOK_RESUME_FAILED — the run completed fine, but the harness's own resumeHook() rejected (typically because the sleep branch already finished the run and disposed the hook).
  • NO_WAKE_BRANCH — the run completed but the sleep branch won every iteration, so the wake path was never taken.
  • transport errors / timeouts thrown in the driver, and cancellations.

What was actually going wrong

A timing race in the test harness, not an SDK bug. The workflow's sleep budget is iterations × sleepMs = 5 × 5000 = 25000ms; the harness resumes the hook at resumeDelayMs + rand(resumeJitterMs) = up to 25000ms — the resume ceiling exactly equals the budget. On a fast/warm deployment the workflow exhausts its sleeps before the resume lands, so the resume hits a disposed hook and/or the wake branch is never taken.

The smoking gun: the #2 retry against the same already-warm deployment jumped 767→1231 other while stuck dropped to 0 and the step scenarios stayed perfect. Faster execution = the resume misses the window more often. It also means most "green" runs weren't even exercising the wake-branch shape the repro is meant to stress.

Changes

  1. Reclassify harness-side, non-corruption outcomes into a dedicated non-gating infra bucket (test + renderer). The job now gates only on regression-class outcomes (CORRUPTED_EVENT_LOG / USER_ERROR / RUNTIME_ERROR / stuck / other); infra is reported but never fails the job. The PR comment now reads "No event-log regressions… N runs hit harness-side infra outcomes (… do not fail the job)."
  2. Surface regressions ahead of infra in the failures table so the 20-row cap never hides a real failure behind a flood of timing rows.
  3. Restore wake-branch coverage: raise the default iterations ceiling (5 → 8). Because the run short-circuits via returnOnWake the moment the hook wins, a higher ceiling widens the window for the resume to land before sleep-budget exhaustion at ~no runtime cost. Added a beforeAll guard that warns when the resume ceiling is not below the sleep budget.
  4. Testability: the renderer's pure helpers are now exported and covered by node:test (run via a new lightweight Lint job).

Tests

node --test .github/scripts/**/*.test.js (8 tests) covers: infra is non-gating; regressionCount ignores completed/infra; an all-infra results file (mirroring the production comment) yields 0 regressions; regressions sort ahead of infra; --check exits 0 on infra-only and 1 on a corruption-class outcome.

Note: the full 2000-run repro only runs against a deployment behind the event-log-race-repro label, so the reclassification's end-to-end effect is best confirmed by adding that label to this PR.

🤖 Generated with Claude Code

The event-log-race-repro job classified every non-completed run into an
`other` grab-bag and gated on it. Hook-resume timing races (HOOK_RESUME_FAILED,
NO_WAKE_BRANCH) and transport errors in the repro driver — none of which are
event-log corruption — landed there and failed the job, drowning the signal it
exists to detect.
- Route harness-side, non-corruption outcomes to a dedicated non-gating `infra`
bucket (test + renderer). The job now gates only on regression-class outcomes
(CORRUPTED_EVENT_LOG / USER_ERROR / RUNTIME_ERROR / stuck / other).
- Sort regressions ahead of infra rows so the 20-row cap never hides a real
failure behind a flood of harness-timing rows.
- Raise the default hook/sleep iteration ceiling (5 -> 8). Because the run
short-circuits via returnOnWake the moment the hook wins, this widens the
window for the delayed resume to land before the sleep budget is exhausted,
at ~no runtime cost — restoring the wake-branch coverage the scenario exists
to exercise. Add a beforeAll guard that warns when the resume ceiling is not
below the sleep budget.
- Make the renderer's pure helpers unit-testable and add node:test coverage,
wired into the Lint workflow.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@changeset-bot

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: e100a60

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

This PR includes changesets to release 0 packages

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

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

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

@vercel

vercelBot commented May 31, 2026

Copy link
Copy Markdown
Contributor

@github-actions

github-actionsBot commented May 31, 2026

Copy link
Copy Markdown
Contributor

🧪 E2E Test Results

Some tests failed

Summary

PassedFailedSkippedTotal
❌ ▲ Vercel Production126332191485
❌ 💻 Local Development167012191890
✅ 📦 Local Production167102191890
✅ 🐘 Local Postgres167102191890
✅ 🪟 Windows13500135
❌ 📋 Other7681176945
Total7178510528235

❌ Failed Tests

▲ Vercel Production (3 failed)

express (1 failed):

  • instanceMethodStepWorkflow - instance methods with "use step" directive | wrun_01KSZ4H8N0DE044HA3WQ2AG25H | 🔍 observability

nextjs-webpack (2 failed):

  • AbortController abortHookOrderingWorkflow [listener-first-abort-first]: addEventListener → hook.then → abort() → resumeHook
  • AbortController abortHookOrderingWorkflow [listener-first-hook-first]: addEventListener → hook.then → resumeHook → abort()
💻 Local Development (1 failed)

express-stable (1 failed):

  • hookWithSleepFinalStepWorkflow - step only on final payload | wrun_01KSZ4NB8SC1XKHH9GSXQEKXZR
📋 Other (1 failed)

e2e-vercel-prod-tanstack-start (1 failed):

  • AbortController abortHookOrderingWorkflow [listener-first-abort-first]: addEventListener → hook.then → abort() → resumeHook

Details by Category

❌ ▲ Vercel Production
AppPassedFailedSkipped
✅ astro109026
✅ example109026
❌ express108126
✅ fastify109026
✅ hono109026
✅ nextjs-turbopack13302
❌ nextjs-webpack13122
✅ nitro109026
✅ nuxt109026
✅ sveltekit12807
✅ vite109026
❌ 💻 Local Development
AppPassedFailedSkipped
✅ astro-stable110025
❌ express-stable109125
✅ fastify-stable110025
✅ hono-stable110025
✅ nextjs-turbopack-canary116019
✅ nextjs-turbopack-stable-lazy-discovery-disabled13500
✅ nextjs-turbopack-stable-lazy-discovery-enabled13500
✅ nextjs-webpack-canary116019
✅ nextjs-webpack-stable-lazy-discovery-disabled13500
✅ nextjs-webpack-stable-lazy-discovery-enabled13500
✅ nitro-stable110025
✅ nuxt-stable110025
✅ sveltekit-stable12906
✅ vite-stable110025
✅ 📦 Local Production
AppPassedFailedSkipped
✅ astro-stable110025
✅ express-stable110025
✅ fastify-stable110025
✅ hono-stable110025
✅ nextjs-turbopack-canary116019
✅ nextjs-turbopack-stable-lazy-discovery-disabled13500
✅ nextjs-turbopack-stable-lazy-discovery-enabled13500
✅ nextjs-webpack-canary116019
✅ nextjs-webpack-stable-lazy-discovery-disabled13500
✅ nextjs-webpack-stable-lazy-discovery-enabled13500
✅ nitro-stable110025
✅ nuxt-stable110025
✅ sveltekit-stable12906
✅ vite-stable110025
✅ 🐘 Local Postgres
AppPassedFailedSkipped
✅ astro-stable110025
✅ express-stable110025
✅ fastify-stable110025
✅ hono-stable110025
✅ nextjs-turbopack-canary116019
✅ nextjs-turbopack-stable-lazy-discovery-disabled13500
✅ nextjs-turbopack-stable-lazy-discovery-enabled13500
✅ nextjs-webpack-canary116019
✅ nextjs-webpack-stable-lazy-discovery-disabled13500
✅ nextjs-webpack-stable-lazy-discovery-enabled13500
✅ nitro-stable110025
✅ nuxt-stable110025
✅ sveltekit-stable12906
✅ vite-stable110025
✅ 🪟 Windows
AppPassedFailedSkipped
✅ nextjs-turbopack13500
❌ 📋 Other
AppPassedFailedSkipped
✅ e2e-local-dev-nest-stable110025
✅ e2e-local-dev-tanstack-start-110025
✅ e2e-local-postgres-nest-stable110025
✅ e2e-local-postgres-tanstack-start-110025
✅ e2e-local-prod-nest-stable110025
✅ e2e-local-prod-tanstack-start-110025
❌ e2e-vercel-prod-tanstack-start108126

📋 View full workflow run


Some E2E test jobs failed:

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

Check the workflow run for details.

@github-actions

github-actionsBot commented May 31, 2026

Copy link
Copy Markdown
Contributor

📊 Benchmark Results

📈 Comparing against baseline from main branch. Green 🟢 = faster, Red 🔺 = slower.

workflow with no steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Express0.042s (-5.9% 🟢)1.006s (~)0.964s101.00x
💻 LocalNitro0.045s (+5.3% 🔺)1.006s (~)0.961s101.09x
💻 LocalNext.js (Turbopack)0.059s1.007s0.947s101.42x
🐘 PostgresExpress0.060s (+2.8%)1.012s (~)0.952s101.43x
🐘 PostgresNitro0.062s (-35.2% 🟢)1.012s (-2.9%)0.951s101.48x
🐘 PostgresNext.js (Turbopack)0.071s1.013s0.941s101.71x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express0.304s (+29.2% 🔺)9.230s (+332.2% 🔺)8.926s101.00x
▲ VercelNitro0.467s (+14.0% 🔺)8.212s (+227.3% 🔺)7.745s101.54x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

workflow with 1 step

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Nitro1.090s (-3.6%)2.007s (~)0.917s101.00x
💻 LocalExpress1.094s (-2.8%)2.006s (~)0.912s101.00x
🐘 PostgresNitro1.100s (-3.5%)2.008s (~)0.909s101.01x
🐘 PostgresExpress1.108s (-3.4%)2.011s (~)0.903s101.02x
💻 LocalNext.js (Turbopack)1.137s2.006s0.869s101.04x
🐘 PostgresNext.js (Turbopack)1.154s2.011s0.856s101.06x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro1.951s (-49.9% 🟢)8.918s (+50.9% 🔺)6.967s101.00x
▲ VercelExpress2.816s (+50.2% 🔺)11.043s (+190.0% 🔺)8.227s101.44x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

workflow with 10 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Express10.509s (-3.8%)11.022s (~)0.513s31.00x
🐘 PostgresExpress10.527s (-4.0%)11.018s (~)0.490s31.00x
🐘 PostgresNitro10.543s (-3.0%)11.018s (~)0.475s31.00x
💻 LocalNitro10.549s (-3.6%)11.023s (~)0.475s31.00x
💻 LocalNext.js (Turbopack)10.771s11.022s0.251s31.02x
🐘 PostgresNext.js (Turbopack)10.864s11.019s0.155s31.03x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro13.250s (-44.2% 🟢)17.759s (-29.3% 🟢)4.509s31.00x
▲ VercelExpress18.536s (+9.2% 🔺)25.082s (+25.3% 🔺)6.546s21.40x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

workflow with 25 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro13.713s (-6.0% 🟢)14.018s (-6.7% 🟢)0.304s51.00x
💻 LocalExpress13.737s (-8.2% 🟢)14.027s (-6.7% 🟢)0.290s51.00x
🐘 PostgresExpress13.748s (-5.7% 🟢)14.016s (-6.7% 🟢)0.268s51.00x
💻 LocalNitro13.768s (-8.6% 🟢)14.027s (-12.5% 🟢)0.260s51.00x
💻 LocalNext.js (Turbopack)14.375s15.031s0.656s41.05x
🐘 PostgresNext.js (Turbopack)14.516s15.019s0.503s41.06x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro22.401s (-65.2% 🟢)41.317s (-38.0% 🟢)18.916s21.00x
▲ VercelExpress22.701s (-54.9% 🟢)31.002s (-41.0% 🟢)8.301s21.01x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

workflow with 50 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro12.332s (-11.7% 🟢)13.018s (-9.0% 🟢)0.687s71.00x
🐘 PostgresExpress12.367s (-11.7% 🟢)13.017s (-10.8% 🟢)0.649s71.00x
💻 LocalExpress12.445s (-25.0% 🟢)13.025s (-23.5% 🟢)0.580s71.01x
💻 LocalNitro12.686s (-24.4% 🟢)13.168s (-22.7% 🟢)0.482s71.03x
💻 LocalNext.js (Turbopack)13.628s14.028s0.400s71.11x
🐘 PostgresNext.js (Turbopack)13.797s14.164s0.367s71.12x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express27.762s (-77.1% 🟢)31.197s (-74.8% 🟢)3.435s31.00x
▲ VercelNitro28.303s (-93.3% 🟢)36.682s (-91.4% 🟢)8.379s31.02x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

Promise.all with 10 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express1.186s (-5.9% 🟢)2.008s (~)0.822s151.00x
💻 LocalExpress1.198s (-19.6% 🟢)2.006s (~)0.808s151.01x
💻 LocalNitro1.206s (-26.1% 🟢)2.007s (-3.2%)0.800s151.02x
🐘 PostgresNitro1.214s (-4.8%)2.007s (~)0.794s151.02x
🐘 PostgresNext.js (Turbopack)1.258s2.007s0.750s151.06x
💻 LocalNext.js (Turbopack)1.347s2.005s0.659s151.14x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express2.716s (-5.0% 🟢)19.336s (+318.3% 🔺)16.620s21.00x
▲ VercelNitro2.825s (~)9.853s (+127.9% 🔺)7.027s41.04x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

Promise.all with 25 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express1.236s (-47.7% 🟢)2.008s (-33.3% 🟢)0.772s151.00x
🐘 PostgresNitro1.255s (-46.6% 🟢)2.007s (-33.3% 🟢)0.752s151.02x
🐘 PostgresNext.js (Turbopack)1.428s2.008s0.579s151.16x
💻 LocalNext.js (Turbopack)1.687s2.074s0.387s151.36x
💻 LocalExpress1.717s (-41.9% 🟢)2.006s (-41.9% 🟢)0.289s151.39x
💻 LocalNitro2.000s (-36.4% 🟢)2.365s (-39.1% 🟢)0.365s141.62x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro3.186s (-21.4% 🟢)11.331s (+91.4% 🔺)8.145s31.00x
▲ VercelExpress6.602s (+82.4% 🔺)18.243s (+257.0% 🔺)11.642s32.07x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

Promise.all with 50 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express1.383s (-60.3% 🟢)2.007s (-50.0% 🟢)0.624s151.00x
🐘 PostgresNitro1.398s (-59.8% 🟢)2.007s (-49.9% 🟢)0.609s151.01x
🐘 PostgresNext.js (Turbopack)1.735s2.315s0.580s131.25x
💻 LocalNext.js (Turbopack)4.602s5.298s0.696s73.33x
💻 LocalExpress4.827s (-42.1% 🟢)5.514s (-38.9% 🟢)0.687s63.49x
💻 LocalNitro6.170s (-26.1% 🟢)6.617s (-26.6% 🟢)0.447s54.46x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express5.289s (+24.7% 🔺)7.700s (+25.7% 🔺)2.411s41.00x
▲ VercelNitro5.461s (+54.9% 🔺)11.366s (+105.4% 🔺)5.905s31.03x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

Promise.race with 10 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.178s (-6.3% 🟢)2.009s (~)0.831s151.00x
🐘 PostgresExpress1.193s (-5.1% 🟢)2.008s (~)0.815s151.01x
🐘 PostgresNext.js (Turbopack)1.249s2.009s0.760s151.06x
💻 LocalNext.js (Turbopack)1.407s2.006s0.599s151.19x
💻 LocalExpress1.456s (-23.1% 🟢)2.007s (-15.1% 🟢)0.551s151.24x
💻 LocalNitro1.681s (-9.9% 🟢)2.073s (-11.4% 🟢)0.392s151.43x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express2.482s (-3.8%)8.298s (+90.8% 🔺)5.816s41.00x
▲ VercelNitro2.653s (+7.9% 🔺)5.245s (+25.8% 🔺)2.592s61.07x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

Promise.race with 25 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.242s (-46.9% 🟢)2.009s (-33.3% 🟢)0.767s151.00x
🐘 PostgresExpress1.261s (-46.1% 🟢)2.010s (-33.3% 🟢)0.748s151.02x
🐘 PostgresNext.js (Turbopack)1.403s2.008s0.605s151.13x
💻 LocalExpress1.970s (-37.1% 🟢)2.392s (-36.4% 🟢)0.423s131.59x
💻 LocalNext.js (Turbopack)2.017s2.591s0.574s121.62x
💻 LocalNitro2.086s (-31.9% 🟢)2.591s (-33.3% 🟢)0.505s121.68x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro3.436s (+6.3% 🔺)10.457s (+106.0% 🔺)7.020s31.00x
▲ VercelExpress3.725s (+16.7% 🔺)8.451s (+76.3% 🔺)4.726s41.08x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

Promise.race with 50 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.382s (-60.3% 🟢)2.008s (-49.9% 🟢)0.626s151.00x
🐘 PostgresExpress1.385s (-60.4% 🟢)2.008s (-49.9% 🟢)0.622s151.00x
🐘 PostgresNext.js (Turbopack)1.746s2.156s0.411s141.26x
💻 LocalExpress4.650s (-47.2% 🟢)5.180s (-44.1% 🟢)0.530s63.36x
💻 LocalNext.js (Turbopack)5.127s5.683s0.557s63.71x
💻 LocalNitro5.886s (-35.6% 🟢)6.413s (-36.0% 🟢)0.527s54.26x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro6.106s (+19.9% 🔺)10.232s (+50.1% 🔺)4.125s51.00x
▲ VercelExpress10.634s (+65.7% 🔺)15.236s (+86.3% 🔺)4.602s21.74x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

workflow with 10 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express0.565s (-32.6% 🟢)1.007s (-1.6%)0.442s601.00x
💻 LocalExpress0.578s (-41.3% 🟢)1.005s (-6.6% 🟢)0.427s601.02x
🐘 PostgresNitro0.593s (-27.7% 🟢)1.040s (+3.4%)0.447s591.05x
💻 LocalNitro0.697s (-29.0% 🟢)1.096s (~)0.399s551.23x
🐘 PostgresNext.js (Turbopack)0.837s1.007s0.170s601.48x
💻 LocalNext.js (Turbopack)0.868s1.004s0.136s601.54x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro4.851s (-78.0% 🟢)7.522s (-68.7% 🟢)2.672s81.00x
▲ VercelExpress4.974s (-73.8% 🟢)12.581s (-41.0% 🟢)7.606s61.03x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

workflow with 25 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express1.325s (-33.0% 🟢)2.008s (-11.1% 🟢)0.682s451.00x
🐘 PostgresNitro1.351s (-29.9% 🟢)2.030s (-3.4%)0.679s451.02x
💻 LocalNitro1.510s (-50.3% 🟢)2.006s (-46.6% 🟢)0.497s451.14x
💻 LocalExpress1.515s (-49.8% 🟢)2.006s (-44.1% 🟢)0.491s451.14x
🐘 PostgresNext.js (Turbopack)2.084s2.468s0.384s371.57x
💻 LocalNext.js (Turbopack)2.112s3.008s0.896s301.59x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express12.360s (-64.2% 🟢)17.479s (-52.5% 🟢)5.119s61.00x
▲ VercelNitro12.401s (-68.6% 🟢)15.005s (-63.7% 🟢)2.605s71.00x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

workflow with 50 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro2.594s (-36.8% 🟢)3.033s (-34.1% 🟢)0.439s401.00x
🐘 PostgresExpress2.702s (-32.3% 🟢)3.137s (-28.2% 🟢)0.434s391.04x
💻 LocalNitro3.229s (-65.3% 🟢)4.009s (-60.0% 🟢)0.780s301.24x
💻 LocalExpress3.324s (-63.9% 🟢)4.043s (-59.6% 🟢)0.719s301.28x
🐘 PostgresNext.js (Turbopack)3.925s4.010s0.085s301.51x
💻 LocalNext.js (Turbopack)4.452s5.052s0.601s241.72x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro25.276s (-73.9% 🟢)30.878s (-68.6% 🟢)5.602s41.00x
▲ VercelExpress26.350s (-79.7% 🟢)32.626s (-75.3% 🟢)6.276s41.04x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

workflow with 10 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.217s (-23.3% 🟢)1.006s (~)0.788s601.00x
🐘 PostgresExpress0.227s (-19.6% 🟢)1.006s (~)0.779s601.05x
🐘 PostgresNext.js (Turbopack)0.305s1.023s0.719s591.40x
💻 LocalNitro0.424s (-29.9% 🟢)1.004s (-1.7%)0.581s601.95x
💻 LocalExpress0.441s (-21.3% 🟢)1.004s (~)0.563s602.03x
💻 LocalNext.js (Turbopack)0.627s1.022s0.395s592.89x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express2.394s (+22.5% 🔺)12.031s (+230.8% 🔺)9.638s51.00x
▲ VercelNitro3.625s (+118.3% 🔺)10.359s (+209.1% 🔺)6.733s61.51x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

workflow with 25 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.339s (-31.7% 🟢)1.006s (~)0.668s901.00x
🐘 PostgresExpress0.361s (-29.1% 🟢)1.006s (~)0.645s901.07x
🐘 PostgresNext.js (Turbopack)0.515s1.007s0.492s901.52x
💻 LocalNitro2.152s (-15.2% 🟢)2.638s (-12.3% 🟢)0.486s356.35x
💻 LocalExpress2.471s (-1.7%)2.979s (-1.0%)0.508s317.29x
💻 LocalNext.js (Turbopack)2.513s3.225s0.712s287.42x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro4.568s (+41.6% 🔺)10.630s (+120.5% 🔺)6.062s91.00x
▲ VercelExpress5.640s (+85.1% 🔺)10.451s (+117.4% 🔺)4.811s101.23x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

workflow with 50 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.683s (-13.6% 🟢)1.006s (~)0.323s1201.00x
🐘 PostgresExpress0.705s (-13.9% 🟢)1.015s (~)0.310s1191.03x
🐘 PostgresNext.js (Turbopack)1.048s1.960s0.912s621.53x
💻 LocalNitro9.742s (-12.9% 🟢)10.277s (-11.9% 🟢)0.534s1214.27x
💻 LocalNext.js (Turbopack)10.810s11.575s0.766s1115.83x
💻 LocalExpress11.232s (~)11.856s (-0.7%)0.624s1116.45x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express13.763s (+85.5% 🔺)17.466s (+88.9% 🔺)3.702s71.00x
▲ VercelNitro15.302s (+98.1% 🔺)21.654s (+130.4% 🔺)6.352s61.11x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

Stream Benchmarks(includes TTFB metrics)
workflow with stream

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.156s (+463.8% 🔺)2.000s (+100.1% 🔺)0.001s (-6.7% 🟢)2.010s (+98.8% 🔺)0.855s101.00x
💻 LocalExpress1.163s (+484.4% 🔺)2.005s (+99.6% 🔺)0.011s (-13.2% 🟢)2.018s (+98.2% 🔺)0.854s101.01x
💻 LocalNitro1.165s (+445.3% 🔺)2.005s (+99.6% 🔺)0.012s (-0.8%)2.020s (+98.2% 🔺)0.854s101.01x
🐘 PostgresExpress1.169s (+469.8% 🔺)1.995s (+99.8% 🔺)0.001s (-31.3% 🟢)2.010s (+98.7% 🔺)0.841s101.01x
💻 LocalNext.js (Turbopack)1.214s2.003s0.011s2.017s0.804s101.05x
🐘 PostgresNext.js (Turbopack)1.233s2.003s0.001s2.012s0.779s101.07x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express2.318s (-7.5% 🟢)6.376s (+55.9% 🔺)1.539s (+60.1% 🔺)8.459s (+51.3% 🔺)6.140s101.00x
▲ VercelNitro3.129s (-18.4% 🟢)6.747s (+27.9% 🔺)1.486s (+100.3% 🔺)9.559s (+47.4% 🔺)6.431s101.35x
▲ VercelNext.js (Turbopack)⚠️missing-----

🔍 Observability: Express | Nitro

stream pipeline with 5 transform steps (1MB)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Nitro1.584s (+88.9% 🔺)2.010s (+98.6% 🔺)0.011s (+14.5% 🔺)2.022s (+81.2% 🔺)0.438s301.00x
🐘 PostgresNitro1.588s (+154.4% 🔺)2.007s (+99.4% 🔺)0.004s (-9.7% 🟢)2.026s (+98.1% 🔺)0.438s301.00x
🐘 PostgresExpress1.621s (+157.3% 🔺)2.001s (+98.8% 🔺)0.004s (~)2.027s (+98.1% 🔺)0.406s301.02x
💻 LocalExpress1.722s (+127.5% 🔺)2.043s (+98.6% 🔺)0.013s (+36.7% 🔺)2.059s (+98.0% 🔺)0.336s301.09x
🐘 PostgresNext.js (Turbopack)1.809s2.011s0.004s2.029s0.220s301.14x
💻 LocalNext.js (Turbopack)1.917s2.008s0.010s2.201s0.284s281.21x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express6.501s (~)13.670s (+70.7% 🔺)0.154s (-62.3% 🟢)14.972s (+69.5% 🔺)8.471s51.00x
▲ VercelNitro7.642s (-74.0% 🟢)7.694s (-75.0% 🟢)0.328s (+192.9% 🔺)10.227s (-67.8% 🟢)2.585s61.18x
▲ VercelNext.js (Turbopack)⚠️missing-----

🔍 Observability: Express | Nitro

10 parallel streams (1MB each)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express0.699s (-27.3% 🟢)1.012s (-20.8% 🟢)0.000s (-22.0% 🟢)1.027s (-21.4% 🟢)0.328s591.00x
🐘 PostgresNitro0.704s (-27.3% 🟢)1.015s (-18.6% 🟢)0.000s (+22.0% 🔺)1.032s (-18.0% 🟢)0.328s591.01x
🐘 PostgresNext.js (Turbopack)0.835s1.091s0.000s1.099s0.264s551.19x
💻 LocalNitro1.375s (+12.5% 🔺)2.013s (~)0.000s (+100.0% 🔺)2.015s (~)0.640s301.97x
💻 LocalNext.js (Turbopack)1.497s2.013s0.001s2.016s0.520s302.14x
💻 LocalExpress1.602s (+30.8% 🔺)2.018s (~)0.000s (-40.0% 🟢)2.020s (~)0.418s302.29x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro3.997s (+31.0% 🔺)8.575s (+95.2% 🔺)0.000s (-100.0% 🟢)9.792s (+103.6% 🔺)5.796s71.00x
▲ VercelExpress5.270s (+40.9% 🔺)8.952s (+75.4% 🔺)0.001s (+358.3% 🔺)10.718s (+93.8% 🔺)5.448s61.32x
▲ VercelNext.js (Turbopack)⚠️missing-----

🔍 Observability: Nitro | Express

fan-out fan-in 10 streams (1MB each)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.409s (-21.3% 🟢)2.142s (~)0.000s (-100.0% 🟢)2.154s (-0.9%)0.745s281.00x
🐘 PostgresExpress1.513s (-14.6% 🟢)2.174s (~)0.000s (+Infinity% 🔺)2.189s (~)0.677s281.07x
🐘 PostgresNext.js (Turbopack)1.650s2.145s0.000s2.162s0.512s281.17x
💻 LocalNitro3.097s (-8.6% 🟢)3.775s (-6.4% 🟢)0.001s (+40.6% 🔺)3.777s (-6.4% 🟢)0.681s162.20x
💻 LocalNext.js (Turbopack)3.186s3.674s0.000s3.678s0.492s172.26x
💻 LocalExpress3.351s (-3.4%)4.028s (~)0.001s (+41.7% 🔺)4.032s (~)0.681s152.38x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express5.775s (+25.9% 🔺)12.656s (+110.2% 🔺)0.001s (+Infinity% 🔺)15.088s (+133.7% 🔺)9.313s41.00x
▲ VercelNitro5.828s (+42.4% 🔺)17.093s (+218.1% 🔺)0.000s (-100.0% 🟢)17.759s (+206.5% 🔺)11.931s41.01x
▲ VercelNext.js (Turbopack)⚠️missing-----

🔍 Observability: Express | Nitro

Summary

Fastest Framework by World

Winner determined by most benchmark wins

World🥇 Fastest FrameworkWins
💻 LocalExpress9/21
🐘 PostgresNitro13/21
▲ VercelExpress11/21
Fastest World by Framework

Winner determined by most benchmark wins

Framework🥇 Fastest WorldWins
Express🐘 Postgres16/21
Next.js (Turbopack)🐘 Postgres15/21
Nitro🐘 Postgres17/21
Column Definitions
  • Workflow Time: Runtime reported by workflow (completedAt - createdAt) - primary metric
  • TTFB: Time to First Byte - time from workflow start until first stream byte received (stream benchmarks only)
  • Slurp: Time from first byte to complete stream consumption (stream benchmarks only)
  • Wall Time: Total testbench time (trigger workflow + poll for result)
  • Overhead: Testbench overhead (Wall Time - Workflow Time)
  • Samples: Number of benchmark iterations run
  • vs Fastest: How much slower compared to the fastest configuration for this benchmark

Worlds:

  • 💻 Local: In-memory filesystem world (local development)
  • 🐘 Postgres: PostgreSQL database world (local development)
  • ▲ Vercel: Vercel production/preview deployment
  • 🌐 Turso: Community world (local development)
  • 🌐 MongoDB: Community world (local development)
  • 🌐 Redis: Community world (local development)
  • 🌐 Jazz: Community world (local development)
  • 🌐 Redis: Community world (local development)
  • 🌐 Redis + BullMQ: Community world (local development)
  • 🌐 Cloudflare: Community world (local development)
  • 🌐 MySQL: Community world (local development)
  • 🌐 Azure: Community world (local development)
  • 🌐 NATS JetStream: Community world (local development)
  • 🌐 Upstash: Community world (local development)

📋 View full workflow run


Some benchmark jobs failed:

  • Local: success
  • Postgres: success
  • Vercel: failure

Check the workflow run for details.

@VaguelySerious
VaguelySerious marked this pull request as ready for review June 1, 2026 09:06
@VaguelySerious
VaguelySerious requested a review from a team as a code ownerJune 1, 2026 09:06
@VaguelySerious
VaguelySerious merged commit ae3c833 into mainJun 1, 2026
112 of 122 checks passed
@VaguelySerious
VaguelySerious deleted the peter/event-log-race-repro-classify-infra branch June 1, 2026 09:07
VaguelySerious added a commit that referenced this pull request Jun 1, 2026
(cherry picked from commit ae3c833)
(cherry picked from commit c1d7bab)
pranaygp added a commit that referenced this pull request Jun 2, 2026
* origin/main:
[world-vercel] Retry transient response-body parse failures in the HTTP client (#2204)
Add virtualization to the trace viewer (#2205)
Trace viewer: scroll-load events past an auto-load cap (#2200)
fix(core): resolve forwarded stream keys across deployments (#2191)
[e2e] Improve error labeling in event-log-race-repro CI job (#2190)
[core] Harden event pagination response parsing (#2180) (#2179)
Add loading skeleton to the new trace viewer (#2164)
Add tooltip components + apply on up/down detail pane (#2163)
fix(swc-plugin): allow wasm host imports during link (#2174)
[test] Forward-port reused-sleep replay divergence test (#2172)
[e2e] Add `event-log-race-repro` label for triggering CI stress-test (#2159)
Version Packages (beta) (#2162)
fix(world-local): skip Nov 2025 ghost versions on npm (#2168)
fix(core,errors): classify SDK encryption failures as RUNTIME_ERROR (#2145)
[web-shared][web] Fix events tab search (#2107)
Version Packages (beta) (#2147)
Allow setting workflow attributes from steps (#2157)
Better search handling on the trace viewer (#2144)
[docs] Document experimental attributes feature (#2141)
Sign up for freeto 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

@VaguelySerious
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' [e2e] Separate event-log-race-repro harness noise from real regressions by VaguelySerious · Pull Request #2190 · vercel/workflow · GitHub
Skip to content

[e2e] Separate event-log-race-repro harness noise from real regressions - #2190

Merged
VaguelySerious merged 1 commit into
mainfrom
peter/event-log-race-repro-classify-infra
Jun 1, 2026
Merged

[e2e] Separate event-log-race-repro harness noise from real regressions#2190
VaguelySerious merged 1 commit into
mainfrom
peter/event-log-race-repro-classify-infra

Conversation

@VaguelySerious

Copy link
Copy Markdown
Member

Summary

The event-log-race-repro job is currently red for the wrong reason. In a recent run, it reported 1231 of 2000 runs "did not complete cleanly" — yet CORRUPTED_EVENT_LOG / USER_ERROR / RUNTIME_ERROR were all 0. The entire count was harness-side noise.

What the other column was

The repro sorts each run into completed, CORRUPTED_EVENT_LOG, USER_ERROR, RUNTIME_ERROR, stuck, or other. Only the three named error codes mapped to their own bucket; everything else fell into other, and the --check gate failed the job on any non-completed run. So other conflated genuine corruption with:

  • HOOK_RESUME_FAILED — the run completed fine, but the harness's own resumeHook() rejected (typically because the sleep branch already finished the run and disposed the hook).
  • NO_WAKE_BRANCH — the run completed but the sleep branch won every iteration, so the wake path was never taken.
  • transport errors / timeouts thrown in the driver, and cancellations.

What was actually going wrong

A timing race in the test harness, not an SDK bug. The workflow's sleep budget is iterations × sleepMs = 5 × 5000 = 25000ms; the harness resumes the hook at resumeDelayMs + rand(resumeJitterMs) = up to 25000ms — the resume ceiling exactly equals the budget. On a fast/warm deployment the workflow exhausts its sleeps before the resume lands, so the resume hits a disposed hook and/or the wake branch is never taken.

The smoking gun: the #2 retry against the same already-warm deployment jumped 767→1231 other while stuck dropped to 0 and the step scenarios stayed perfect. Faster execution = the resume misses the window more often. It also means most "green" runs weren't even exercising the wake-branch shape the repro is meant to stress.

Changes

  1. Reclassify harness-side, non-corruption outcomes into a dedicated non-gating infra bucket (test + renderer). The job now gates only on regression-class outcomes (CORRUPTED_EVENT_LOG / USER_ERROR / RUNTIME_ERROR / stuck / other); infra is reported but never fails the job. The PR comment now reads "No event-log regressions… N runs hit harness-side infra outcomes (… do not fail the job)."
  2. Surface regressions ahead of infra in the failures table so the 20-row cap never hides a real failure behind a flood of timing rows.
  3. Restore wake-branch coverage: raise the default iterations ceiling (5 → 8). Because the run short-circuits via returnOnWake the moment the hook wins, a higher ceiling widens the window for the resume to land before sleep-budget exhaustion at ~no runtime cost. Added a beforeAll guard that warns when the resume ceiling is not below the sleep budget.
  4. Testability: the renderer's pure helpers are now exported and covered by node:test (run via a new lightweight Lint job).

Tests

node --test .github/scripts/**/*.test.js (8 tests) covers: infra is non-gating; regressionCount ignores completed/infra; an all-infra results file (mirroring the production comment) yields 0 regressions; regressions sort ahead of infra; --check exits 0 on infra-only and 1 on a corruption-class outcome.

Note: the full 2000-run repro only runs against a deployment behind the event-log-race-repro label, so the reclassification's end-to-end effect is best confirmed by adding that label to this PR.

🤖 Generated with Claude Code

The event-log-race-repro job classified every non-completed run into an
`other` grab-bag and gated on it. Hook-resume timing races (HOOK_RESUME_FAILED,
NO_WAKE_BRANCH) and transport errors in the repro driver — none of which are
event-log corruption — landed there and failed the job, drowning the signal it
exists to detect.
- Route harness-side, non-corruption outcomes to a dedicated non-gating `infra`
bucket (test + renderer). The job now gates only on regression-class outcomes
(CORRUPTED_EVENT_LOG / USER_ERROR / RUNTIME_ERROR / stuck / other).
- Sort regressions ahead of infra rows so the 20-row cap never hides a real
failure behind a flood of harness-timing rows.
- Raise the default hook/sleep iteration ceiling (5 -> 8). Because the run
short-circuits via returnOnWake the moment the hook wins, this widens the
window for the delayed resume to land before the sleep budget is exhausted,
at ~no runtime cost — restoring the wake-branch coverage the scenario exists
to exercise. Add a beforeAll guard that warns when the resume ceiling is not
below the sleep budget.
- Make the renderer's pure helpers unit-testable and add node:test coverage,
wired into the Lint workflow.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@changeset-bot

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: e100a60

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

This PR includes changesets to release 0 packages

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

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

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

@vercel

vercelBot commented May 31, 2026

Copy link
Copy Markdown
Contributor

@github-actions

github-actionsBot commented May 31, 2026

Copy link
Copy Markdown
Contributor

🧪 E2E Test Results

Some tests failed

Summary

PassedFailedSkippedTotal
❌ ▲ Vercel Production126332191485
❌ 💻 Local Development167012191890
✅ 📦 Local Production167102191890
✅ 🐘 Local Postgres167102191890
✅ 🪟 Windows13500135
❌ 📋 Other7681176945
Total7178510528235

❌ Failed Tests

▲ Vercel Production (3 failed)

express (1 failed):

  • instanceMethodStepWorkflow - instance methods with "use step" directive | wrun_01KSZ4H8N0DE044HA3WQ2AG25H | 🔍 observability

nextjs-webpack (2 failed):

  • AbortController abortHookOrderingWorkflow [listener-first-abort-first]: addEventListener → hook.then → abort() → resumeHook
  • AbortController abortHookOrderingWorkflow [listener-first-hook-first]: addEventListener → hook.then → resumeHook → abort()
💻 Local Development (1 failed)

express-stable (1 failed):

  • hookWithSleepFinalStepWorkflow - step only on final payload | wrun_01KSZ4NB8SC1XKHH9GSXQEKXZR
📋 Other (1 failed)

e2e-vercel-prod-tanstack-start (1 failed):

  • AbortController abortHookOrderingWorkflow [listener-first-abort-first]: addEventListener → hook.then → abort() → resumeHook

Details by Category

❌ ▲ Vercel Production
AppPassedFailedSkipped
✅ astro109026
✅ example109026
❌ express108126
✅ fastify109026
✅ hono109026
✅ nextjs-turbopack13302
❌ nextjs-webpack13122
✅ nitro109026
✅ nuxt109026
✅ sveltekit12807
✅ vite109026
❌ 💻 Local Development
AppPassedFailedSkipped
✅ astro-stable110025
❌ express-stable109125
✅ fastify-stable110025
✅ hono-stable110025
✅ nextjs-turbopack-canary116019
✅ nextjs-turbopack-stable-lazy-discovery-disabled13500
✅ nextjs-turbopack-stable-lazy-discovery-enabled13500
✅ nextjs-webpack-canary116019
✅ nextjs-webpack-stable-lazy-discovery-disabled13500
✅ nextjs-webpack-stable-lazy-discovery-enabled13500
✅ nitro-stable110025
✅ nuxt-stable110025
✅ sveltekit-stable12906
✅ vite-stable110025
✅ 📦 Local Production
AppPassedFailedSkipped
✅ astro-stable110025
✅ express-stable110025
✅ fastify-stable110025
✅ hono-stable110025
✅ nextjs-turbopack-canary116019
✅ nextjs-turbopack-stable-lazy-discovery-disabled13500
✅ nextjs-turbopack-stable-lazy-discovery-enabled13500
✅ nextjs-webpack-canary116019
✅ nextjs-webpack-stable-lazy-discovery-disabled13500
✅ nextjs-webpack-stable-lazy-discovery-enabled13500
✅ nitro-stable110025
✅ nuxt-stable110025
✅ sveltekit-stable12906
✅ vite-stable110025
✅ 🐘 Local Postgres
AppPassedFailedSkipped
✅ astro-stable110025
✅ express-stable110025
✅ fastify-stable110025
✅ hono-stable110025
✅ nextjs-turbopack-canary116019
✅ nextjs-turbopack-stable-lazy-discovery-disabled13500
✅ nextjs-turbopack-stable-lazy-discovery-enabled13500
✅ nextjs-webpack-canary116019
✅ nextjs-webpack-stable-lazy-discovery-disabled13500
✅ nextjs-webpack-stable-lazy-discovery-enabled13500
✅ nitro-stable110025
✅ nuxt-stable110025
✅ sveltekit-stable12906
✅ vite-stable110025
✅ 🪟 Windows
AppPassedFailedSkipped
✅ nextjs-turbopack13500
❌ 📋 Other
AppPassedFailedSkipped
✅ e2e-local-dev-nest-stable110025
✅ e2e-local-dev-tanstack-start-110025
✅ e2e-local-postgres-nest-stable110025
✅ e2e-local-postgres-tanstack-start-110025
✅ e2e-local-prod-nest-stable110025
✅ e2e-local-prod-tanstack-start-110025
❌ e2e-vercel-prod-tanstack-start108126

📋 View full workflow run


Some E2E test jobs failed:

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

Check the workflow run for details.

@github-actions

github-actionsBot commented May 31, 2026

Copy link
Copy Markdown
Contributor

📊 Benchmark Results

📈 Comparing against baseline from main branch. Green 🟢 = faster, Red 🔺 = slower.

workflow with no steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Express0.042s (-5.9% 🟢)1.006s (~)0.964s101.00x
💻 LocalNitro0.045s (+5.3% 🔺)1.006s (~)0.961s101.09x
💻 LocalNext.js (Turbopack)0.059s1.007s0.947s101.42x
🐘 PostgresExpress0.060s (+2.8%)1.012s (~)0.952s101.43x
🐘 PostgresNitro0.062s (-35.2% 🟢)1.012s (-2.9%)0.951s101.48x
🐘 PostgresNext.js (Turbopack)0.071s1.013s0.941s101.71x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express0.304s (+29.2% 🔺)9.230s (+332.2% 🔺)8.926s101.00x
▲ VercelNitro0.467s (+14.0% 🔺)8.212s (+227.3% 🔺)7.745s101.54x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

workflow with 1 step

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Nitro1.090s (-3.6%)2.007s (~)0.917s101.00x
💻 LocalExpress1.094s (-2.8%)2.006s (~)0.912s101.00x
🐘 PostgresNitro1.100s (-3.5%)2.008s (~)0.909s101.01x
🐘 PostgresExpress1.108s (-3.4%)2.011s (~)0.903s101.02x
💻 LocalNext.js (Turbopack)1.137s2.006s0.869s101.04x
🐘 PostgresNext.js (Turbopack)1.154s2.011s0.856s101.06x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro1.951s (-49.9% 🟢)8.918s (+50.9% 🔺)6.967s101.00x
▲ VercelExpress2.816s (+50.2% 🔺)11.043s (+190.0% 🔺)8.227s101.44x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

workflow with 10 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Express10.509s (-3.8%)11.022s (~)0.513s31.00x
🐘 PostgresExpress10.527s (-4.0%)11.018s (~)0.490s31.00x
🐘 PostgresNitro10.543s (-3.0%)11.018s (~)0.475s31.00x
💻 LocalNitro10.549s (-3.6%)11.023s (~)0.475s31.00x
💻 LocalNext.js (Turbopack)10.771s11.022s0.251s31.02x
🐘 PostgresNext.js (Turbopack)10.864s11.019s0.155s31.03x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro13.250s (-44.2% 🟢)17.759s (-29.3% 🟢)4.509s31.00x
▲ VercelExpress18.536s (+9.2% 🔺)25.082s (+25.3% 🔺)6.546s21.40x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

workflow with 25 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro13.713s (-6.0% 🟢)14.018s (-6.7% 🟢)0.304s51.00x
💻 LocalExpress13.737s (-8.2% 🟢)14.027s (-6.7% 🟢)0.290s51.00x
🐘 PostgresExpress13.748s (-5.7% 🟢)14.016s (-6.7% 🟢)0.268s51.00x
💻 LocalNitro13.768s (-8.6% 🟢)14.027s (-12.5% 🟢)0.260s51.00x
💻 LocalNext.js (Turbopack)14.375s15.031s0.656s41.05x
🐘 PostgresNext.js (Turbopack)14.516s15.019s0.503s41.06x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro22.401s (-65.2% 🟢)41.317s (-38.0% 🟢)18.916s21.00x
▲ VercelExpress22.701s (-54.9% 🟢)31.002s (-41.0% 🟢)8.301s21.01x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

workflow with 50 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro12.332s (-11.7% 🟢)13.018s (-9.0% 🟢)0.687s71.00x
🐘 PostgresExpress12.367s (-11.7% 🟢)13.017s (-10.8% 🟢)0.649s71.00x
💻 LocalExpress12.445s (-25.0% 🟢)13.025s (-23.5% 🟢)0.580s71.01x
💻 LocalNitro12.686s (-24.4% 🟢)13.168s (-22.7% 🟢)0.482s71.03x
💻 LocalNext.js (Turbopack)13.628s14.028s0.400s71.11x
🐘 PostgresNext.js (Turbopack)13.797s14.164s0.367s71.12x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express27.762s (-77.1% 🟢)31.197s (-74.8% 🟢)3.435s31.00x
▲ VercelNitro28.303s (-93.3% 🟢)36.682s (-91.4% 🟢)8.379s31.02x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

Promise.all with 10 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express1.186s (-5.9% 🟢)2.008s (~)0.822s151.00x
💻 LocalExpress1.198s (-19.6% 🟢)2.006s (~)0.808s151.01x
💻 LocalNitro1.206s (-26.1% 🟢)2.007s (-3.2%)0.800s151.02x
🐘 PostgresNitro1.214s (-4.8%)2.007s (~)0.794s151.02x
🐘 PostgresNext.js (Turbopack)1.258s2.007s0.750s151.06x
💻 LocalNext.js (Turbopack)1.347s2.005s0.659s151.14x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express2.716s (-5.0% 🟢)19.336s (+318.3% 🔺)16.620s21.00x
▲ VercelNitro2.825s (~)9.853s (+127.9% 🔺)7.027s41.04x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

Promise.all with 25 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express1.236s (-47.7% 🟢)2.008s (-33.3% 🟢)0.772s151.00x
🐘 PostgresNitro1.255s (-46.6% 🟢)2.007s (-33.3% 🟢)0.752s151.02x
🐘 PostgresNext.js (Turbopack)1.428s2.008s0.579s151.16x
💻 LocalNext.js (Turbopack)1.687s2.074s0.387s151.36x
💻 LocalExpress1.717s (-41.9% 🟢)2.006s (-41.9% 🟢)0.289s151.39x
💻 LocalNitro2.000s (-36.4% 🟢)2.365s (-39.1% 🟢)0.365s141.62x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro3.186s (-21.4% 🟢)11.331s (+91.4% 🔺)8.145s31.00x
▲ VercelExpress6.602s (+82.4% 🔺)18.243s (+257.0% 🔺)11.642s32.07x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

Promise.all with 50 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express1.383s (-60.3% 🟢)2.007s (-50.0% 🟢)0.624s151.00x
🐘 PostgresNitro1.398s (-59.8% 🟢)2.007s (-49.9% 🟢)0.609s151.01x
🐘 PostgresNext.js (Turbopack)1.735s2.315s0.580s131.25x
💻 LocalNext.js (Turbopack)4.602s5.298s0.696s73.33x
💻 LocalExpress4.827s (-42.1% 🟢)5.514s (-38.9% 🟢)0.687s63.49x
💻 LocalNitro6.170s (-26.1% 🟢)6.617s (-26.6% 🟢)0.447s54.46x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express5.289s (+24.7% 🔺)7.700s (+25.7% 🔺)2.411s41.00x
▲ VercelNitro5.461s (+54.9% 🔺)11.366s (+105.4% 🔺)5.905s31.03x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

Promise.race with 10 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.178s (-6.3% 🟢)2.009s (~)0.831s151.00x
🐘 PostgresExpress1.193s (-5.1% 🟢)2.008s (~)0.815s151.01x
🐘 PostgresNext.js (Turbopack)1.249s2.009s0.760s151.06x
💻 LocalNext.js (Turbopack)1.407s2.006s0.599s151.19x
💻 LocalExpress1.456s (-23.1% 🟢)2.007s (-15.1% 🟢)0.551s151.24x
💻 LocalNitro1.681s (-9.9% 🟢)2.073s (-11.4% 🟢)0.392s151.43x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express2.482s (-3.8%)8.298s (+90.8% 🔺)5.816s41.00x
▲ VercelNitro2.653s (+7.9% 🔺)5.245s (+25.8% 🔺)2.592s61.07x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

Promise.race with 25 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.242s (-46.9% 🟢)2.009s (-33.3% 🟢)0.767s151.00x
🐘 PostgresExpress1.261s (-46.1% 🟢)2.010s (-33.3% 🟢)0.748s151.02x
🐘 PostgresNext.js (Turbopack)1.403s2.008s0.605s151.13x
💻 LocalExpress1.970s (-37.1% 🟢)2.392s (-36.4% 🟢)0.423s131.59x
💻 LocalNext.js (Turbopack)2.017s2.591s0.574s121.62x
💻 LocalNitro2.086s (-31.9% 🟢)2.591s (-33.3% 🟢)0.505s121.68x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro3.436s (+6.3% 🔺)10.457s (+106.0% 🔺)7.020s31.00x
▲ VercelExpress3.725s (+16.7% 🔺)8.451s (+76.3% 🔺)4.726s41.08x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

Promise.race with 50 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.382s (-60.3% 🟢)2.008s (-49.9% 🟢)0.626s151.00x
🐘 PostgresExpress1.385s (-60.4% 🟢)2.008s (-49.9% 🟢)0.622s151.00x
🐘 PostgresNext.js (Turbopack)1.746s2.156s0.411s141.26x
💻 LocalExpress4.650s (-47.2% 🟢)5.180s (-44.1% 🟢)0.530s63.36x
💻 LocalNext.js (Turbopack)5.127s5.683s0.557s63.71x
💻 LocalNitro5.886s (-35.6% 🟢)6.413s (-36.0% 🟢)0.527s54.26x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro6.106s (+19.9% 🔺)10.232s (+50.1% 🔺)4.125s51.00x
▲ VercelExpress10.634s (+65.7% 🔺)15.236s (+86.3% 🔺)4.602s21.74x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

workflow with 10 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express0.565s (-32.6% 🟢)1.007s (-1.6%)0.442s601.00x
💻 LocalExpress0.578s (-41.3% 🟢)1.005s (-6.6% 🟢)0.427s601.02x
🐘 PostgresNitro0.593s (-27.7% 🟢)1.040s (+3.4%)0.447s591.05x
💻 LocalNitro0.697s (-29.0% 🟢)1.096s (~)0.399s551.23x
🐘 PostgresNext.js (Turbopack)0.837s1.007s0.170s601.48x
💻 LocalNext.js (Turbopack)0.868s1.004s0.136s601.54x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro4.851s (-78.0% 🟢)7.522s (-68.7% 🟢)2.672s81.00x
▲ VercelExpress4.974s (-73.8% 🟢)12.581s (-41.0% 🟢)7.606s61.03x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

workflow with 25 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express1.325s (-33.0% 🟢)2.008s (-11.1% 🟢)0.682s451.00x
🐘 PostgresNitro1.351s (-29.9% 🟢)2.030s (-3.4%)0.679s451.02x
💻 LocalNitro1.510s (-50.3% 🟢)2.006s (-46.6% 🟢)0.497s451.14x
💻 LocalExpress1.515s (-49.8% 🟢)2.006s (-44.1% 🟢)0.491s451.14x
🐘 PostgresNext.js (Turbopack)2.084s2.468s0.384s371.57x
💻 LocalNext.js (Turbopack)2.112s3.008s0.896s301.59x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express12.360s (-64.2% 🟢)17.479s (-52.5% 🟢)5.119s61.00x
▲ VercelNitro12.401s (-68.6% 🟢)15.005s (-63.7% 🟢)2.605s71.00x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

workflow with 50 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro2.594s (-36.8% 🟢)3.033s (-34.1% 🟢)0.439s401.00x
🐘 PostgresExpress2.702s (-32.3% 🟢)3.137s (-28.2% 🟢)0.434s391.04x
💻 LocalNitro3.229s (-65.3% 🟢)4.009s (-60.0% 🟢)0.780s301.24x
💻 LocalExpress3.324s (-63.9% 🟢)4.043s (-59.6% 🟢)0.719s301.28x
🐘 PostgresNext.js (Turbopack)3.925s4.010s0.085s301.51x
💻 LocalNext.js (Turbopack)4.452s5.052s0.601s241.72x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro25.276s (-73.9% 🟢)30.878s (-68.6% 🟢)5.602s41.00x
▲ VercelExpress26.350s (-79.7% 🟢)32.626s (-75.3% 🟢)6.276s41.04x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

workflow with 10 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.217s (-23.3% 🟢)1.006s (~)0.788s601.00x
🐘 PostgresExpress0.227s (-19.6% 🟢)1.006s (~)0.779s601.05x
🐘 PostgresNext.js (Turbopack)0.305s1.023s0.719s591.40x
💻 LocalNitro0.424s (-29.9% 🟢)1.004s (-1.7%)0.581s601.95x
💻 LocalExpress0.441s (-21.3% 🟢)1.004s (~)0.563s602.03x
💻 LocalNext.js (Turbopack)0.627s1.022s0.395s592.89x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express2.394s (+22.5% 🔺)12.031s (+230.8% 🔺)9.638s51.00x
▲ VercelNitro3.625s (+118.3% 🔺)10.359s (+209.1% 🔺)6.733s61.51x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

workflow with 25 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.339s (-31.7% 🟢)1.006s (~)0.668s901.00x
🐘 PostgresExpress0.361s (-29.1% 🟢)1.006s (~)0.645s901.07x
🐘 PostgresNext.js (Turbopack)0.515s1.007s0.492s901.52x
💻 LocalNitro2.152s (-15.2% 🟢)2.638s (-12.3% 🟢)0.486s356.35x
💻 LocalExpress2.471s (-1.7%)2.979s (-1.0%)0.508s317.29x
💻 LocalNext.js (Turbopack)2.513s3.225s0.712s287.42x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro4.568s (+41.6% 🔺)10.630s (+120.5% 🔺)6.062s91.00x
▲ VercelExpress5.640s (+85.1% 🔺)10.451s (+117.4% 🔺)4.811s101.23x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

workflow with 50 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.683s (-13.6% 🟢)1.006s (~)0.323s1201.00x
🐘 PostgresExpress0.705s (-13.9% 🟢)1.015s (~)0.310s1191.03x
🐘 PostgresNext.js (Turbopack)1.048s1.960s0.912s621.53x
💻 LocalNitro9.742s (-12.9% 🟢)10.277s (-11.9% 🟢)0.534s1214.27x
💻 LocalNext.js (Turbopack)10.810s11.575s0.766s1115.83x
💻 LocalExpress11.232s (~)11.856s (-0.7%)0.624s1116.45x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express13.763s (+85.5% 🔺)17.466s (+88.9% 🔺)3.702s71.00x
▲ VercelNitro15.302s (+98.1% 🔺)21.654s (+130.4% 🔺)6.352s61.11x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

Stream Benchmarks(includes TTFB metrics)
workflow with stream

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.156s (+463.8% 🔺)2.000s (+100.1% 🔺)0.001s (-6.7% 🟢)2.010s (+98.8% 🔺)0.855s101.00x
💻 LocalExpress1.163s (+484.4% 🔺)2.005s (+99.6% 🔺)0.011s (-13.2% 🟢)2.018s (+98.2% 🔺)0.854s101.01x
💻 LocalNitro1.165s (+445.3% 🔺)2.005s (+99.6% 🔺)0.012s (-0.8%)2.020s (+98.2% 🔺)0.854s101.01x
🐘 PostgresExpress1.169s (+469.8% 🔺)1.995s (+99.8% 🔺)0.001s (-31.3% 🟢)2.010s (+98.7% 🔺)0.841s101.01x
💻 LocalNext.js (Turbopack)1.214s2.003s0.011s2.017s0.804s101.05x
🐘 PostgresNext.js (Turbopack)1.233s2.003s0.001s2.012s0.779s101.07x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express2.318s (-7.5% 🟢)6.376s (+55.9% 🔺)1.539s (+60.1% 🔺)8.459s (+51.3% 🔺)6.140s101.00x
▲ VercelNitro3.129s (-18.4% 🟢)6.747s (+27.9% 🔺)1.486s (+100.3% 🔺)9.559s (+47.4% 🔺)6.431s101.35x
▲ VercelNext.js (Turbopack)⚠️missing-----

🔍 Observability: Express | Nitro

stream pipeline with 5 transform steps (1MB)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Nitro1.584s (+88.9% 🔺)2.010s (+98.6% 🔺)0.011s (+14.5% 🔺)2.022s (+81.2% 🔺)0.438s301.00x
🐘 PostgresNitro1.588s (+154.4% 🔺)2.007s (+99.4% 🔺)0.004s (-9.7% 🟢)2.026s (+98.1% 🔺)0.438s301.00x
🐘 PostgresExpress1.621s (+157.3% 🔺)2.001s (+98.8% 🔺)0.004s (~)2.027s (+98.1% 🔺)0.406s301.02x
💻 LocalExpress1.722s (+127.5% 🔺)2.043s (+98.6% 🔺)0.013s (+36.7% 🔺)2.059s (+98.0% 🔺)0.336s301.09x
🐘 PostgresNext.js (Turbopack)1.809s2.011s0.004s2.029s0.220s301.14x
💻 LocalNext.js (Turbopack)1.917s2.008s0.010s2.201s0.284s281.21x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express6.501s (~)13.670s (+70.7% 🔺)0.154s (-62.3% 🟢)14.972s (+69.5% 🔺)8.471s51.00x
▲ VercelNitro7.642s (-74.0% 🟢)7.694s (-75.0% 🟢)0.328s (+192.9% 🔺)10.227s (-67.8% 🟢)2.585s61.18x
▲ VercelNext.js (Turbopack)⚠️missing-----

🔍 Observability: Express | Nitro

10 parallel streams (1MB each)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express0.699s (-27.3% 🟢)1.012s (-20.8% 🟢)0.000s (-22.0% 🟢)1.027s (-21.4% 🟢)0.328s591.00x
🐘 PostgresNitro0.704s (-27.3% 🟢)1.015s (-18.6% 🟢)0.000s (+22.0% 🔺)1.032s (-18.0% 🟢)0.328s591.01x
🐘 PostgresNext.js (Turbopack)0.835s1.091s0.000s1.099s0.264s551.19x
💻 LocalNitro1.375s (+12.5% 🔺)2.013s (~)0.000s (+100.0% 🔺)2.015s (~)0.640s301.97x
💻 LocalNext.js (Turbopack)1.497s2.013s0.001s2.016s0.520s302.14x
💻 LocalExpress1.602s (+30.8% 🔺)2.018s (~)0.000s (-40.0% 🟢)2.020s (~)0.418s302.29x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro3.997s (+31.0% 🔺)8.575s (+95.2% 🔺)0.000s (-100.0% 🟢)9.792s (+103.6% 🔺)5.796s71.00x
▲ VercelExpress5.270s (+40.9% 🔺)8.952s (+75.4% 🔺)0.001s (+358.3% 🔺)10.718s (+93.8% 🔺)5.448s61.32x
▲ VercelNext.js (Turbopack)⚠️missing-----

🔍 Observability: Nitro | Express

fan-out fan-in 10 streams (1MB each)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.409s (-21.3% 🟢)2.142s (~)0.000s (-100.0% 🟢)2.154s (-0.9%)0.745s281.00x
🐘 PostgresExpress1.513s (-14.6% 🟢)2.174s (~)0.000s (+Infinity% 🔺)2.189s (~)0.677s281.07x
🐘 PostgresNext.js (Turbopack)1.650s2.145s0.000s2.162s0.512s281.17x
💻 LocalNitro3.097s (-8.6% 🟢)3.775s (-6.4% 🟢)0.001s (+40.6% 🔺)3.777s (-6.4% 🟢)0.681s162.20x
💻 LocalNext.js (Turbopack)3.186s3.674s0.000s3.678s0.492s172.26x
💻 LocalExpress3.351s (-3.4%)4.028s (~)0.001s (+41.7% 🔺)4.032s (~)0.681s152.38x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express5.775s (+25.9% 🔺)12.656s (+110.2% 🔺)0.001s (+Infinity% 🔺)15.088s (+133.7% 🔺)9.313s41.00x
▲ VercelNitro5.828s (+42.4% 🔺)17.093s (+218.1% 🔺)0.000s (-100.0% 🟢)17.759s (+206.5% 🔺)11.931s41.01x
▲ VercelNext.js (Turbopack)⚠️missing-----

🔍 Observability: Express | Nitro

Summary

Fastest Framework by World

Winner determined by most benchmark wins

World🥇 Fastest FrameworkWins
💻 LocalExpress9/21
🐘 PostgresNitro13/21
▲ VercelExpress11/21
Fastest World by Framework

Winner determined by most benchmark wins

Framework🥇 Fastest WorldWins
Express🐘 Postgres16/21
Next.js (Turbopack)🐘 Postgres15/21
Nitro🐘 Postgres17/21
Column Definitions
  • Workflow Time: Runtime reported by workflow (completedAt - createdAt) - primary metric
  • TTFB: Time to First Byte - time from workflow start until first stream byte received (stream benchmarks only)
  • Slurp: Time from first byte to complete stream consumption (stream benchmarks only)
  • Wall Time: Total testbench time (trigger workflow + poll for result)
  • Overhead: Testbench overhead (Wall Time - Workflow Time)
  • Samples: Number of benchmark iterations run
  • vs Fastest: How much slower compared to the fastest configuration for this benchmark

Worlds:

  • 💻 Local: In-memory filesystem world (local development)
  • 🐘 Postgres: PostgreSQL database world (local development)
  • ▲ Vercel: Vercel production/preview deployment
  • 🌐 Turso: Community world (local development)
  • 🌐 MongoDB: Community world (local development)
  • 🌐 Redis: Community world (local development)
  • 🌐 Jazz: Community world (local development)
  • 🌐 Redis: Community world (local development)
  • 🌐 Redis + BullMQ: Community world (local development)
  • 🌐 Cloudflare: Community world (local development)
  • 🌐 MySQL: Community world (local development)
  • 🌐 Azure: Community world (local development)
  • 🌐 NATS JetStream: Community world (local development)
  • 🌐 Upstash: Community world (local development)

📋 View full workflow run


Some benchmark jobs failed:

  • Local: success
  • Postgres: success
  • Vercel: failure

Check the workflow run for details.

@VaguelySerious
VaguelySerious marked this pull request as ready for review June 1, 2026 09:06
@VaguelySerious
VaguelySerious requested a review from a team as a code ownerJune 1, 2026 09:06
@VaguelySerious
VaguelySerious merged commit ae3c833 into mainJun 1, 2026
112 of 122 checks passed
@VaguelySerious
VaguelySerious deleted the peter/event-log-race-repro-classify-infra branch June 1, 2026 09:07
VaguelySerious added a commit that referenced this pull request Jun 1, 2026
(cherry picked from commit ae3c833)
(cherry picked from commit c1d7bab)
pranaygp added a commit that referenced this pull request Jun 2, 2026
* origin/main:
[world-vercel] Retry transient response-body parse failures in the HTTP client (#2204)
Add virtualization to the trace viewer (#2205)
Trace viewer: scroll-load events past an auto-load cap (#2200)
fix(core): resolve forwarded stream keys across deployments (#2191)
[e2e] Improve error labeling in event-log-race-repro CI job (#2190)
[core] Harden event pagination response parsing (#2180) (#2179)
Add loading skeleton to the new trace viewer (#2164)
Add tooltip components + apply on up/down detail pane (#2163)
fix(swc-plugin): allow wasm host imports during link (#2174)
[test] Forward-port reused-sleep replay divergence test (#2172)
[e2e] Add `event-log-race-repro` label for triggering CI stress-test (#2159)
Version Packages (beta) (#2162)
fix(world-local): skip Nov 2025 ghost versions on npm (#2168)
fix(core,errors): classify SDK encryption failures as RUNTIME_ERROR (#2145)
[web-shared][web] Fix events tab search (#2107)
Version Packages (beta) (#2147)
Allow setting workflow attributes from steps (#2157)
Better search handling on the trace viewer (#2144)
[docs] Document experimental attributes feature (#2141)
Sign up for freeto 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

@VaguelySerious
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' [e2e] Separate event-log-race-repro harness noise from real regressions by VaguelySerious · Pull Request #2190 · vercel/workflow · GitHub
Skip to content

[e2e] Separate event-log-race-repro harness noise from real regressions - #2190

Merged
VaguelySerious merged 1 commit into
mainfrom
peter/event-log-race-repro-classify-infra
Jun 1, 2026
Merged

[e2e] Separate event-log-race-repro harness noise from real regressions#2190
VaguelySerious merged 1 commit into
mainfrom
peter/event-log-race-repro-classify-infra

Conversation

@VaguelySerious

Copy link
Copy Markdown
Member

Summary

The event-log-race-repro job is currently red for the wrong reason. In a recent run, it reported 1231 of 2000 runs "did not complete cleanly" — yet CORRUPTED_EVENT_LOG / USER_ERROR / RUNTIME_ERROR were all 0. The entire count was harness-side noise.

What the other column was

The repro sorts each run into completed, CORRUPTED_EVENT_LOG, USER_ERROR, RUNTIME_ERROR, stuck, or other. Only the three named error codes mapped to their own bucket; everything else fell into other, and the --check gate failed the job on any non-completed run. So other conflated genuine corruption with:

  • HOOK_RESUME_FAILED — the run completed fine, but the harness's own resumeHook() rejected (typically because the sleep branch already finished the run and disposed the hook).
  • NO_WAKE_BRANCH — the run completed but the sleep branch won every iteration, so the wake path was never taken.
  • transport errors / timeouts thrown in the driver, and cancellations.

What was actually going wrong

A timing race in the test harness, not an SDK bug. The workflow's sleep budget is iterations × sleepMs = 5 × 5000 = 25000ms; the harness resumes the hook at resumeDelayMs + rand(resumeJitterMs) = up to 25000ms — the resume ceiling exactly equals the budget. On a fast/warm deployment the workflow exhausts its sleeps before the resume lands, so the resume hits a disposed hook and/or the wake branch is never taken.

The smoking gun: the #2 retry against the same already-warm deployment jumped 767→1231 other while stuck dropped to 0 and the step scenarios stayed perfect. Faster execution = the resume misses the window more often. It also means most "green" runs weren't even exercising the wake-branch shape the repro is meant to stress.

Changes

  1. Reclassify harness-side, non-corruption outcomes into a dedicated non-gating infra bucket (test + renderer). The job now gates only on regression-class outcomes (CORRUPTED_EVENT_LOG / USER_ERROR / RUNTIME_ERROR / stuck / other); infra is reported but never fails the job. The PR comment now reads "No event-log regressions… N runs hit harness-side infra outcomes (… do not fail the job)."
  2. Surface regressions ahead of infra in the failures table so the 20-row cap never hides a real failure behind a flood of timing rows.
  3. Restore wake-branch coverage: raise the default iterations ceiling (5 → 8). Because the run short-circuits via returnOnWake the moment the hook wins, a higher ceiling widens the window for the resume to land before sleep-budget exhaustion at ~no runtime cost. Added a beforeAll guard that warns when the resume ceiling is not below the sleep budget.
  4. Testability: the renderer's pure helpers are now exported and covered by node:test (run via a new lightweight Lint job).

Tests

node --test .github/scripts/**/*.test.js (8 tests) covers: infra is non-gating; regressionCount ignores completed/infra; an all-infra results file (mirroring the production comment) yields 0 regressions; regressions sort ahead of infra; --check exits 0 on infra-only and 1 on a corruption-class outcome.

Note: the full 2000-run repro only runs against a deployment behind the event-log-race-repro label, so the reclassification's end-to-end effect is best confirmed by adding that label to this PR.

🤖 Generated with Claude Code

The event-log-race-repro job classified every non-completed run into an
`other` grab-bag and gated on it. Hook-resume timing races (HOOK_RESUME_FAILED,
NO_WAKE_BRANCH) and transport errors in the repro driver — none of which are
event-log corruption — landed there and failed the job, drowning the signal it
exists to detect.
- Route harness-side, non-corruption outcomes to a dedicated non-gating `infra`
bucket (test + renderer). The job now gates only on regression-class outcomes
(CORRUPTED_EVENT_LOG / USER_ERROR / RUNTIME_ERROR / stuck / other).
- Sort regressions ahead of infra rows so the 20-row cap never hides a real
failure behind a flood of harness-timing rows.
- Raise the default hook/sleep iteration ceiling (5 -> 8). Because the run
short-circuits via returnOnWake the moment the hook wins, this widens the
window for the delayed resume to land before the sleep budget is exhausted,
at ~no runtime cost — restoring the wake-branch coverage the scenario exists
to exercise. Add a beforeAll guard that warns when the resume ceiling is not
below the sleep budget.
- Make the renderer's pure helpers unit-testable and add node:test coverage,
wired into the Lint workflow.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@changeset-bot

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: e100a60

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

This PR includes changesets to release 0 packages

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

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

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

@vercel

vercelBot commented May 31, 2026

Copy link
Copy Markdown
Contributor

@github-actions

github-actionsBot commented May 31, 2026

Copy link
Copy Markdown
Contributor

🧪 E2E Test Results

Some tests failed

Summary

PassedFailedSkippedTotal
❌ ▲ Vercel Production126332191485
❌ 💻 Local Development167012191890
✅ 📦 Local Production167102191890
✅ 🐘 Local Postgres167102191890
✅ 🪟 Windows13500135
❌ 📋 Other7681176945
Total7178510528235

❌ Failed Tests

▲ Vercel Production (3 failed)

express (1 failed):

  • instanceMethodStepWorkflow - instance methods with "use step" directive | wrun_01KSZ4H8N0DE044HA3WQ2AG25H | 🔍 observability

nextjs-webpack (2 failed):

  • AbortController abortHookOrderingWorkflow [listener-first-abort-first]: addEventListener → hook.then → abort() → resumeHook
  • AbortController abortHookOrderingWorkflow [listener-first-hook-first]: addEventListener → hook.then → resumeHook → abort()
💻 Local Development (1 failed)

express-stable (1 failed):

  • hookWithSleepFinalStepWorkflow - step only on final payload | wrun_01KSZ4NB8SC1XKHH9GSXQEKXZR
📋 Other (1 failed)

e2e-vercel-prod-tanstack-start (1 failed):

  • AbortController abortHookOrderingWorkflow [listener-first-abort-first]: addEventListener → hook.then → abort() → resumeHook

Details by Category

❌ ▲ Vercel Production
AppPassedFailedSkipped
✅ astro109026
✅ example109026
❌ express108126
✅ fastify109026
✅ hono109026
✅ nextjs-turbopack13302
❌ nextjs-webpack13122
✅ nitro109026
✅ nuxt109026
✅ sveltekit12807
✅ vite109026
❌ 💻 Local Development
AppPassedFailedSkipped
✅ astro-stable110025
❌ express-stable109125
✅ fastify-stable110025
✅ hono-stable110025
✅ nextjs-turbopack-canary116019
✅ nextjs-turbopack-stable-lazy-discovery-disabled13500
✅ nextjs-turbopack-stable-lazy-discovery-enabled13500
✅ nextjs-webpack-canary116019
✅ nextjs-webpack-stable-lazy-discovery-disabled13500
✅ nextjs-webpack-stable-lazy-discovery-enabled13500
✅ nitro-stable110025
✅ nuxt-stable110025
✅ sveltekit-stable12906
✅ vite-stable110025
✅ 📦 Local Production
AppPassedFailedSkipped
✅ astro-stable110025
✅ express-stable110025
✅ fastify-stable110025
✅ hono-stable110025
✅ nextjs-turbopack-canary116019
✅ nextjs-turbopack-stable-lazy-discovery-disabled13500
✅ nextjs-turbopack-stable-lazy-discovery-enabled13500
✅ nextjs-webpack-canary116019
✅ nextjs-webpack-stable-lazy-discovery-disabled13500
✅ nextjs-webpack-stable-lazy-discovery-enabled13500
✅ nitro-stable110025
✅ nuxt-stable110025
✅ sveltekit-stable12906
✅ vite-stable110025
✅ 🐘 Local Postgres
AppPassedFailedSkipped
✅ astro-stable110025
✅ express-stable110025
✅ fastify-stable110025
✅ hono-stable110025
✅ nextjs-turbopack-canary116019
✅ nextjs-turbopack-stable-lazy-discovery-disabled13500
✅ nextjs-turbopack-stable-lazy-discovery-enabled13500
✅ nextjs-webpack-canary116019
✅ nextjs-webpack-stable-lazy-discovery-disabled13500
✅ nextjs-webpack-stable-lazy-discovery-enabled13500
✅ nitro-stable110025
✅ nuxt-stable110025
✅ sveltekit-stable12906
✅ vite-stable110025
✅ 🪟 Windows
AppPassedFailedSkipped
✅ nextjs-turbopack13500
❌ 📋 Other
AppPassedFailedSkipped
✅ e2e-local-dev-nest-stable110025
✅ e2e-local-dev-tanstack-start-110025
✅ e2e-local-postgres-nest-stable110025
✅ e2e-local-postgres-tanstack-start-110025
✅ e2e-local-prod-nest-stable110025
✅ e2e-local-prod-tanstack-start-110025
❌ e2e-vercel-prod-tanstack-start108126

📋 View full workflow run


Some E2E test jobs failed:

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

Check the workflow run for details.

@github-actions

github-actionsBot commented May 31, 2026

Copy link
Copy Markdown
Contributor

📊 Benchmark Results

📈 Comparing against baseline from main branch. Green 🟢 = faster, Red 🔺 = slower.

workflow with no steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Express0.042s (-5.9% 🟢)1.006s (~)0.964s101.00x
💻 LocalNitro0.045s (+5.3% 🔺)1.006s (~)0.961s101.09x
💻 LocalNext.js (Turbopack)0.059s1.007s0.947s101.42x
🐘 PostgresExpress0.060s (+2.8%)1.012s (~)0.952s101.43x
🐘 PostgresNitro0.062s (-35.2% 🟢)1.012s (-2.9%)0.951s101.48x
🐘 PostgresNext.js (Turbopack)0.071s1.013s0.941s101.71x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express0.304s (+29.2% 🔺)9.230s (+332.2% 🔺)8.926s101.00x
▲ VercelNitro0.467s (+14.0% 🔺)8.212s (+227.3% 🔺)7.745s101.54x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

workflow with 1 step

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Nitro1.090s (-3.6%)2.007s (~)0.917s101.00x
💻 LocalExpress1.094s (-2.8%)2.006s (~)0.912s101.00x
🐘 PostgresNitro1.100s (-3.5%)2.008s (~)0.909s101.01x
🐘 PostgresExpress1.108s (-3.4%)2.011s (~)0.903s101.02x
💻 LocalNext.js (Turbopack)1.137s2.006s0.869s101.04x
🐘 PostgresNext.js (Turbopack)1.154s2.011s0.856s101.06x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro1.951s (-49.9% 🟢)8.918s (+50.9% 🔺)6.967s101.00x
▲ VercelExpress2.816s (+50.2% 🔺)11.043s (+190.0% 🔺)8.227s101.44x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

workflow with 10 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Express10.509s (-3.8%)11.022s (~)0.513s31.00x
🐘 PostgresExpress10.527s (-4.0%)11.018s (~)0.490s31.00x
🐘 PostgresNitro10.543s (-3.0%)11.018s (~)0.475s31.00x
💻 LocalNitro10.549s (-3.6%)11.023s (~)0.475s31.00x
💻 LocalNext.js (Turbopack)10.771s11.022s0.251s31.02x
🐘 PostgresNext.js (Turbopack)10.864s11.019s0.155s31.03x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro13.250s (-44.2% 🟢)17.759s (-29.3% 🟢)4.509s31.00x
▲ VercelExpress18.536s (+9.2% 🔺)25.082s (+25.3% 🔺)6.546s21.40x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

workflow with 25 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro13.713s (-6.0% 🟢)14.018s (-6.7% 🟢)0.304s51.00x
💻 LocalExpress13.737s (-8.2% 🟢)14.027s (-6.7% 🟢)0.290s51.00x
🐘 PostgresExpress13.748s (-5.7% 🟢)14.016s (-6.7% 🟢)0.268s51.00x
💻 LocalNitro13.768s (-8.6% 🟢)14.027s (-12.5% 🟢)0.260s51.00x
💻 LocalNext.js (Turbopack)14.375s15.031s0.656s41.05x
🐘 PostgresNext.js (Turbopack)14.516s15.019s0.503s41.06x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro22.401s (-65.2% 🟢)41.317s (-38.0% 🟢)18.916s21.00x
▲ VercelExpress22.701s (-54.9% 🟢)31.002s (-41.0% 🟢)8.301s21.01x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

workflow with 50 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro12.332s (-11.7% 🟢)13.018s (-9.0% 🟢)0.687s71.00x
🐘 PostgresExpress12.367s (-11.7% 🟢)13.017s (-10.8% 🟢)0.649s71.00x
💻 LocalExpress12.445s (-25.0% 🟢)13.025s (-23.5% 🟢)0.580s71.01x
💻 LocalNitro12.686s (-24.4% 🟢)13.168s (-22.7% 🟢)0.482s71.03x
💻 LocalNext.js (Turbopack)13.628s14.028s0.400s71.11x
🐘 PostgresNext.js (Turbopack)13.797s14.164s0.367s71.12x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express27.762s (-77.1% 🟢)31.197s (-74.8% 🟢)3.435s31.00x
▲ VercelNitro28.303s (-93.3% 🟢)36.682s (-91.4% 🟢)8.379s31.02x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

Promise.all with 10 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express1.186s (-5.9% 🟢)2.008s (~)0.822s151.00x
💻 LocalExpress1.198s (-19.6% 🟢)2.006s (~)0.808s151.01x
💻 LocalNitro1.206s (-26.1% 🟢)2.007s (-3.2%)0.800s151.02x
🐘 PostgresNitro1.214s (-4.8%)2.007s (~)0.794s151.02x
🐘 PostgresNext.js (Turbopack)1.258s2.007s0.750s151.06x
💻 LocalNext.js (Turbopack)1.347s2.005s0.659s151.14x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express2.716s (-5.0% 🟢)19.336s (+318.3% 🔺)16.620s21.00x
▲ VercelNitro2.825s (~)9.853s (+127.9% 🔺)7.027s41.04x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

Promise.all with 25 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express1.236s (-47.7% 🟢)2.008s (-33.3% 🟢)0.772s151.00x
🐘 PostgresNitro1.255s (-46.6% 🟢)2.007s (-33.3% 🟢)0.752s151.02x
🐘 PostgresNext.js (Turbopack)1.428s2.008s0.579s151.16x
💻 LocalNext.js (Turbopack)1.687s2.074s0.387s151.36x
💻 LocalExpress1.717s (-41.9% 🟢)2.006s (-41.9% 🟢)0.289s151.39x
💻 LocalNitro2.000s (-36.4% 🟢)2.365s (-39.1% 🟢)0.365s141.62x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro3.186s (-21.4% 🟢)11.331s (+91.4% 🔺)8.145s31.00x
▲ VercelExpress6.602s (+82.4% 🔺)18.243s (+257.0% 🔺)11.642s32.07x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

Promise.all with 50 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express1.383s (-60.3% 🟢)2.007s (-50.0% 🟢)0.624s151.00x
🐘 PostgresNitro1.398s (-59.8% 🟢)2.007s (-49.9% 🟢)0.609s151.01x
🐘 PostgresNext.js (Turbopack)1.735s2.315s0.580s131.25x
💻 LocalNext.js (Turbopack)4.602s5.298s0.696s73.33x
💻 LocalExpress4.827s (-42.1% 🟢)5.514s (-38.9% 🟢)0.687s63.49x
💻 LocalNitro6.170s (-26.1% 🟢)6.617s (-26.6% 🟢)0.447s54.46x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express5.289s (+24.7% 🔺)7.700s (+25.7% 🔺)2.411s41.00x
▲ VercelNitro5.461s (+54.9% 🔺)11.366s (+105.4% 🔺)5.905s31.03x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

Promise.race with 10 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.178s (-6.3% 🟢)2.009s (~)0.831s151.00x
🐘 PostgresExpress1.193s (-5.1% 🟢)2.008s (~)0.815s151.01x
🐘 PostgresNext.js (Turbopack)1.249s2.009s0.760s151.06x
💻 LocalNext.js (Turbopack)1.407s2.006s0.599s151.19x
💻 LocalExpress1.456s (-23.1% 🟢)2.007s (-15.1% 🟢)0.551s151.24x
💻 LocalNitro1.681s (-9.9% 🟢)2.073s (-11.4% 🟢)0.392s151.43x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express2.482s (-3.8%)8.298s (+90.8% 🔺)5.816s41.00x
▲ VercelNitro2.653s (+7.9% 🔺)5.245s (+25.8% 🔺)2.592s61.07x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

Promise.race with 25 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.242s (-46.9% 🟢)2.009s (-33.3% 🟢)0.767s151.00x
🐘 PostgresExpress1.261s (-46.1% 🟢)2.010s (-33.3% 🟢)0.748s151.02x
🐘 PostgresNext.js (Turbopack)1.403s2.008s0.605s151.13x
💻 LocalExpress1.970s (-37.1% 🟢)2.392s (-36.4% 🟢)0.423s131.59x
💻 LocalNext.js (Turbopack)2.017s2.591s0.574s121.62x
💻 LocalNitro2.086s (-31.9% 🟢)2.591s (-33.3% 🟢)0.505s121.68x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro3.436s (+6.3% 🔺)10.457s (+106.0% 🔺)7.020s31.00x
▲ VercelExpress3.725s (+16.7% 🔺)8.451s (+76.3% 🔺)4.726s41.08x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

Promise.race with 50 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.382s (-60.3% 🟢)2.008s (-49.9% 🟢)0.626s151.00x
🐘 PostgresExpress1.385s (-60.4% 🟢)2.008s (-49.9% 🟢)0.622s151.00x
🐘 PostgresNext.js (Turbopack)1.746s2.156s0.411s141.26x
💻 LocalExpress4.650s (-47.2% 🟢)5.180s (-44.1% 🟢)0.530s63.36x
💻 LocalNext.js (Turbopack)5.127s5.683s0.557s63.71x
💻 LocalNitro5.886s (-35.6% 🟢)6.413s (-36.0% 🟢)0.527s54.26x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro6.106s (+19.9% 🔺)10.232s (+50.1% 🔺)4.125s51.00x
▲ VercelExpress10.634s (+65.7% 🔺)15.236s (+86.3% 🔺)4.602s21.74x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

workflow with 10 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express0.565s (-32.6% 🟢)1.007s (-1.6%)0.442s601.00x
💻 LocalExpress0.578s (-41.3% 🟢)1.005s (-6.6% 🟢)0.427s601.02x
🐘 PostgresNitro0.593s (-27.7% 🟢)1.040s (+3.4%)0.447s591.05x
💻 LocalNitro0.697s (-29.0% 🟢)1.096s (~)0.399s551.23x
🐘 PostgresNext.js (Turbopack)0.837s1.007s0.170s601.48x
💻 LocalNext.js (Turbopack)0.868s1.004s0.136s601.54x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro4.851s (-78.0% 🟢)7.522s (-68.7% 🟢)2.672s81.00x
▲ VercelExpress4.974s (-73.8% 🟢)12.581s (-41.0% 🟢)7.606s61.03x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

workflow with 25 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express1.325s (-33.0% 🟢)2.008s (-11.1% 🟢)0.682s451.00x
🐘 PostgresNitro1.351s (-29.9% 🟢)2.030s (-3.4%)0.679s451.02x
💻 LocalNitro1.510s (-50.3% 🟢)2.006s (-46.6% 🟢)0.497s451.14x
💻 LocalExpress1.515s (-49.8% 🟢)2.006s (-44.1% 🟢)0.491s451.14x
🐘 PostgresNext.js (Turbopack)2.084s2.468s0.384s371.57x
💻 LocalNext.js (Turbopack)2.112s3.008s0.896s301.59x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express12.360s (-64.2% 🟢)17.479s (-52.5% 🟢)5.119s61.00x
▲ VercelNitro12.401s (-68.6% 🟢)15.005s (-63.7% 🟢)2.605s71.00x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

workflow with 50 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro2.594s (-36.8% 🟢)3.033s (-34.1% 🟢)0.439s401.00x
🐘 PostgresExpress2.702s (-32.3% 🟢)3.137s (-28.2% 🟢)0.434s391.04x
💻 LocalNitro3.229s (-65.3% 🟢)4.009s (-60.0% 🟢)0.780s301.24x
💻 LocalExpress3.324s (-63.9% 🟢)4.043s (-59.6% 🟢)0.719s301.28x
🐘 PostgresNext.js (Turbopack)3.925s4.010s0.085s301.51x
💻 LocalNext.js (Turbopack)4.452s5.052s0.601s241.72x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro25.276s (-73.9% 🟢)30.878s (-68.6% 🟢)5.602s41.00x
▲ VercelExpress26.350s (-79.7% 🟢)32.626s (-75.3% 🟢)6.276s41.04x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

workflow with 10 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.217s (-23.3% 🟢)1.006s (~)0.788s601.00x
🐘 PostgresExpress0.227s (-19.6% 🟢)1.006s (~)0.779s601.05x
🐘 PostgresNext.js (Turbopack)0.305s1.023s0.719s591.40x
💻 LocalNitro0.424s (-29.9% 🟢)1.004s (-1.7%)0.581s601.95x
💻 LocalExpress0.441s (-21.3% 🟢)1.004s (~)0.563s602.03x
💻 LocalNext.js (Turbopack)0.627s1.022s0.395s592.89x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express2.394s (+22.5% 🔺)12.031s (+230.8% 🔺)9.638s51.00x
▲ VercelNitro3.625s (+118.3% 🔺)10.359s (+209.1% 🔺)6.733s61.51x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

workflow with 25 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.339s (-31.7% 🟢)1.006s (~)0.668s901.00x
🐘 PostgresExpress0.361s (-29.1% 🟢)1.006s (~)0.645s901.07x
🐘 PostgresNext.js (Turbopack)0.515s1.007s0.492s901.52x
💻 LocalNitro2.152s (-15.2% 🟢)2.638s (-12.3% 🟢)0.486s356.35x
💻 LocalExpress2.471s (-1.7%)2.979s (-1.0%)0.508s317.29x
💻 LocalNext.js (Turbopack)2.513s3.225s0.712s287.42x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro4.568s (+41.6% 🔺)10.630s (+120.5% 🔺)6.062s91.00x
▲ VercelExpress5.640s (+85.1% 🔺)10.451s (+117.4% 🔺)4.811s101.23x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

workflow with 50 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.683s (-13.6% 🟢)1.006s (~)0.323s1201.00x
🐘 PostgresExpress0.705s (-13.9% 🟢)1.015s (~)0.310s1191.03x
🐘 PostgresNext.js (Turbopack)1.048s1.960s0.912s621.53x
💻 LocalNitro9.742s (-12.9% 🟢)10.277s (-11.9% 🟢)0.534s1214.27x
💻 LocalNext.js (Turbopack)10.810s11.575s0.766s1115.83x
💻 LocalExpress11.232s (~)11.856s (-0.7%)0.624s1116.45x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express13.763s (+85.5% 🔺)17.466s (+88.9% 🔺)3.702s71.00x
▲ VercelNitro15.302s (+98.1% 🔺)21.654s (+130.4% 🔺)6.352s61.11x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

Stream Benchmarks(includes TTFB metrics)
workflow with stream

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.156s (+463.8% 🔺)2.000s (+100.1% 🔺)0.001s (-6.7% 🟢)2.010s (+98.8% 🔺)0.855s101.00x
💻 LocalExpress1.163s (+484.4% 🔺)2.005s (+99.6% 🔺)0.011s (-13.2% 🟢)2.018s (+98.2% 🔺)0.854s101.01x
💻 LocalNitro1.165s (+445.3% 🔺)2.005s (+99.6% 🔺)0.012s (-0.8%)2.020s (+98.2% 🔺)0.854s101.01x
🐘 PostgresExpress1.169s (+469.8% 🔺)1.995s (+99.8% 🔺)0.001s (-31.3% 🟢)2.010s (+98.7% 🔺)0.841s101.01x
💻 LocalNext.js (Turbopack)1.214s2.003s0.011s2.017s0.804s101.05x
🐘 PostgresNext.js (Turbopack)1.233s2.003s0.001s2.012s0.779s101.07x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express2.318s (-7.5% 🟢)6.376s (+55.9% 🔺)1.539s (+60.1% 🔺)8.459s (+51.3% 🔺)6.140s101.00x
▲ VercelNitro3.129s (-18.4% 🟢)6.747s (+27.9% 🔺)1.486s (+100.3% 🔺)9.559s (+47.4% 🔺)6.431s101.35x
▲ VercelNext.js (Turbopack)⚠️missing-----

🔍 Observability: Express | Nitro

stream pipeline with 5 transform steps (1MB)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Nitro1.584s (+88.9% 🔺)2.010s (+98.6% 🔺)0.011s (+14.5% 🔺)2.022s (+81.2% 🔺)0.438s301.00x
🐘 PostgresNitro1.588s (+154.4% 🔺)2.007s (+99.4% 🔺)0.004s (-9.7% 🟢)2.026s (+98.1% 🔺)0.438s301.00x
🐘 PostgresExpress1.621s (+157.3% 🔺)2.001s (+98.8% 🔺)0.004s (~)2.027s (+98.1% 🔺)0.406s301.02x
💻 LocalExpress1.722s (+127.5% 🔺)2.043s (+98.6% 🔺)0.013s (+36.7% 🔺)2.059s (+98.0% 🔺)0.336s301.09x
🐘 PostgresNext.js (Turbopack)1.809s2.011s0.004s2.029s0.220s301.14x
💻 LocalNext.js (Turbopack)1.917s2.008s0.010s2.201s0.284s281.21x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express6.501s (~)13.670s (+70.7% 🔺)0.154s (-62.3% 🟢)14.972s (+69.5% 🔺)8.471s51.00x
▲ VercelNitro7.642s (-74.0% 🟢)7.694s (-75.0% 🟢)0.328s (+192.9% 🔺)10.227s (-67.8% 🟢)2.585s61.18x
▲ VercelNext.js (Turbopack)⚠️missing-----

🔍 Observability: Express | Nitro

10 parallel streams (1MB each)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express0.699s (-27.3% 🟢)1.012s (-20.8% 🟢)0.000s (-22.0% 🟢)1.027s (-21.4% 🟢)0.328s591.00x
🐘 PostgresNitro0.704s (-27.3% 🟢)1.015s (-18.6% 🟢)0.000s (+22.0% 🔺)1.032s (-18.0% 🟢)0.328s591.01x
🐘 PostgresNext.js (Turbopack)0.835s1.091s0.000s1.099s0.264s551.19x
💻 LocalNitro1.375s (+12.5% 🔺)2.013s (~)0.000s (+100.0% 🔺)2.015s (~)0.640s301.97x
💻 LocalNext.js (Turbopack)1.497s2.013s0.001s2.016s0.520s302.14x
💻 LocalExpress1.602s (+30.8% 🔺)2.018s (~)0.000s (-40.0% 🟢)2.020s (~)0.418s302.29x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro3.997s (+31.0% 🔺)8.575s (+95.2% 🔺)0.000s (-100.0% 🟢)9.792s (+103.6% 🔺)5.796s71.00x
▲ VercelExpress5.270s (+40.9% 🔺)8.952s (+75.4% 🔺)0.001s (+358.3% 🔺)10.718s (+93.8% 🔺)5.448s61.32x
▲ VercelNext.js (Turbopack)⚠️missing-----

🔍 Observability: Nitro | Express

fan-out fan-in 10 streams (1MB each)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.409s (-21.3% 🟢)2.142s (~)0.000s (-100.0% 🟢)2.154s (-0.9%)0.745s281.00x
🐘 PostgresExpress1.513s (-14.6% 🟢)2.174s (~)0.000s (+Infinity% 🔺)2.189s (~)0.677s281.07x
🐘 PostgresNext.js (Turbopack)1.650s2.145s0.000s2.162s0.512s281.17x
💻 LocalNitro3.097s (-8.6% 🟢)3.775s (-6.4% 🟢)0.001s (+40.6% 🔺)3.777s (-6.4% 🟢)0.681s162.20x
💻 LocalNext.js (Turbopack)3.186s3.674s0.000s3.678s0.492s172.26x
💻 LocalExpress3.351s (-3.4%)4.028s (~)0.001s (+41.7% 🔺)4.032s (~)0.681s152.38x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express5.775s (+25.9% 🔺)12.656s (+110.2% 🔺)0.001s (+Infinity% 🔺)15.088s (+133.7% 🔺)9.313s41.00x
▲ VercelNitro5.828s (+42.4% 🔺)17.093s (+218.1% 🔺)0.000s (-100.0% 🟢)17.759s (+206.5% 🔺)11.931s41.01x
▲ VercelNext.js (Turbopack)⚠️missing-----

🔍 Observability: Express | Nitro

Summary

Fastest Framework by World

Winner determined by most benchmark wins

World🥇 Fastest FrameworkWins
💻 LocalExpress9/21
🐘 PostgresNitro13/21
▲ VercelExpress11/21
Fastest World by Framework

Winner determined by most benchmark wins

Framework🥇 Fastest WorldWins
Express🐘 Postgres16/21
Next.js (Turbopack)🐘 Postgres15/21
Nitro🐘 Postgres17/21
Column Definitions
  • Workflow Time: Runtime reported by workflow (completedAt - createdAt) - primary metric
  • TTFB: Time to First Byte - time from workflow start until first stream byte received (stream benchmarks only)
  • Slurp: Time from first byte to complete stream consumption (stream benchmarks only)
  • Wall Time: Total testbench time (trigger workflow + poll for result)
  • Overhead: Testbench overhead (Wall Time - Workflow Time)
  • Samples: Number of benchmark iterations run
  • vs Fastest: How much slower compared to the fastest configuration for this benchmark

Worlds:

  • 💻 Local: In-memory filesystem world (local development)
  • 🐘 Postgres: PostgreSQL database world (local development)
  • ▲ Vercel: Vercel production/preview deployment
  • 🌐 Turso: Community world (local development)
  • 🌐 MongoDB: Community world (local development)
  • 🌐 Redis: Community world (local development)
  • 🌐 Jazz: Community world (local development)
  • 🌐 Redis: Community world (local development)
  • 🌐 Redis + BullMQ: Community world (local development)
  • 🌐 Cloudflare: Community world (local development)
  • 🌐 MySQL: Community world (local development)
  • 🌐 Azure: Community world (local development)
  • 🌐 NATS JetStream: Community world (local development)
  • 🌐 Upstash: Community world (local development)

📋 View full workflow run


Some benchmark jobs failed:

  • Local: success
  • Postgres: success
  • Vercel: failure

Check the workflow run for details.

@VaguelySerious
VaguelySerious marked this pull request as ready for review June 1, 2026 09:06
@VaguelySerious
VaguelySerious requested a review from a team as a code ownerJune 1, 2026 09:06
@VaguelySerious
VaguelySerious merged commit ae3c833 into mainJun 1, 2026
112 of 122 checks passed
@VaguelySerious
VaguelySerious deleted the peter/event-log-race-repro-classify-infra branch June 1, 2026 09:07
VaguelySerious added a commit that referenced this pull request Jun 1, 2026
(cherry picked from commit ae3c833)
(cherry picked from commit c1d7bab)
pranaygp added a commit that referenced this pull request Jun 2, 2026
* origin/main:
[world-vercel] Retry transient response-body parse failures in the HTTP client (#2204)
Add virtualization to the trace viewer (#2205)
Trace viewer: scroll-load events past an auto-load cap (#2200)
fix(core): resolve forwarded stream keys across deployments (#2191)
[e2e] Improve error labeling in event-log-race-repro CI job (#2190)
[core] Harden event pagination response parsing (#2180) (#2179)
Add loading skeleton to the new trace viewer (#2164)
Add tooltip components + apply on up/down detail pane (#2163)
fix(swc-plugin): allow wasm host imports during link (#2174)
[test] Forward-port reused-sleep replay divergence test (#2172)
[e2e] Add `event-log-race-repro` label for triggering CI stress-test (#2159)
Version Packages (beta) (#2162)
fix(world-local): skip Nov 2025 ghost versions on npm (#2168)
fix(core,errors): classify SDK encryption failures as RUNTIME_ERROR (#2145)
[web-shared][web] Fix events tab search (#2107)
Version Packages (beta) (#2147)
Allow setting workflow attributes from steps (#2157)
Better search handling on the trace viewer (#2144)
[docs] Document experimental attributes feature (#2141)
Sign up for freeto 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

@VaguelySerious
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' [e2e] Separate event-log-race-repro harness noise from real regressions by VaguelySerious · Pull Request #2190 · vercel/workflow · GitHub
Skip to content

[e2e] Separate event-log-race-repro harness noise from real regressions - #2190

Merged
VaguelySerious merged 1 commit into
mainfrom
peter/event-log-race-repro-classify-infra
Jun 1, 2026
Merged

[e2e] Separate event-log-race-repro harness noise from real regressions#2190
VaguelySerious merged 1 commit into
mainfrom
peter/event-log-race-repro-classify-infra

Conversation

@VaguelySerious

Copy link
Copy Markdown
Member

Summary

The event-log-race-repro job is currently red for the wrong reason. In a recent run, it reported 1231 of 2000 runs "did not complete cleanly" — yet CORRUPTED_EVENT_LOG / USER_ERROR / RUNTIME_ERROR were all 0. The entire count was harness-side noise.

What the other column was

The repro sorts each run into completed, CORRUPTED_EVENT_LOG, USER_ERROR, RUNTIME_ERROR, stuck, or other. Only the three named error codes mapped to their own bucket; everything else fell into other, and the --check gate failed the job on any non-completed run. So other conflated genuine corruption with:

  • HOOK_RESUME_FAILED — the run completed fine, but the harness's own resumeHook() rejected (typically because the sleep branch already finished the run and disposed the hook).
  • NO_WAKE_BRANCH — the run completed but the sleep branch won every iteration, so the wake path was never taken.
  • transport errors / timeouts thrown in the driver, and cancellations.

What was actually going wrong

A timing race in the test harness, not an SDK bug. The workflow's sleep budget is iterations × sleepMs = 5 × 5000 = 25000ms; the harness resumes the hook at resumeDelayMs + rand(resumeJitterMs) = up to 25000ms — the resume ceiling exactly equals the budget. On a fast/warm deployment the workflow exhausts its sleeps before the resume lands, so the resume hits a disposed hook and/or the wake branch is never taken.

The smoking gun: the #2 retry against the same already-warm deployment jumped 767→1231 other while stuck dropped to 0 and the step scenarios stayed perfect. Faster execution = the resume misses the window more often. It also means most "green" runs weren't even exercising the wake-branch shape the repro is meant to stress.

Changes

  1. Reclassify harness-side, non-corruption outcomes into a dedicated non-gating infra bucket (test + renderer). The job now gates only on regression-class outcomes (CORRUPTED_EVENT_LOG / USER_ERROR / RUNTIME_ERROR / stuck / other); infra is reported but never fails the job. The PR comment now reads "No event-log regressions… N runs hit harness-side infra outcomes (… do not fail the job)."
  2. Surface regressions ahead of infra in the failures table so the 20-row cap never hides a real failure behind a flood of timing rows.
  3. Restore wake-branch coverage: raise the default iterations ceiling (5 → 8). Because the run short-circuits via returnOnWake the moment the hook wins, a higher ceiling widens the window for the resume to land before sleep-budget exhaustion at ~no runtime cost. Added a beforeAll guard that warns when the resume ceiling is not below the sleep budget.
  4. Testability: the renderer's pure helpers are now exported and covered by node:test (run via a new lightweight Lint job).

Tests

node --test .github/scripts/**/*.test.js (8 tests) covers: infra is non-gating; regressionCount ignores completed/infra; an all-infra results file (mirroring the production comment) yields 0 regressions; regressions sort ahead of infra; --check exits 0 on infra-only and 1 on a corruption-class outcome.

Note: the full 2000-run repro only runs against a deployment behind the event-log-race-repro label, so the reclassification's end-to-end effect is best confirmed by adding that label to this PR.

🤖 Generated with Claude Code

The event-log-race-repro job classified every non-completed run into an
`other` grab-bag and gated on it. Hook-resume timing races (HOOK_RESUME_FAILED,
NO_WAKE_BRANCH) and transport errors in the repro driver — none of which are
event-log corruption — landed there and failed the job, drowning the signal it
exists to detect.
- Route harness-side, non-corruption outcomes to a dedicated non-gating `infra`
bucket (test + renderer). The job now gates only on regression-class outcomes
(CORRUPTED_EVENT_LOG / USER_ERROR / RUNTIME_ERROR / stuck / other).
- Sort regressions ahead of infra rows so the 20-row cap never hides a real
failure behind a flood of harness-timing rows.
- Raise the default hook/sleep iteration ceiling (5 -> 8). Because the run
short-circuits via returnOnWake the moment the hook wins, this widens the
window for the delayed resume to land before the sleep budget is exhausted,
at ~no runtime cost — restoring the wake-branch coverage the scenario exists
to exercise. Add a beforeAll guard that warns when the resume ceiling is not
below the sleep budget.
- Make the renderer's pure helpers unit-testable and add node:test coverage,
wired into the Lint workflow.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@changeset-bot

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: e100a60

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

This PR includes changesets to release 0 packages

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

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

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

@vercel

vercelBot commented May 31, 2026

Copy link
Copy Markdown
Contributor

@github-actions

github-actionsBot commented May 31, 2026

Copy link
Copy Markdown
Contributor

🧪 E2E Test Results

Some tests failed

Summary

PassedFailedSkippedTotal
❌ ▲ Vercel Production126332191485
❌ 💻 Local Development167012191890
✅ 📦 Local Production167102191890
✅ 🐘 Local Postgres167102191890
✅ 🪟 Windows13500135
❌ 📋 Other7681176945
Total7178510528235

❌ Failed Tests

▲ Vercel Production (3 failed)

express (1 failed):

  • instanceMethodStepWorkflow - instance methods with "use step" directive | wrun_01KSZ4H8N0DE044HA3WQ2AG25H | 🔍 observability

nextjs-webpack (2 failed):

  • AbortController abortHookOrderingWorkflow [listener-first-abort-first]: addEventListener → hook.then → abort() → resumeHook
  • AbortController abortHookOrderingWorkflow [listener-first-hook-first]: addEventListener → hook.then → resumeHook → abort()
💻 Local Development (1 failed)

express-stable (1 failed):

  • hookWithSleepFinalStepWorkflow - step only on final payload | wrun_01KSZ4NB8SC1XKHH9GSXQEKXZR
📋 Other (1 failed)

e2e-vercel-prod-tanstack-start (1 failed):

  • AbortController abortHookOrderingWorkflow [listener-first-abort-first]: addEventListener → hook.then → abort() → resumeHook

Details by Category

❌ ▲ Vercel Production
AppPassedFailedSkipped
✅ astro109026
✅ example109026
❌ express108126
✅ fastify109026
✅ hono109026
✅ nextjs-turbopack13302
❌ nextjs-webpack13122
✅ nitro109026
✅ nuxt109026
✅ sveltekit12807
✅ vite109026
❌ 💻 Local Development
AppPassedFailedSkipped
✅ astro-stable110025
❌ express-stable109125
✅ fastify-stable110025
✅ hono-stable110025
✅ nextjs-turbopack-canary116019
✅ nextjs-turbopack-stable-lazy-discovery-disabled13500
✅ nextjs-turbopack-stable-lazy-discovery-enabled13500
✅ nextjs-webpack-canary116019
✅ nextjs-webpack-stable-lazy-discovery-disabled13500
✅ nextjs-webpack-stable-lazy-discovery-enabled13500
✅ nitro-stable110025
✅ nuxt-stable110025
✅ sveltekit-stable12906
✅ vite-stable110025
✅ 📦 Local Production
AppPassedFailedSkipped
✅ astro-stable110025
✅ express-stable110025
✅ fastify-stable110025
✅ hono-stable110025
✅ nextjs-turbopack-canary116019
✅ nextjs-turbopack-stable-lazy-discovery-disabled13500
✅ nextjs-turbopack-stable-lazy-discovery-enabled13500
✅ nextjs-webpack-canary116019
✅ nextjs-webpack-stable-lazy-discovery-disabled13500
✅ nextjs-webpack-stable-lazy-discovery-enabled13500
✅ nitro-stable110025
✅ nuxt-stable110025
✅ sveltekit-stable12906
✅ vite-stable110025
✅ 🐘 Local Postgres
AppPassedFailedSkipped
✅ astro-stable110025
✅ express-stable110025
✅ fastify-stable110025
✅ hono-stable110025
✅ nextjs-turbopack-canary116019
✅ nextjs-turbopack-stable-lazy-discovery-disabled13500
✅ nextjs-turbopack-stable-lazy-discovery-enabled13500
✅ nextjs-webpack-canary116019
✅ nextjs-webpack-stable-lazy-discovery-disabled13500
✅ nextjs-webpack-stable-lazy-discovery-enabled13500
✅ nitro-stable110025
✅ nuxt-stable110025
✅ sveltekit-stable12906
✅ vite-stable110025
✅ 🪟 Windows
AppPassedFailedSkipped
✅ nextjs-turbopack13500
❌ 📋 Other
AppPassedFailedSkipped
✅ e2e-local-dev-nest-stable110025
✅ e2e-local-dev-tanstack-start-110025
✅ e2e-local-postgres-nest-stable110025
✅ e2e-local-postgres-tanstack-start-110025
✅ e2e-local-prod-nest-stable110025
✅ e2e-local-prod-tanstack-start-110025
❌ e2e-vercel-prod-tanstack-start108126

📋 View full workflow run


Some E2E test jobs failed:

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

Check the workflow run for details.

@github-actions

github-actionsBot commented May 31, 2026

Copy link
Copy Markdown
Contributor

📊 Benchmark Results

📈 Comparing against baseline from main branch. Green 🟢 = faster, Red 🔺 = slower.

workflow with no steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Express0.042s (-5.9% 🟢)1.006s (~)0.964s101.00x
💻 LocalNitro0.045s (+5.3% 🔺)1.006s (~)0.961s101.09x
💻 LocalNext.js (Turbopack)0.059s1.007s0.947s101.42x
🐘 PostgresExpress0.060s (+2.8%)1.012s (~)0.952s101.43x
🐘 PostgresNitro0.062s (-35.2% 🟢)1.012s (-2.9%)0.951s101.48x
🐘 PostgresNext.js (Turbopack)0.071s1.013s0.941s101.71x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express0.304s (+29.2% 🔺)9.230s (+332.2% 🔺)8.926s101.00x
▲ VercelNitro0.467s (+14.0% 🔺)8.212s (+227.3% 🔺)7.745s101.54x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

workflow with 1 step

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Nitro1.090s (-3.6%)2.007s (~)0.917s101.00x
💻 LocalExpress1.094s (-2.8%)2.006s (~)0.912s101.00x
🐘 PostgresNitro1.100s (-3.5%)2.008s (~)0.909s101.01x
🐘 PostgresExpress1.108s (-3.4%)2.011s (~)0.903s101.02x
💻 LocalNext.js (Turbopack)1.137s2.006s0.869s101.04x
🐘 PostgresNext.js (Turbopack)1.154s2.011s0.856s101.06x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro1.951s (-49.9% 🟢)8.918s (+50.9% 🔺)6.967s101.00x
▲ VercelExpress2.816s (+50.2% 🔺)11.043s (+190.0% 🔺)8.227s101.44x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

workflow with 10 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Express10.509s (-3.8%)11.022s (~)0.513s31.00x
🐘 PostgresExpress10.527s (-4.0%)11.018s (~)0.490s31.00x
🐘 PostgresNitro10.543s (-3.0%)11.018s (~)0.475s31.00x
💻 LocalNitro10.549s (-3.6%)11.023s (~)0.475s31.00x
💻 LocalNext.js (Turbopack)10.771s11.022s0.251s31.02x
🐘 PostgresNext.js (Turbopack)10.864s11.019s0.155s31.03x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro13.250s (-44.2% 🟢)17.759s (-29.3% 🟢)4.509s31.00x
▲ VercelExpress18.536s (+9.2% 🔺)25.082s (+25.3% 🔺)6.546s21.40x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

workflow with 25 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro13.713s (-6.0% 🟢)14.018s (-6.7% 🟢)0.304s51.00x
💻 LocalExpress13.737s (-8.2% 🟢)14.027s (-6.7% 🟢)0.290s51.00x
🐘 PostgresExpress13.748s (-5.7% 🟢)14.016s (-6.7% 🟢)0.268s51.00x
💻 LocalNitro13.768s (-8.6% 🟢)14.027s (-12.5% 🟢)0.260s51.00x
💻 LocalNext.js (Turbopack)14.375s15.031s0.656s41.05x
🐘 PostgresNext.js (Turbopack)14.516s15.019s0.503s41.06x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro22.401s (-65.2% 🟢)41.317s (-38.0% 🟢)18.916s21.00x
▲ VercelExpress22.701s (-54.9% 🟢)31.002s (-41.0% 🟢)8.301s21.01x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

workflow with 50 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro12.332s (-11.7% 🟢)13.018s (-9.0% 🟢)0.687s71.00x
🐘 PostgresExpress12.367s (-11.7% 🟢)13.017s (-10.8% 🟢)0.649s71.00x
💻 LocalExpress12.445s (-25.0% 🟢)13.025s (-23.5% 🟢)0.580s71.01x
💻 LocalNitro12.686s (-24.4% 🟢)13.168s (-22.7% 🟢)0.482s71.03x
💻 LocalNext.js (Turbopack)13.628s14.028s0.400s71.11x
🐘 PostgresNext.js (Turbopack)13.797s14.164s0.367s71.12x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express27.762s (-77.1% 🟢)31.197s (-74.8% 🟢)3.435s31.00x
▲ VercelNitro28.303s (-93.3% 🟢)36.682s (-91.4% 🟢)8.379s31.02x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

Promise.all with 10 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express1.186s (-5.9% 🟢)2.008s (~)0.822s151.00x
💻 LocalExpress1.198s (-19.6% 🟢)2.006s (~)0.808s151.01x
💻 LocalNitro1.206s (-26.1% 🟢)2.007s (-3.2%)0.800s151.02x
🐘 PostgresNitro1.214s (-4.8%)2.007s (~)0.794s151.02x
🐘 PostgresNext.js (Turbopack)1.258s2.007s0.750s151.06x
💻 LocalNext.js (Turbopack)1.347s2.005s0.659s151.14x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express2.716s (-5.0% 🟢)19.336s (+318.3% 🔺)16.620s21.00x
▲ VercelNitro2.825s (~)9.853s (+127.9% 🔺)7.027s41.04x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

Promise.all with 25 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express1.236s (-47.7% 🟢)2.008s (-33.3% 🟢)0.772s151.00x
🐘 PostgresNitro1.255s (-46.6% 🟢)2.007s (-33.3% 🟢)0.752s151.02x
🐘 PostgresNext.js (Turbopack)1.428s2.008s0.579s151.16x
💻 LocalNext.js (Turbopack)1.687s2.074s0.387s151.36x
💻 LocalExpress1.717s (-41.9% 🟢)2.006s (-41.9% 🟢)0.289s151.39x
💻 LocalNitro2.000s (-36.4% 🟢)2.365s (-39.1% 🟢)0.365s141.62x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro3.186s (-21.4% 🟢)11.331s (+91.4% 🔺)8.145s31.00x
▲ VercelExpress6.602s (+82.4% 🔺)18.243s (+257.0% 🔺)11.642s32.07x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

Promise.all with 50 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express1.383s (-60.3% 🟢)2.007s (-50.0% 🟢)0.624s151.00x
🐘 PostgresNitro1.398s (-59.8% 🟢)2.007s (-49.9% 🟢)0.609s151.01x
🐘 PostgresNext.js (Turbopack)1.735s2.315s0.580s131.25x
💻 LocalNext.js (Turbopack)4.602s5.298s0.696s73.33x
💻 LocalExpress4.827s (-42.1% 🟢)5.514s (-38.9% 🟢)0.687s63.49x
💻 LocalNitro6.170s (-26.1% 🟢)6.617s (-26.6% 🟢)0.447s54.46x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express5.289s (+24.7% 🔺)7.700s (+25.7% 🔺)2.411s41.00x
▲ VercelNitro5.461s (+54.9% 🔺)11.366s (+105.4% 🔺)5.905s31.03x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

Promise.race with 10 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.178s (-6.3% 🟢)2.009s (~)0.831s151.00x
🐘 PostgresExpress1.193s (-5.1% 🟢)2.008s (~)0.815s151.01x
🐘 PostgresNext.js (Turbopack)1.249s2.009s0.760s151.06x
💻 LocalNext.js (Turbopack)1.407s2.006s0.599s151.19x
💻 LocalExpress1.456s (-23.1% 🟢)2.007s (-15.1% 🟢)0.551s151.24x
💻 LocalNitro1.681s (-9.9% 🟢)2.073s (-11.4% 🟢)0.392s151.43x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express2.482s (-3.8%)8.298s (+90.8% 🔺)5.816s41.00x
▲ VercelNitro2.653s (+7.9% 🔺)5.245s (+25.8% 🔺)2.592s61.07x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

Promise.race with 25 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.242s (-46.9% 🟢)2.009s (-33.3% 🟢)0.767s151.00x
🐘 PostgresExpress1.261s (-46.1% 🟢)2.010s (-33.3% 🟢)0.748s151.02x
🐘 PostgresNext.js (Turbopack)1.403s2.008s0.605s151.13x
💻 LocalExpress1.970s (-37.1% 🟢)2.392s (-36.4% 🟢)0.423s131.59x
💻 LocalNext.js (Turbopack)2.017s2.591s0.574s121.62x
💻 LocalNitro2.086s (-31.9% 🟢)2.591s (-33.3% 🟢)0.505s121.68x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro3.436s (+6.3% 🔺)10.457s (+106.0% 🔺)7.020s31.00x
▲ VercelExpress3.725s (+16.7% 🔺)8.451s (+76.3% 🔺)4.726s41.08x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

Promise.race with 50 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.382s (-60.3% 🟢)2.008s (-49.9% 🟢)0.626s151.00x
🐘 PostgresExpress1.385s (-60.4% 🟢)2.008s (-49.9% 🟢)0.622s151.00x
🐘 PostgresNext.js (Turbopack)1.746s2.156s0.411s141.26x
💻 LocalExpress4.650s (-47.2% 🟢)5.180s (-44.1% 🟢)0.530s63.36x
💻 LocalNext.js (Turbopack)5.127s5.683s0.557s63.71x
💻 LocalNitro5.886s (-35.6% 🟢)6.413s (-36.0% 🟢)0.527s54.26x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro6.106s (+19.9% 🔺)10.232s (+50.1% 🔺)4.125s51.00x
▲ VercelExpress10.634s (+65.7% 🔺)15.236s (+86.3% 🔺)4.602s21.74x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

workflow with 10 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express0.565s (-32.6% 🟢)1.007s (-1.6%)0.442s601.00x
💻 LocalExpress0.578s (-41.3% 🟢)1.005s (-6.6% 🟢)0.427s601.02x
🐘 PostgresNitro0.593s (-27.7% 🟢)1.040s (+3.4%)0.447s591.05x
💻 LocalNitro0.697s (-29.0% 🟢)1.096s (~)0.399s551.23x
🐘 PostgresNext.js (Turbopack)0.837s1.007s0.170s601.48x
💻 LocalNext.js (Turbopack)0.868s1.004s0.136s601.54x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro4.851s (-78.0% 🟢)7.522s (-68.7% 🟢)2.672s81.00x
▲ VercelExpress4.974s (-73.8% 🟢)12.581s (-41.0% 🟢)7.606s61.03x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

workflow with 25 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express1.325s (-33.0% 🟢)2.008s (-11.1% 🟢)0.682s451.00x
🐘 PostgresNitro1.351s (-29.9% 🟢)2.030s (-3.4%)0.679s451.02x
💻 LocalNitro1.510s (-50.3% 🟢)2.006s (-46.6% 🟢)0.497s451.14x
💻 LocalExpress1.515s (-49.8% 🟢)2.006s (-44.1% 🟢)0.491s451.14x
🐘 PostgresNext.js (Turbopack)2.084s2.468s0.384s371.57x
💻 LocalNext.js (Turbopack)2.112s3.008s0.896s301.59x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express12.360s (-64.2% 🟢)17.479s (-52.5% 🟢)5.119s61.00x
▲ VercelNitro12.401s (-68.6% 🟢)15.005s (-63.7% 🟢)2.605s71.00x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

workflow with 50 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro2.594s (-36.8% 🟢)3.033s (-34.1% 🟢)0.439s401.00x
🐘 PostgresExpress2.702s (-32.3% 🟢)3.137s (-28.2% 🟢)0.434s391.04x
💻 LocalNitro3.229s (-65.3% 🟢)4.009s (-60.0% 🟢)0.780s301.24x
💻 LocalExpress3.324s (-63.9% 🟢)4.043s (-59.6% 🟢)0.719s301.28x
🐘 PostgresNext.js (Turbopack)3.925s4.010s0.085s301.51x
💻 LocalNext.js (Turbopack)4.452s5.052s0.601s241.72x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro25.276s (-73.9% 🟢)30.878s (-68.6% 🟢)5.602s41.00x
▲ VercelExpress26.350s (-79.7% 🟢)32.626s (-75.3% 🟢)6.276s41.04x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

workflow with 10 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.217s (-23.3% 🟢)1.006s (~)0.788s601.00x
🐘 PostgresExpress0.227s (-19.6% 🟢)1.006s (~)0.779s601.05x
🐘 PostgresNext.js (Turbopack)0.305s1.023s0.719s591.40x
💻 LocalNitro0.424s (-29.9% 🟢)1.004s (-1.7%)0.581s601.95x
💻 LocalExpress0.441s (-21.3% 🟢)1.004s (~)0.563s602.03x
💻 LocalNext.js (Turbopack)0.627s1.022s0.395s592.89x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express2.394s (+22.5% 🔺)12.031s (+230.8% 🔺)9.638s51.00x
▲ VercelNitro3.625s (+118.3% 🔺)10.359s (+209.1% 🔺)6.733s61.51x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

workflow with 25 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.339s (-31.7% 🟢)1.006s (~)0.668s901.00x
🐘 PostgresExpress0.361s (-29.1% 🟢)1.006s (~)0.645s901.07x
🐘 PostgresNext.js (Turbopack)0.515s1.007s0.492s901.52x
💻 LocalNitro2.152s (-15.2% 🟢)2.638s (-12.3% 🟢)0.486s356.35x
💻 LocalExpress2.471s (-1.7%)2.979s (-1.0%)0.508s317.29x
💻 LocalNext.js (Turbopack)2.513s3.225s0.712s287.42x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro4.568s (+41.6% 🔺)10.630s (+120.5% 🔺)6.062s91.00x
▲ VercelExpress5.640s (+85.1% 🔺)10.451s (+117.4% 🔺)4.811s101.23x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

workflow with 50 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.683s (-13.6% 🟢)1.006s (~)0.323s1201.00x
🐘 PostgresExpress0.705s (-13.9% 🟢)1.015s (~)0.310s1191.03x
🐘 PostgresNext.js (Turbopack)1.048s1.960s0.912s621.53x
💻 LocalNitro9.742s (-12.9% 🟢)10.277s (-11.9% 🟢)0.534s1214.27x
💻 LocalNext.js (Turbopack)10.810s11.575s0.766s1115.83x
💻 LocalExpress11.232s (~)11.856s (-0.7%)0.624s1116.45x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express13.763s (+85.5% 🔺)17.466s (+88.9% 🔺)3.702s71.00x
▲ VercelNitro15.302s (+98.1% 🔺)21.654s (+130.4% 🔺)6.352s61.11x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

Stream Benchmarks(includes TTFB metrics)
workflow with stream

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.156s (+463.8% 🔺)2.000s (+100.1% 🔺)0.001s (-6.7% 🟢)2.010s (+98.8% 🔺)0.855s101.00x
💻 LocalExpress1.163s (+484.4% 🔺)2.005s (+99.6% 🔺)0.011s (-13.2% 🟢)2.018s (+98.2% 🔺)0.854s101.01x
💻 LocalNitro1.165s (+445.3% 🔺)2.005s (+99.6% 🔺)0.012s (-0.8%)2.020s (+98.2% 🔺)0.854s101.01x
🐘 PostgresExpress1.169s (+469.8% 🔺)1.995s (+99.8% 🔺)0.001s (-31.3% 🟢)2.010s (+98.7% 🔺)0.841s101.01x
💻 LocalNext.js (Turbopack)1.214s2.003s0.011s2.017s0.804s101.05x
🐘 PostgresNext.js (Turbopack)1.233s2.003s0.001s2.012s0.779s101.07x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express2.318s (-7.5% 🟢)6.376s (+55.9% 🔺)1.539s (+60.1% 🔺)8.459s (+51.3% 🔺)6.140s101.00x
▲ VercelNitro3.129s (-18.4% 🟢)6.747s (+27.9% 🔺)1.486s (+100.3% 🔺)9.559s (+47.4% 🔺)6.431s101.35x
▲ VercelNext.js (Turbopack)⚠️missing-----

🔍 Observability: Express | Nitro

stream pipeline with 5 transform steps (1MB)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Nitro1.584s (+88.9% 🔺)2.010s (+98.6% 🔺)0.011s (+14.5% 🔺)2.022s (+81.2% 🔺)0.438s301.00x
🐘 PostgresNitro1.588s (+154.4% 🔺)2.007s (+99.4% 🔺)0.004s (-9.7% 🟢)2.026s (+98.1% 🔺)0.438s301.00x
🐘 PostgresExpress1.621s (+157.3% 🔺)2.001s (+98.8% 🔺)0.004s (~)2.027s (+98.1% 🔺)0.406s301.02x
💻 LocalExpress1.722s (+127.5% 🔺)2.043s (+98.6% 🔺)0.013s (+36.7% 🔺)2.059s (+98.0% 🔺)0.336s301.09x
🐘 PostgresNext.js (Turbopack)1.809s2.011s0.004s2.029s0.220s301.14x
💻 LocalNext.js (Turbopack)1.917s2.008s0.010s2.201s0.284s281.21x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express6.501s (~)13.670s (+70.7% 🔺)0.154s (-62.3% 🟢)14.972s (+69.5% 🔺)8.471s51.00x
▲ VercelNitro7.642s (-74.0% 🟢)7.694s (-75.0% 🟢)0.328s (+192.9% 🔺)10.227s (-67.8% 🟢)2.585s61.18x
▲ VercelNext.js (Turbopack)⚠️missing-----

🔍 Observability: Express | Nitro

10 parallel streams (1MB each)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express0.699s (-27.3% 🟢)1.012s (-20.8% 🟢)0.000s (-22.0% 🟢)1.027s (-21.4% 🟢)0.328s591.00x
🐘 PostgresNitro0.704s (-27.3% 🟢)1.015s (-18.6% 🟢)0.000s (+22.0% 🔺)1.032s (-18.0% 🟢)0.328s591.01x
🐘 PostgresNext.js (Turbopack)0.835s1.091s0.000s1.099s0.264s551.19x
💻 LocalNitro1.375s (+12.5% 🔺)2.013s (~)0.000s (+100.0% 🔺)2.015s (~)0.640s301.97x
💻 LocalNext.js (Turbopack)1.497s2.013s0.001s2.016s0.520s302.14x
💻 LocalExpress1.602s (+30.8% 🔺)2.018s (~)0.000s (-40.0% 🟢)2.020s (~)0.418s302.29x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro3.997s (+31.0% 🔺)8.575s (+95.2% 🔺)0.000s (-100.0% 🟢)9.792s (+103.6% 🔺)5.796s71.00x
▲ VercelExpress5.270s (+40.9% 🔺)8.952s (+75.4% 🔺)0.001s (+358.3% 🔺)10.718s (+93.8% 🔺)5.448s61.32x
▲ VercelNext.js (Turbopack)⚠️missing-----

🔍 Observability: Nitro | Express

fan-out fan-in 10 streams (1MB each)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.409s (-21.3% 🟢)2.142s (~)0.000s (-100.0% 🟢)2.154s (-0.9%)0.745s281.00x
🐘 PostgresExpress1.513s (-14.6% 🟢)2.174s (~)0.000s (+Infinity% 🔺)2.189s (~)0.677s281.07x
🐘 PostgresNext.js (Turbopack)1.650s2.145s0.000s2.162s0.512s281.17x
💻 LocalNitro3.097s (-8.6% 🟢)3.775s (-6.4% 🟢)0.001s (+40.6% 🔺)3.777s (-6.4% 🟢)0.681s162.20x
💻 LocalNext.js (Turbopack)3.186s3.674s0.000s3.678s0.492s172.26x
💻 LocalExpress3.351s (-3.4%)4.028s (~)0.001s (+41.7% 🔺)4.032s (~)0.681s152.38x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express5.775s (+25.9% 🔺)12.656s (+110.2% 🔺)0.001s (+Infinity% 🔺)15.088s (+133.7% 🔺)9.313s41.00x
▲ VercelNitro5.828s (+42.4% 🔺)17.093s (+218.1% 🔺)0.000s (-100.0% 🟢)17.759s (+206.5% 🔺)11.931s41.01x
▲ VercelNext.js (Turbopack)⚠️missing-----

🔍 Observability: Express | Nitro

Summary

Fastest Framework by World

Winner determined by most benchmark wins

World🥇 Fastest FrameworkWins
💻 LocalExpress9/21
🐘 PostgresNitro13/21
▲ VercelExpress11/21
Fastest World by Framework

Winner determined by most benchmark wins

Framework🥇 Fastest WorldWins
Express🐘 Postgres16/21
Next.js (Turbopack)🐘 Postgres15/21
Nitro🐘 Postgres17/21
Column Definitions
  • Workflow Time: Runtime reported by workflow (completedAt - createdAt) - primary metric
  • TTFB: Time to First Byte - time from workflow start until first stream byte received (stream benchmarks only)
  • Slurp: Time from first byte to complete stream consumption (stream benchmarks only)
  • Wall Time: Total testbench time (trigger workflow + poll for result)
  • Overhead: Testbench overhead (Wall Time - Workflow Time)
  • Samples: Number of benchmark iterations run
  • vs Fastest: How much slower compared to the fastest configuration for this benchmark

Worlds:

  • 💻 Local: In-memory filesystem world (local development)
  • 🐘 Postgres: PostgreSQL database world (local development)
  • ▲ Vercel: Vercel production/preview deployment
  • 🌐 Turso: Community world (local development)
  • 🌐 MongoDB: Community world (local development)
  • 🌐 Redis: Community world (local development)
  • 🌐 Jazz: Community world (local development)
  • 🌐 Redis: Community world (local development)
  • 🌐 Redis + BullMQ: Community world (local development)
  • 🌐 Cloudflare: Community world (local development)
  • 🌐 MySQL: Community world (local development)
  • 🌐 Azure: Community world (local development)
  • 🌐 NATS JetStream: Community world (local development)
  • 🌐 Upstash: Community world (local development)

📋 View full workflow run


Some benchmark jobs failed:

  • Local: success
  • Postgres: success
  • Vercel: failure

Check the workflow run for details.

@VaguelySerious
VaguelySerious marked this pull request as ready for review June 1, 2026 09:06
@VaguelySerious
VaguelySerious requested a review from a team as a code ownerJune 1, 2026 09:06
@VaguelySerious
VaguelySerious merged commit ae3c833 into mainJun 1, 2026
112 of 122 checks passed
@VaguelySerious
VaguelySerious deleted the peter/event-log-race-repro-classify-infra branch June 1, 2026 09:07
VaguelySerious added a commit that referenced this pull request Jun 1, 2026
(cherry picked from commit ae3c833)
(cherry picked from commit c1d7bab)
pranaygp added a commit that referenced this pull request Jun 2, 2026
* origin/main:
[world-vercel] Retry transient response-body parse failures in the HTTP client (#2204)
Add virtualization to the trace viewer (#2205)
Trace viewer: scroll-load events past an auto-load cap (#2200)
fix(core): resolve forwarded stream keys across deployments (#2191)
[e2e] Improve error labeling in event-log-race-repro CI job (#2190)
[core] Harden event pagination response parsing (#2180) (#2179)
Add loading skeleton to the new trace viewer (#2164)
Add tooltip components + apply on up/down detail pane (#2163)
fix(swc-plugin): allow wasm host imports during link (#2174)
[test] Forward-port reused-sleep replay divergence test (#2172)
[e2e] Add `event-log-race-repro` label for triggering CI stress-test (#2159)
Version Packages (beta) (#2162)
fix(world-local): skip Nov 2025 ghost versions on npm (#2168)
fix(core,errors): classify SDK encryption failures as RUNTIME_ERROR (#2145)
[web-shared][web] Fix events tab search (#2107)
Version Packages (beta) (#2147)
Allow setting workflow attributes from steps (#2157)
Better search handling on the trace viewer (#2144)
[docs] Document experimental attributes feature (#2141)
Sign up for freeto 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

@VaguelySerious
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' [e2e] Separate event-log-race-repro harness noise from real regressions by VaguelySerious · Pull Request #2190 · vercel/workflow · GitHub
Skip to content

[e2e] Separate event-log-race-repro harness noise from real regressions - #2190

Merged
VaguelySerious merged 1 commit into
mainfrom
peter/event-log-race-repro-classify-infra
Jun 1, 2026
Merged

[e2e] Separate event-log-race-repro harness noise from real regressions#2190
VaguelySerious merged 1 commit into
mainfrom
peter/event-log-race-repro-classify-infra

Conversation

@VaguelySerious

Copy link
Copy Markdown
Member

Summary

The event-log-race-repro job is currently red for the wrong reason. In a recent run, it reported 1231 of 2000 runs "did not complete cleanly" — yet CORRUPTED_EVENT_LOG / USER_ERROR / RUNTIME_ERROR were all 0. The entire count was harness-side noise.

What the other column was

The repro sorts each run into completed, CORRUPTED_EVENT_LOG, USER_ERROR, RUNTIME_ERROR, stuck, or other. Only the three named error codes mapped to their own bucket; everything else fell into other, and the --check gate failed the job on any non-completed run. So other conflated genuine corruption with:

  • HOOK_RESUME_FAILED — the run completed fine, but the harness's own resumeHook() rejected (typically because the sleep branch already finished the run and disposed the hook).
  • NO_WAKE_BRANCH — the run completed but the sleep branch won every iteration, so the wake path was never taken.
  • transport errors / timeouts thrown in the driver, and cancellations.

What was actually going wrong

A timing race in the test harness, not an SDK bug. The workflow's sleep budget is iterations × sleepMs = 5 × 5000 = 25000ms; the harness resumes the hook at resumeDelayMs + rand(resumeJitterMs) = up to 25000ms — the resume ceiling exactly equals the budget. On a fast/warm deployment the workflow exhausts its sleeps before the resume lands, so the resume hits a disposed hook and/or the wake branch is never taken.

The smoking gun: the #2 retry against the same already-warm deployment jumped 767→1231 other while stuck dropped to 0 and the step scenarios stayed perfect. Faster execution = the resume misses the window more often. It also means most "green" runs weren't even exercising the wake-branch shape the repro is meant to stress.

Changes

  1. Reclassify harness-side, non-corruption outcomes into a dedicated non-gating infra bucket (test + renderer). The job now gates only on regression-class outcomes (CORRUPTED_EVENT_LOG / USER_ERROR / RUNTIME_ERROR / stuck / other); infra is reported but never fails the job. The PR comment now reads "No event-log regressions… N runs hit harness-side infra outcomes (… do not fail the job)."
  2. Surface regressions ahead of infra in the failures table so the 20-row cap never hides a real failure behind a flood of timing rows.
  3. Restore wake-branch coverage: raise the default iterations ceiling (5 → 8). Because the run short-circuits via returnOnWake the moment the hook wins, a higher ceiling widens the window for the resume to land before sleep-budget exhaustion at ~no runtime cost. Added a beforeAll guard that warns when the resume ceiling is not below the sleep budget.
  4. Testability: the renderer's pure helpers are now exported and covered by node:test (run via a new lightweight Lint job).

Tests

node --test .github/scripts/**/*.test.js (8 tests) covers: infra is non-gating; regressionCount ignores completed/infra; an all-infra results file (mirroring the production comment) yields 0 regressions; regressions sort ahead of infra; --check exits 0 on infra-only and 1 on a corruption-class outcome.

Note: the full 2000-run repro only runs against a deployment behind the event-log-race-repro label, so the reclassification's end-to-end effect is best confirmed by adding that label to this PR.

🤖 Generated with Claude Code

The event-log-race-repro job classified every non-completed run into an
`other` grab-bag and gated on it. Hook-resume timing races (HOOK_RESUME_FAILED,
NO_WAKE_BRANCH) and transport errors in the repro driver — none of which are
event-log corruption — landed there and failed the job, drowning the signal it
exists to detect.
- Route harness-side, non-corruption outcomes to a dedicated non-gating `infra`
bucket (test + renderer). The job now gates only on regression-class outcomes
(CORRUPTED_EVENT_LOG / USER_ERROR / RUNTIME_ERROR / stuck / other).
- Sort regressions ahead of infra rows so the 20-row cap never hides a real
failure behind a flood of harness-timing rows.
- Raise the default hook/sleep iteration ceiling (5 -> 8). Because the run
short-circuits via returnOnWake the moment the hook wins, this widens the
window for the delayed resume to land before the sleep budget is exhausted,
at ~no runtime cost — restoring the wake-branch coverage the scenario exists
to exercise. Add a beforeAll guard that warns when the resume ceiling is not
below the sleep budget.
- Make the renderer's pure helpers unit-testable and add node:test coverage,
wired into the Lint workflow.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@changeset-bot

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: e100a60

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

This PR includes changesets to release 0 packages

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

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

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

@vercel

vercelBot commented May 31, 2026

Copy link
Copy Markdown
Contributor

@github-actions

github-actionsBot commented May 31, 2026

Copy link
Copy Markdown
Contributor

🧪 E2E Test Results

Some tests failed

Summary

PassedFailedSkippedTotal
❌ ▲ Vercel Production126332191485
❌ 💻 Local Development167012191890
✅ 📦 Local Production167102191890
✅ 🐘 Local Postgres167102191890
✅ 🪟 Windows13500135
❌ 📋 Other7681176945
Total7178510528235

❌ Failed Tests

▲ Vercel Production (3 failed)

express (1 failed):

  • instanceMethodStepWorkflow - instance methods with "use step" directive | wrun_01KSZ4H8N0DE044HA3WQ2AG25H | 🔍 observability

nextjs-webpack (2 failed):

  • AbortController abortHookOrderingWorkflow [listener-first-abort-first]: addEventListener → hook.then → abort() → resumeHook
  • AbortController abortHookOrderingWorkflow [listener-first-hook-first]: addEventListener → hook.then → resumeHook → abort()
💻 Local Development (1 failed)

express-stable (1 failed):

  • hookWithSleepFinalStepWorkflow - step only on final payload | wrun_01KSZ4NB8SC1XKHH9GSXQEKXZR
📋 Other (1 failed)

e2e-vercel-prod-tanstack-start (1 failed):

  • AbortController abortHookOrderingWorkflow [listener-first-abort-first]: addEventListener → hook.then → abort() → resumeHook

Details by Category

❌ ▲ Vercel Production
AppPassedFailedSkipped
✅ astro109026
✅ example109026
❌ express108126
✅ fastify109026
✅ hono109026
✅ nextjs-turbopack13302
❌ nextjs-webpack13122
✅ nitro109026
✅ nuxt109026
✅ sveltekit12807
✅ vite109026
❌ 💻 Local Development
AppPassedFailedSkipped
✅ astro-stable110025
❌ express-stable109125
✅ fastify-stable110025
✅ hono-stable110025
✅ nextjs-turbopack-canary116019
✅ nextjs-turbopack-stable-lazy-discovery-disabled13500
✅ nextjs-turbopack-stable-lazy-discovery-enabled13500
✅ nextjs-webpack-canary116019
✅ nextjs-webpack-stable-lazy-discovery-disabled13500
✅ nextjs-webpack-stable-lazy-discovery-enabled13500
✅ nitro-stable110025
✅ nuxt-stable110025
✅ sveltekit-stable12906
✅ vite-stable110025
✅ 📦 Local Production
AppPassedFailedSkipped
✅ astro-stable110025
✅ express-stable110025
✅ fastify-stable110025
✅ hono-stable110025
✅ nextjs-turbopack-canary116019
✅ nextjs-turbopack-stable-lazy-discovery-disabled13500
✅ nextjs-turbopack-stable-lazy-discovery-enabled13500
✅ nextjs-webpack-canary116019
✅ nextjs-webpack-stable-lazy-discovery-disabled13500
✅ nextjs-webpack-stable-lazy-discovery-enabled13500
✅ nitro-stable110025
✅ nuxt-stable110025
✅ sveltekit-stable12906
✅ vite-stable110025
✅ 🐘 Local Postgres
AppPassedFailedSkipped
✅ astro-stable110025
✅ express-stable110025
✅ fastify-stable110025
✅ hono-stable110025
✅ nextjs-turbopack-canary116019
✅ nextjs-turbopack-stable-lazy-discovery-disabled13500
✅ nextjs-turbopack-stable-lazy-discovery-enabled13500
✅ nextjs-webpack-canary116019
✅ nextjs-webpack-stable-lazy-discovery-disabled13500
✅ nextjs-webpack-stable-lazy-discovery-enabled13500
✅ nitro-stable110025
✅ nuxt-stable110025
✅ sveltekit-stable12906
✅ vite-stable110025
✅ 🪟 Windows
AppPassedFailedSkipped
✅ nextjs-turbopack13500
❌ 📋 Other
AppPassedFailedSkipped
✅ e2e-local-dev-nest-stable110025
✅ e2e-local-dev-tanstack-start-110025
✅ e2e-local-postgres-nest-stable110025
✅ e2e-local-postgres-tanstack-start-110025
✅ e2e-local-prod-nest-stable110025
✅ e2e-local-prod-tanstack-start-110025
❌ e2e-vercel-prod-tanstack-start108126

📋 View full workflow run


Some E2E test jobs failed:

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

Check the workflow run for details.

@github-actions

github-actionsBot commented May 31, 2026

Copy link
Copy Markdown
Contributor

📊 Benchmark Results

📈 Comparing against baseline from main branch. Green 🟢 = faster, Red 🔺 = slower.

workflow with no steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Express0.042s (-5.9% 🟢)1.006s (~)0.964s101.00x
💻 LocalNitro0.045s (+5.3% 🔺)1.006s (~)0.961s101.09x
💻 LocalNext.js (Turbopack)0.059s1.007s0.947s101.42x
🐘 PostgresExpress0.060s (+2.8%)1.012s (~)0.952s101.43x
🐘 PostgresNitro0.062s (-35.2% 🟢)1.012s (-2.9%)0.951s101.48x
🐘 PostgresNext.js (Turbopack)0.071s1.013s0.941s101.71x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express0.304s (+29.2% 🔺)9.230s (+332.2% 🔺)8.926s101.00x
▲ VercelNitro0.467s (+14.0% 🔺)8.212s (+227.3% 🔺)7.745s101.54x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

workflow with 1 step

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Nitro1.090s (-3.6%)2.007s (~)0.917s101.00x
💻 LocalExpress1.094s (-2.8%)2.006s (~)0.912s101.00x
🐘 PostgresNitro1.100s (-3.5%)2.008s (~)0.909s101.01x
🐘 PostgresExpress1.108s (-3.4%)2.011s (~)0.903s101.02x
💻 LocalNext.js (Turbopack)1.137s2.006s0.869s101.04x
🐘 PostgresNext.js (Turbopack)1.154s2.011s0.856s101.06x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro1.951s (-49.9% 🟢)8.918s (+50.9% 🔺)6.967s101.00x
▲ VercelExpress2.816s (+50.2% 🔺)11.043s (+190.0% 🔺)8.227s101.44x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

workflow with 10 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Express10.509s (-3.8%)11.022s (~)0.513s31.00x
🐘 PostgresExpress10.527s (-4.0%)11.018s (~)0.490s31.00x
🐘 PostgresNitro10.543s (-3.0%)11.018s (~)0.475s31.00x
💻 LocalNitro10.549s (-3.6%)11.023s (~)0.475s31.00x
💻 LocalNext.js (Turbopack)10.771s11.022s0.251s31.02x
🐘 PostgresNext.js (Turbopack)10.864s11.019s0.155s31.03x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro13.250s (-44.2% 🟢)17.759s (-29.3% 🟢)4.509s31.00x
▲ VercelExpress18.536s (+9.2% 🔺)25.082s (+25.3% 🔺)6.546s21.40x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

workflow with 25 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro13.713s (-6.0% 🟢)14.018s (-6.7% 🟢)0.304s51.00x
💻 LocalExpress13.737s (-8.2% 🟢)14.027s (-6.7% 🟢)0.290s51.00x
🐘 PostgresExpress13.748s (-5.7% 🟢)14.016s (-6.7% 🟢)0.268s51.00x
💻 LocalNitro13.768s (-8.6% 🟢)14.027s (-12.5% 🟢)0.260s51.00x
💻 LocalNext.js (Turbopack)14.375s15.031s0.656s41.05x
🐘 PostgresNext.js (Turbopack)14.516s15.019s0.503s41.06x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro22.401s (-65.2% 🟢)41.317s (-38.0% 🟢)18.916s21.00x
▲ VercelExpress22.701s (-54.9% 🟢)31.002s (-41.0% 🟢)8.301s21.01x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

workflow with 50 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro12.332s (-11.7% 🟢)13.018s (-9.0% 🟢)0.687s71.00x
🐘 PostgresExpress12.367s (-11.7% 🟢)13.017s (-10.8% 🟢)0.649s71.00x
💻 LocalExpress12.445s (-25.0% 🟢)13.025s (-23.5% 🟢)0.580s71.01x
💻 LocalNitro12.686s (-24.4% 🟢)13.168s (-22.7% 🟢)0.482s71.03x
💻 LocalNext.js (Turbopack)13.628s14.028s0.400s71.11x
🐘 PostgresNext.js (Turbopack)13.797s14.164s0.367s71.12x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express27.762s (-77.1% 🟢)31.197s (-74.8% 🟢)3.435s31.00x
▲ VercelNitro28.303s (-93.3% 🟢)36.682s (-91.4% 🟢)8.379s31.02x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

Promise.all with 10 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express1.186s (-5.9% 🟢)2.008s (~)0.822s151.00x
💻 LocalExpress1.198s (-19.6% 🟢)2.006s (~)0.808s151.01x
💻 LocalNitro1.206s (-26.1% 🟢)2.007s (-3.2%)0.800s151.02x
🐘 PostgresNitro1.214s (-4.8%)2.007s (~)0.794s151.02x
🐘 PostgresNext.js (Turbopack)1.258s2.007s0.750s151.06x
💻 LocalNext.js (Turbopack)1.347s2.005s0.659s151.14x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express2.716s (-5.0% 🟢)19.336s (+318.3% 🔺)16.620s21.00x
▲ VercelNitro2.825s (~)9.853s (+127.9% 🔺)7.027s41.04x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

Promise.all with 25 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express1.236s (-47.7% 🟢)2.008s (-33.3% 🟢)0.772s151.00x
🐘 PostgresNitro1.255s (-46.6% 🟢)2.007s (-33.3% 🟢)0.752s151.02x
🐘 PostgresNext.js (Turbopack)1.428s2.008s0.579s151.16x
💻 LocalNext.js (Turbopack)1.687s2.074s0.387s151.36x
💻 LocalExpress1.717s (-41.9% 🟢)2.006s (-41.9% 🟢)0.289s151.39x
💻 LocalNitro2.000s (-36.4% 🟢)2.365s (-39.1% 🟢)0.365s141.62x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro3.186s (-21.4% 🟢)11.331s (+91.4% 🔺)8.145s31.00x
▲ VercelExpress6.602s (+82.4% 🔺)18.243s (+257.0% 🔺)11.642s32.07x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

Promise.all with 50 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express1.383s (-60.3% 🟢)2.007s (-50.0% 🟢)0.624s151.00x
🐘 PostgresNitro1.398s (-59.8% 🟢)2.007s (-49.9% 🟢)0.609s151.01x
🐘 PostgresNext.js (Turbopack)1.735s2.315s0.580s131.25x
💻 LocalNext.js (Turbopack)4.602s5.298s0.696s73.33x
💻 LocalExpress4.827s (-42.1% 🟢)5.514s (-38.9% 🟢)0.687s63.49x
💻 LocalNitro6.170s (-26.1% 🟢)6.617s (-26.6% 🟢)0.447s54.46x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express5.289s (+24.7% 🔺)7.700s (+25.7% 🔺)2.411s41.00x
▲ VercelNitro5.461s (+54.9% 🔺)11.366s (+105.4% 🔺)5.905s31.03x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

Promise.race with 10 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.178s (-6.3% 🟢)2.009s (~)0.831s151.00x
🐘 PostgresExpress1.193s (-5.1% 🟢)2.008s (~)0.815s151.01x
🐘 PostgresNext.js (Turbopack)1.249s2.009s0.760s151.06x
💻 LocalNext.js (Turbopack)1.407s2.006s0.599s151.19x
💻 LocalExpress1.456s (-23.1% 🟢)2.007s (-15.1% 🟢)0.551s151.24x
💻 LocalNitro1.681s (-9.9% 🟢)2.073s (-11.4% 🟢)0.392s151.43x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express2.482s (-3.8%)8.298s (+90.8% 🔺)5.816s41.00x
▲ VercelNitro2.653s (+7.9% 🔺)5.245s (+25.8% 🔺)2.592s61.07x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

Promise.race with 25 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.242s (-46.9% 🟢)2.009s (-33.3% 🟢)0.767s151.00x
🐘 PostgresExpress1.261s (-46.1% 🟢)2.010s (-33.3% 🟢)0.748s151.02x
🐘 PostgresNext.js (Turbopack)1.403s2.008s0.605s151.13x
💻 LocalExpress1.970s (-37.1% 🟢)2.392s (-36.4% 🟢)0.423s131.59x
💻 LocalNext.js (Turbopack)2.017s2.591s0.574s121.62x
💻 LocalNitro2.086s (-31.9% 🟢)2.591s (-33.3% 🟢)0.505s121.68x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro3.436s (+6.3% 🔺)10.457s (+106.0% 🔺)7.020s31.00x
▲ VercelExpress3.725s (+16.7% 🔺)8.451s (+76.3% 🔺)4.726s41.08x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

Promise.race with 50 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.382s (-60.3% 🟢)2.008s (-49.9% 🟢)0.626s151.00x
🐘 PostgresExpress1.385s (-60.4% 🟢)2.008s (-49.9% 🟢)0.622s151.00x
🐘 PostgresNext.js (Turbopack)1.746s2.156s0.411s141.26x
💻 LocalExpress4.650s (-47.2% 🟢)5.180s (-44.1% 🟢)0.530s63.36x
💻 LocalNext.js (Turbopack)5.127s5.683s0.557s63.71x
💻 LocalNitro5.886s (-35.6% 🟢)6.413s (-36.0% 🟢)0.527s54.26x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro6.106s (+19.9% 🔺)10.232s (+50.1% 🔺)4.125s51.00x
▲ VercelExpress10.634s (+65.7% 🔺)15.236s (+86.3% 🔺)4.602s21.74x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

workflow with 10 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express0.565s (-32.6% 🟢)1.007s (-1.6%)0.442s601.00x
💻 LocalExpress0.578s (-41.3% 🟢)1.005s (-6.6% 🟢)0.427s601.02x
🐘 PostgresNitro0.593s (-27.7% 🟢)1.040s (+3.4%)0.447s591.05x
💻 LocalNitro0.697s (-29.0% 🟢)1.096s (~)0.399s551.23x
🐘 PostgresNext.js (Turbopack)0.837s1.007s0.170s601.48x
💻 LocalNext.js (Turbopack)0.868s1.004s0.136s601.54x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro4.851s (-78.0% 🟢)7.522s (-68.7% 🟢)2.672s81.00x
▲ VercelExpress4.974s (-73.8% 🟢)12.581s (-41.0% 🟢)7.606s61.03x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

workflow with 25 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express1.325s (-33.0% 🟢)2.008s (-11.1% 🟢)0.682s451.00x
🐘 PostgresNitro1.351s (-29.9% 🟢)2.030s (-3.4%)0.679s451.02x
💻 LocalNitro1.510s (-50.3% 🟢)2.006s (-46.6% 🟢)0.497s451.14x
💻 LocalExpress1.515s (-49.8% 🟢)2.006s (-44.1% 🟢)0.491s451.14x
🐘 PostgresNext.js (Turbopack)2.084s2.468s0.384s371.57x
💻 LocalNext.js (Turbopack)2.112s3.008s0.896s301.59x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express12.360s (-64.2% 🟢)17.479s (-52.5% 🟢)5.119s61.00x
▲ VercelNitro12.401s (-68.6% 🟢)15.005s (-63.7% 🟢)2.605s71.00x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

workflow with 50 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro2.594s (-36.8% 🟢)3.033s (-34.1% 🟢)0.439s401.00x
🐘 PostgresExpress2.702s (-32.3% 🟢)3.137s (-28.2% 🟢)0.434s391.04x
💻 LocalNitro3.229s (-65.3% 🟢)4.009s (-60.0% 🟢)0.780s301.24x
💻 LocalExpress3.324s (-63.9% 🟢)4.043s (-59.6% 🟢)0.719s301.28x
🐘 PostgresNext.js (Turbopack)3.925s4.010s0.085s301.51x
💻 LocalNext.js (Turbopack)4.452s5.052s0.601s241.72x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro25.276s (-73.9% 🟢)30.878s (-68.6% 🟢)5.602s41.00x
▲ VercelExpress26.350s (-79.7% 🟢)32.626s (-75.3% 🟢)6.276s41.04x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

workflow with 10 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.217s (-23.3% 🟢)1.006s (~)0.788s601.00x
🐘 PostgresExpress0.227s (-19.6% 🟢)1.006s (~)0.779s601.05x
🐘 PostgresNext.js (Turbopack)0.305s1.023s0.719s591.40x
💻 LocalNitro0.424s (-29.9% 🟢)1.004s (-1.7%)0.581s601.95x
💻 LocalExpress0.441s (-21.3% 🟢)1.004s (~)0.563s602.03x
💻 LocalNext.js (Turbopack)0.627s1.022s0.395s592.89x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express2.394s (+22.5% 🔺)12.031s (+230.8% 🔺)9.638s51.00x
▲ VercelNitro3.625s (+118.3% 🔺)10.359s (+209.1% 🔺)6.733s61.51x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

workflow with 25 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.339s (-31.7% 🟢)1.006s (~)0.668s901.00x
🐘 PostgresExpress0.361s (-29.1% 🟢)1.006s (~)0.645s901.07x
🐘 PostgresNext.js (Turbopack)0.515s1.007s0.492s901.52x
💻 LocalNitro2.152s (-15.2% 🟢)2.638s (-12.3% 🟢)0.486s356.35x
💻 LocalExpress2.471s (-1.7%)2.979s (-1.0%)0.508s317.29x
💻 LocalNext.js (Turbopack)2.513s3.225s0.712s287.42x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro4.568s (+41.6% 🔺)10.630s (+120.5% 🔺)6.062s91.00x
▲ VercelExpress5.640s (+85.1% 🔺)10.451s (+117.4% 🔺)4.811s101.23x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

workflow with 50 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.683s (-13.6% 🟢)1.006s (~)0.323s1201.00x
🐘 PostgresExpress0.705s (-13.9% 🟢)1.015s (~)0.310s1191.03x
🐘 PostgresNext.js (Turbopack)1.048s1.960s0.912s621.53x
💻 LocalNitro9.742s (-12.9% 🟢)10.277s (-11.9% 🟢)0.534s1214.27x
💻 LocalNext.js (Turbopack)10.810s11.575s0.766s1115.83x
💻 LocalExpress11.232s (~)11.856s (-0.7%)0.624s1116.45x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express13.763s (+85.5% 🔺)17.466s (+88.9% 🔺)3.702s71.00x
▲ VercelNitro15.302s (+98.1% 🔺)21.654s (+130.4% 🔺)6.352s61.11x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

Stream Benchmarks(includes TTFB metrics)
workflow with stream

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.156s (+463.8% 🔺)2.000s (+100.1% 🔺)0.001s (-6.7% 🟢)2.010s (+98.8% 🔺)0.855s101.00x
💻 LocalExpress1.163s (+484.4% 🔺)2.005s (+99.6% 🔺)0.011s (-13.2% 🟢)2.018s (+98.2% 🔺)0.854s101.01x
💻 LocalNitro1.165s (+445.3% 🔺)2.005s (+99.6% 🔺)0.012s (-0.8%)2.020s (+98.2% 🔺)0.854s101.01x
🐘 PostgresExpress1.169s (+469.8% 🔺)1.995s (+99.8% 🔺)0.001s (-31.3% 🟢)2.010s (+98.7% 🔺)0.841s101.01x
💻 LocalNext.js (Turbopack)1.214s2.003s0.011s2.017s0.804s101.05x
🐘 PostgresNext.js (Turbopack)1.233s2.003s0.001s2.012s0.779s101.07x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express2.318s (-7.5% 🟢)6.376s (+55.9% 🔺)1.539s (+60.1% 🔺)8.459s (+51.3% 🔺)6.140s101.00x
▲ VercelNitro3.129s (-18.4% 🟢)6.747s (+27.9% 🔺)1.486s (+100.3% 🔺)9.559s (+47.4% 🔺)6.431s101.35x
▲ VercelNext.js (Turbopack)⚠️missing-----

🔍 Observability: Express | Nitro

stream pipeline with 5 transform steps (1MB)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Nitro1.584s (+88.9% 🔺)2.010s (+98.6% 🔺)0.011s (+14.5% 🔺)2.022s (+81.2% 🔺)0.438s301.00x
🐘 PostgresNitro1.588s (+154.4% 🔺)2.007s (+99.4% 🔺)0.004s (-9.7% 🟢)2.026s (+98.1% 🔺)0.438s301.00x
🐘 PostgresExpress1.621s (+157.3% 🔺)2.001s (+98.8% 🔺)0.004s (~)2.027s (+98.1% 🔺)0.406s301.02x
💻 LocalExpress1.722s (+127.5% 🔺)2.043s (+98.6% 🔺)0.013s (+36.7% 🔺)2.059s (+98.0% 🔺)0.336s301.09x
🐘 PostgresNext.js (Turbopack)1.809s2.011s0.004s2.029s0.220s301.14x
💻 LocalNext.js (Turbopack)1.917s2.008s0.010s2.201s0.284s281.21x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express6.501s (~)13.670s (+70.7% 🔺)0.154s (-62.3% 🟢)14.972s (+69.5% 🔺)8.471s51.00x
▲ VercelNitro7.642s (-74.0% 🟢)7.694s (-75.0% 🟢)0.328s (+192.9% 🔺)10.227s (-67.8% 🟢)2.585s61.18x
▲ VercelNext.js (Turbopack)⚠️missing-----

🔍 Observability: Express | Nitro

10 parallel streams (1MB each)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express0.699s (-27.3% 🟢)1.012s (-20.8% 🟢)0.000s (-22.0% 🟢)1.027s (-21.4% 🟢)0.328s591.00x
🐘 PostgresNitro0.704s (-27.3% 🟢)1.015s (-18.6% 🟢)0.000s (+22.0% 🔺)1.032s (-18.0% 🟢)0.328s591.01x
🐘 PostgresNext.js (Turbopack)0.835s1.091s0.000s1.099s0.264s551.19x
💻 LocalNitro1.375s (+12.5% 🔺)2.013s (~)0.000s (+100.0% 🔺)2.015s (~)0.640s301.97x
💻 LocalNext.js (Turbopack)1.497s2.013s0.001s2.016s0.520s302.14x
💻 LocalExpress1.602s (+30.8% 🔺)2.018s (~)0.000s (-40.0% 🟢)2.020s (~)0.418s302.29x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro3.997s (+31.0% 🔺)8.575s (+95.2% 🔺)0.000s (-100.0% 🟢)9.792s (+103.6% 🔺)5.796s71.00x
▲ VercelExpress5.270s (+40.9% 🔺)8.952s (+75.4% 🔺)0.001s (+358.3% 🔺)10.718s (+93.8% 🔺)5.448s61.32x
▲ VercelNext.js (Turbopack)⚠️missing-----

🔍 Observability: Nitro | Express

fan-out fan-in 10 streams (1MB each)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.409s (-21.3% 🟢)2.142s (~)0.000s (-100.0% 🟢)2.154s (-0.9%)0.745s281.00x
🐘 PostgresExpress1.513s (-14.6% 🟢)2.174s (~)0.000s (+Infinity% 🔺)2.189s (~)0.677s281.07x
🐘 PostgresNext.js (Turbopack)1.650s2.145s0.000s2.162s0.512s281.17x
💻 LocalNitro3.097s (-8.6% 🟢)3.775s (-6.4% 🟢)0.001s (+40.6% 🔺)3.777s (-6.4% 🟢)0.681s162.20x
💻 LocalNext.js (Turbopack)3.186s3.674s0.000s3.678s0.492s172.26x
💻 LocalExpress3.351s (-3.4%)4.028s (~)0.001s (+41.7% 🔺)4.032s (~)0.681s152.38x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express5.775s (+25.9% 🔺)12.656s (+110.2% 🔺)0.001s (+Infinity% 🔺)15.088s (+133.7% 🔺)9.313s41.00x
▲ VercelNitro5.828s (+42.4% 🔺)17.093s (+218.1% 🔺)0.000s (-100.0% 🟢)17.759s (+206.5% 🔺)11.931s41.01x
▲ VercelNext.js (Turbopack)⚠️missing-----

🔍 Observability: Express | Nitro

Summary

Fastest Framework by World

Winner determined by most benchmark wins

World🥇 Fastest FrameworkWins
💻 LocalExpress9/21
🐘 PostgresNitro13/21
▲ VercelExpress11/21
Fastest World by Framework

Winner determined by most benchmark wins

Framework🥇 Fastest WorldWins
Express🐘 Postgres16/21
Next.js (Turbopack)🐘 Postgres15/21
Nitro🐘 Postgres17/21
Column Definitions
  • Workflow Time: Runtime reported by workflow (completedAt - createdAt) - primary metric
  • TTFB: Time to First Byte - time from workflow start until first stream byte received (stream benchmarks only)
  • Slurp: Time from first byte to complete stream consumption (stream benchmarks only)
  • Wall Time: Total testbench time (trigger workflow + poll for result)
  • Overhead: Testbench overhead (Wall Time - Workflow Time)
  • Samples: Number of benchmark iterations run
  • vs Fastest: How much slower compared to the fastest configuration for this benchmark

Worlds:

  • 💻 Local: In-memory filesystem world (local development)
  • 🐘 Postgres: PostgreSQL database world (local development)
  • ▲ Vercel: Vercel production/preview deployment
  • 🌐 Turso: Community world (local development)
  • 🌐 MongoDB: Community world (local development)
  • 🌐 Redis: Community world (local development)
  • 🌐 Jazz: Community world (local development)
  • 🌐 Redis: Community world (local development)
  • 🌐 Redis + BullMQ: Community world (local development)
  • 🌐 Cloudflare: Community world (local development)
  • 🌐 MySQL: Community world (local development)
  • 🌐 Azure: Community world (local development)
  • 🌐 NATS JetStream: Community world (local development)
  • 🌐 Upstash: Community world (local development)

📋 View full workflow run


Some benchmark jobs failed:

  • Local: success
  • Postgres: success
  • Vercel: failure

Check the workflow run for details.

@VaguelySerious
VaguelySerious marked this pull request as ready for review June 1, 2026 09:06
@VaguelySerious
VaguelySerious requested a review from a team as a code ownerJune 1, 2026 09:06
@VaguelySerious
VaguelySerious merged commit ae3c833 into mainJun 1, 2026
112 of 122 checks passed
@VaguelySerious
VaguelySerious deleted the peter/event-log-race-repro-classify-infra branch June 1, 2026 09:07
VaguelySerious added a commit that referenced this pull request Jun 1, 2026
(cherry picked from commit ae3c833)
(cherry picked from commit c1d7bab)
pranaygp added a commit that referenced this pull request Jun 2, 2026
* origin/main:
[world-vercel] Retry transient response-body parse failures in the HTTP client (#2204)
Add virtualization to the trace viewer (#2205)
Trace viewer: scroll-load events past an auto-load cap (#2200)
fix(core): resolve forwarded stream keys across deployments (#2191)
[e2e] Improve error labeling in event-log-race-repro CI job (#2190)
[core] Harden event pagination response parsing (#2180) (#2179)
Add loading skeleton to the new trace viewer (#2164)
Add tooltip components + apply on up/down detail pane (#2163)
fix(swc-plugin): allow wasm host imports during link (#2174)
[test] Forward-port reused-sleep replay divergence test (#2172)
[e2e] Add `event-log-race-repro` label for triggering CI stress-test (#2159)
Version Packages (beta) (#2162)
fix(world-local): skip Nov 2025 ghost versions on npm (#2168)
fix(core,errors): classify SDK encryption failures as RUNTIME_ERROR (#2145)
[web-shared][web] Fix events tab search (#2107)
Version Packages (beta) (#2147)
Allow setting workflow attributes from steps (#2157)
Better search handling on the trace viewer (#2144)
[docs] Document experimental attributes feature (#2141)
Sign up for freeto 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

@VaguelySerious
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' [e2e] Separate event-log-race-repro harness noise from real regressions by VaguelySerious · Pull Request #2190 · vercel/workflow · GitHub
Skip to content

[e2e] Separate event-log-race-repro harness noise from real regressions - #2190

Merged
VaguelySerious merged 1 commit into
mainfrom
peter/event-log-race-repro-classify-infra
Jun 1, 2026
Merged

[e2e] Separate event-log-race-repro harness noise from real regressions#2190
VaguelySerious merged 1 commit into
mainfrom
peter/event-log-race-repro-classify-infra

Conversation

@VaguelySerious

Copy link
Copy Markdown
Member

Summary

The event-log-race-repro job is currently red for the wrong reason. In a recent run, it reported 1231 of 2000 runs "did not complete cleanly" — yet CORRUPTED_EVENT_LOG / USER_ERROR / RUNTIME_ERROR were all 0. The entire count was harness-side noise.

What the other column was

The repro sorts each run into completed, CORRUPTED_EVENT_LOG, USER_ERROR, RUNTIME_ERROR, stuck, or other. Only the three named error codes mapped to their own bucket; everything else fell into other, and the --check gate failed the job on any non-completed run. So other conflated genuine corruption with:

  • HOOK_RESUME_FAILED — the run completed fine, but the harness's own resumeHook() rejected (typically because the sleep branch already finished the run and disposed the hook).
  • NO_WAKE_BRANCH — the run completed but the sleep branch won every iteration, so the wake path was never taken.
  • transport errors / timeouts thrown in the driver, and cancellations.

What was actually going wrong

A timing race in the test harness, not an SDK bug. The workflow's sleep budget is iterations × sleepMs = 5 × 5000 = 25000ms; the harness resumes the hook at resumeDelayMs + rand(resumeJitterMs) = up to 25000ms — the resume ceiling exactly equals the budget. On a fast/warm deployment the workflow exhausts its sleeps before the resume lands, so the resume hits a disposed hook and/or the wake branch is never taken.

The smoking gun: the #2 retry against the same already-warm deployment jumped 767→1231 other while stuck dropped to 0 and the step scenarios stayed perfect. Faster execution = the resume misses the window more often. It also means most "green" runs weren't even exercising the wake-branch shape the repro is meant to stress.

Changes

  1. Reclassify harness-side, non-corruption outcomes into a dedicated non-gating infra bucket (test + renderer). The job now gates only on regression-class outcomes (CORRUPTED_EVENT_LOG / USER_ERROR / RUNTIME_ERROR / stuck / other); infra is reported but never fails the job. The PR comment now reads "No event-log regressions… N runs hit harness-side infra outcomes (… do not fail the job)."
  2. Surface regressions ahead of infra in the failures table so the 20-row cap never hides a real failure behind a flood of timing rows.
  3. Restore wake-branch coverage: raise the default iterations ceiling (5 → 8). Because the run short-circuits via returnOnWake the moment the hook wins, a higher ceiling widens the window for the resume to land before sleep-budget exhaustion at ~no runtime cost. Added a beforeAll guard that warns when the resume ceiling is not below the sleep budget.
  4. Testability: the renderer's pure helpers are now exported and covered by node:test (run via a new lightweight Lint job).

Tests

node --test .github/scripts/**/*.test.js (8 tests) covers: infra is non-gating; regressionCount ignores completed/infra; an all-infra results file (mirroring the production comment) yields 0 regressions; regressions sort ahead of infra; --check exits 0 on infra-only and 1 on a corruption-class outcome.

Note: the full 2000-run repro only runs against a deployment behind the event-log-race-repro label, so the reclassification's end-to-end effect is best confirmed by adding that label to this PR.

🤖 Generated with Claude Code

The event-log-race-repro job classified every non-completed run into an
`other` grab-bag and gated on it. Hook-resume timing races (HOOK_RESUME_FAILED,
NO_WAKE_BRANCH) and transport errors in the repro driver — none of which are
event-log corruption — landed there and failed the job, drowning the signal it
exists to detect.
- Route harness-side, non-corruption outcomes to a dedicated non-gating `infra`
bucket (test + renderer). The job now gates only on regression-class outcomes
(CORRUPTED_EVENT_LOG / USER_ERROR / RUNTIME_ERROR / stuck / other).
- Sort regressions ahead of infra rows so the 20-row cap never hides a real
failure behind a flood of harness-timing rows.
- Raise the default hook/sleep iteration ceiling (5 -> 8). Because the run
short-circuits via returnOnWake the moment the hook wins, this widens the
window for the delayed resume to land before the sleep budget is exhausted,
at ~no runtime cost — restoring the wake-branch coverage the scenario exists
to exercise. Add a beforeAll guard that warns when the resume ceiling is not
below the sleep budget.
- Make the renderer's pure helpers unit-testable and add node:test coverage,
wired into the Lint workflow.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@changeset-bot

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: e100a60

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

This PR includes changesets to release 0 packages

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

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

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

@vercel

vercelBot commented May 31, 2026

Copy link
Copy Markdown
Contributor

@github-actions

github-actionsBot commented May 31, 2026

Copy link
Copy Markdown
Contributor

🧪 E2E Test Results

Some tests failed

Summary

PassedFailedSkippedTotal
❌ ▲ Vercel Production126332191485
❌ 💻 Local Development167012191890
✅ 📦 Local Production167102191890
✅ 🐘 Local Postgres167102191890
✅ 🪟 Windows13500135
❌ 📋 Other7681176945
Total7178510528235

❌ Failed Tests

▲ Vercel Production (3 failed)

express (1 failed):

  • instanceMethodStepWorkflow - instance methods with "use step" directive | wrun_01KSZ4H8N0DE044HA3WQ2AG25H | 🔍 observability

nextjs-webpack (2 failed):

  • AbortController abortHookOrderingWorkflow [listener-first-abort-first]: addEventListener → hook.then → abort() → resumeHook
  • AbortController abortHookOrderingWorkflow [listener-first-hook-first]: addEventListener → hook.then → resumeHook → abort()
💻 Local Development (1 failed)

express-stable (1 failed):

  • hookWithSleepFinalStepWorkflow - step only on final payload | wrun_01KSZ4NB8SC1XKHH9GSXQEKXZR
📋 Other (1 failed)

e2e-vercel-prod-tanstack-start (1 failed):

  • AbortController abortHookOrderingWorkflow [listener-first-abort-first]: addEventListener → hook.then → abort() → resumeHook

Details by Category

❌ ▲ Vercel Production
AppPassedFailedSkipped
✅ astro109026
✅ example109026
❌ express108126
✅ fastify109026
✅ hono109026
✅ nextjs-turbopack13302
❌ nextjs-webpack13122
✅ nitro109026
✅ nuxt109026
✅ sveltekit12807
✅ vite109026
❌ 💻 Local Development
AppPassedFailedSkipped
✅ astro-stable110025
❌ express-stable109125
✅ fastify-stable110025
✅ hono-stable110025
✅ nextjs-turbopack-canary116019
✅ nextjs-turbopack-stable-lazy-discovery-disabled13500
✅ nextjs-turbopack-stable-lazy-discovery-enabled13500
✅ nextjs-webpack-canary116019
✅ nextjs-webpack-stable-lazy-discovery-disabled13500
✅ nextjs-webpack-stable-lazy-discovery-enabled13500
✅ nitro-stable110025
✅ nuxt-stable110025
✅ sveltekit-stable12906
✅ vite-stable110025
✅ 📦 Local Production
AppPassedFailedSkipped
✅ astro-stable110025
✅ express-stable110025
✅ fastify-stable110025
✅ hono-stable110025
✅ nextjs-turbopack-canary116019
✅ nextjs-turbopack-stable-lazy-discovery-disabled13500
✅ nextjs-turbopack-stable-lazy-discovery-enabled13500
✅ nextjs-webpack-canary116019
✅ nextjs-webpack-stable-lazy-discovery-disabled13500
✅ nextjs-webpack-stable-lazy-discovery-enabled13500
✅ nitro-stable110025
✅ nuxt-stable110025
✅ sveltekit-stable12906
✅ vite-stable110025
✅ 🐘 Local Postgres
AppPassedFailedSkipped
✅ astro-stable110025
✅ express-stable110025
✅ fastify-stable110025
✅ hono-stable110025
✅ nextjs-turbopack-canary116019
✅ nextjs-turbopack-stable-lazy-discovery-disabled13500
✅ nextjs-turbopack-stable-lazy-discovery-enabled13500
✅ nextjs-webpack-canary116019
✅ nextjs-webpack-stable-lazy-discovery-disabled13500
✅ nextjs-webpack-stable-lazy-discovery-enabled13500
✅ nitro-stable110025
✅ nuxt-stable110025
✅ sveltekit-stable12906
✅ vite-stable110025
✅ 🪟 Windows
AppPassedFailedSkipped
✅ nextjs-turbopack13500
❌ 📋 Other
AppPassedFailedSkipped
✅ e2e-local-dev-nest-stable110025
✅ e2e-local-dev-tanstack-start-110025
✅ e2e-local-postgres-nest-stable110025
✅ e2e-local-postgres-tanstack-start-110025
✅ e2e-local-prod-nest-stable110025
✅ e2e-local-prod-tanstack-start-110025
❌ e2e-vercel-prod-tanstack-start108126

📋 View full workflow run


Some E2E test jobs failed:

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

Check the workflow run for details.

@github-actions

github-actionsBot commented May 31, 2026

Copy link
Copy Markdown
Contributor

📊 Benchmark Results

📈 Comparing against baseline from main branch. Green 🟢 = faster, Red 🔺 = slower.

workflow with no steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Express0.042s (-5.9% 🟢)1.006s (~)0.964s101.00x
💻 LocalNitro0.045s (+5.3% 🔺)1.006s (~)0.961s101.09x
💻 LocalNext.js (Turbopack)0.059s1.007s0.947s101.42x
🐘 PostgresExpress0.060s (+2.8%)1.012s (~)0.952s101.43x
🐘 PostgresNitro0.062s (-35.2% 🟢)1.012s (-2.9%)0.951s101.48x
🐘 PostgresNext.js (Turbopack)0.071s1.013s0.941s101.71x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express0.304s (+29.2% 🔺)9.230s (+332.2% 🔺)8.926s101.00x
▲ VercelNitro0.467s (+14.0% 🔺)8.212s (+227.3% 🔺)7.745s101.54x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

workflow with 1 step

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Nitro1.090s (-3.6%)2.007s (~)0.917s101.00x
💻 LocalExpress1.094s (-2.8%)2.006s (~)0.912s101.00x
🐘 PostgresNitro1.100s (-3.5%)2.008s (~)0.909s101.01x
🐘 PostgresExpress1.108s (-3.4%)2.011s (~)0.903s101.02x
💻 LocalNext.js (Turbopack)1.137s2.006s0.869s101.04x
🐘 PostgresNext.js (Turbopack)1.154s2.011s0.856s101.06x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro1.951s (-49.9% 🟢)8.918s (+50.9% 🔺)6.967s101.00x
▲ VercelExpress2.816s (+50.2% 🔺)11.043s (+190.0% 🔺)8.227s101.44x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

workflow with 10 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Express10.509s (-3.8%)11.022s (~)0.513s31.00x
🐘 PostgresExpress10.527s (-4.0%)11.018s (~)0.490s31.00x
🐘 PostgresNitro10.543s (-3.0%)11.018s (~)0.475s31.00x
💻 LocalNitro10.549s (-3.6%)11.023s (~)0.475s31.00x
💻 LocalNext.js (Turbopack)10.771s11.022s0.251s31.02x
🐘 PostgresNext.js (Turbopack)10.864s11.019s0.155s31.03x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro13.250s (-44.2% 🟢)17.759s (-29.3% 🟢)4.509s31.00x
▲ VercelExpress18.536s (+9.2% 🔺)25.082s (+25.3% 🔺)6.546s21.40x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

workflow with 25 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro13.713s (-6.0% 🟢)14.018s (-6.7% 🟢)0.304s51.00x
💻 LocalExpress13.737s (-8.2% 🟢)14.027s (-6.7% 🟢)0.290s51.00x
🐘 PostgresExpress13.748s (-5.7% 🟢)14.016s (-6.7% 🟢)0.268s51.00x
💻 LocalNitro13.768s (-8.6% 🟢)14.027s (-12.5% 🟢)0.260s51.00x
💻 LocalNext.js (Turbopack)14.375s15.031s0.656s41.05x
🐘 PostgresNext.js (Turbopack)14.516s15.019s0.503s41.06x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro22.401s (-65.2% 🟢)41.317s (-38.0% 🟢)18.916s21.00x
▲ VercelExpress22.701s (-54.9% 🟢)31.002s (-41.0% 🟢)8.301s21.01x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

workflow with 50 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro12.332s (-11.7% 🟢)13.018s (-9.0% 🟢)0.687s71.00x
🐘 PostgresExpress12.367s (-11.7% 🟢)13.017s (-10.8% 🟢)0.649s71.00x
💻 LocalExpress12.445s (-25.0% 🟢)13.025s (-23.5% 🟢)0.580s71.01x
💻 LocalNitro12.686s (-24.4% 🟢)13.168s (-22.7% 🟢)0.482s71.03x
💻 LocalNext.js (Turbopack)13.628s14.028s0.400s71.11x
🐘 PostgresNext.js (Turbopack)13.797s14.164s0.367s71.12x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express27.762s (-77.1% 🟢)31.197s (-74.8% 🟢)3.435s31.00x
▲ VercelNitro28.303s (-93.3% 🟢)36.682s (-91.4% 🟢)8.379s31.02x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

Promise.all with 10 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express1.186s (-5.9% 🟢)2.008s (~)0.822s151.00x
💻 LocalExpress1.198s (-19.6% 🟢)2.006s (~)0.808s151.01x
💻 LocalNitro1.206s (-26.1% 🟢)2.007s (-3.2%)0.800s151.02x
🐘 PostgresNitro1.214s (-4.8%)2.007s (~)0.794s151.02x
🐘 PostgresNext.js (Turbopack)1.258s2.007s0.750s151.06x
💻 LocalNext.js (Turbopack)1.347s2.005s0.659s151.14x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express2.716s (-5.0% 🟢)19.336s (+318.3% 🔺)16.620s21.00x
▲ VercelNitro2.825s (~)9.853s (+127.9% 🔺)7.027s41.04x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

Promise.all with 25 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express1.236s (-47.7% 🟢)2.008s (-33.3% 🟢)0.772s151.00x
🐘 PostgresNitro1.255s (-46.6% 🟢)2.007s (-33.3% 🟢)0.752s151.02x
🐘 PostgresNext.js (Turbopack)1.428s2.008s0.579s151.16x
💻 LocalNext.js (Turbopack)1.687s2.074s0.387s151.36x
💻 LocalExpress1.717s (-41.9% 🟢)2.006s (-41.9% 🟢)0.289s151.39x
💻 LocalNitro2.000s (-36.4% 🟢)2.365s (-39.1% 🟢)0.365s141.62x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro3.186s (-21.4% 🟢)11.331s (+91.4% 🔺)8.145s31.00x
▲ VercelExpress6.602s (+82.4% 🔺)18.243s (+257.0% 🔺)11.642s32.07x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

Promise.all with 50 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express1.383s (-60.3% 🟢)2.007s (-50.0% 🟢)0.624s151.00x
🐘 PostgresNitro1.398s (-59.8% 🟢)2.007s (-49.9% 🟢)0.609s151.01x
🐘 PostgresNext.js (Turbopack)1.735s2.315s0.580s131.25x
💻 LocalNext.js (Turbopack)4.602s5.298s0.696s73.33x
💻 LocalExpress4.827s (-42.1% 🟢)5.514s (-38.9% 🟢)0.687s63.49x
💻 LocalNitro6.170s (-26.1% 🟢)6.617s (-26.6% 🟢)0.447s54.46x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express5.289s (+24.7% 🔺)7.700s (+25.7% 🔺)2.411s41.00x
▲ VercelNitro5.461s (+54.9% 🔺)11.366s (+105.4% 🔺)5.905s31.03x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

Promise.race with 10 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.178s (-6.3% 🟢)2.009s (~)0.831s151.00x
🐘 PostgresExpress1.193s (-5.1% 🟢)2.008s (~)0.815s151.01x
🐘 PostgresNext.js (Turbopack)1.249s2.009s0.760s151.06x
💻 LocalNext.js (Turbopack)1.407s2.006s0.599s151.19x
💻 LocalExpress1.456s (-23.1% 🟢)2.007s (-15.1% 🟢)0.551s151.24x
💻 LocalNitro1.681s (-9.9% 🟢)2.073s (-11.4% 🟢)0.392s151.43x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express2.482s (-3.8%)8.298s (+90.8% 🔺)5.816s41.00x
▲ VercelNitro2.653s (+7.9% 🔺)5.245s (+25.8% 🔺)2.592s61.07x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

Promise.race with 25 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.242s (-46.9% 🟢)2.009s (-33.3% 🟢)0.767s151.00x
🐘 PostgresExpress1.261s (-46.1% 🟢)2.010s (-33.3% 🟢)0.748s151.02x
🐘 PostgresNext.js (Turbopack)1.403s2.008s0.605s151.13x
💻 LocalExpress1.970s (-37.1% 🟢)2.392s (-36.4% 🟢)0.423s131.59x
💻 LocalNext.js (Turbopack)2.017s2.591s0.574s121.62x
💻 LocalNitro2.086s (-31.9% 🟢)2.591s (-33.3% 🟢)0.505s121.68x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro3.436s (+6.3% 🔺)10.457s (+106.0% 🔺)7.020s31.00x
▲ VercelExpress3.725s (+16.7% 🔺)8.451s (+76.3% 🔺)4.726s41.08x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

Promise.race with 50 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.382s (-60.3% 🟢)2.008s (-49.9% 🟢)0.626s151.00x
🐘 PostgresExpress1.385s (-60.4% 🟢)2.008s (-49.9% 🟢)0.622s151.00x
🐘 PostgresNext.js (Turbopack)1.746s2.156s0.411s141.26x
💻 LocalExpress4.650s (-47.2% 🟢)5.180s (-44.1% 🟢)0.530s63.36x
💻 LocalNext.js (Turbopack)5.127s5.683s0.557s63.71x
💻 LocalNitro5.886s (-35.6% 🟢)6.413s (-36.0% 🟢)0.527s54.26x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro6.106s (+19.9% 🔺)10.232s (+50.1% 🔺)4.125s51.00x
▲ VercelExpress10.634s (+65.7% 🔺)15.236s (+86.3% 🔺)4.602s21.74x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

workflow with 10 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express0.565s (-32.6% 🟢)1.007s (-1.6%)0.442s601.00x
💻 LocalExpress0.578s (-41.3% 🟢)1.005s (-6.6% 🟢)0.427s601.02x
🐘 PostgresNitro0.593s (-27.7% 🟢)1.040s (+3.4%)0.447s591.05x
💻 LocalNitro0.697s (-29.0% 🟢)1.096s (~)0.399s551.23x
🐘 PostgresNext.js (Turbopack)0.837s1.007s0.170s601.48x
💻 LocalNext.js (Turbopack)0.868s1.004s0.136s601.54x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro4.851s (-78.0% 🟢)7.522s (-68.7% 🟢)2.672s81.00x
▲ VercelExpress4.974s (-73.8% 🟢)12.581s (-41.0% 🟢)7.606s61.03x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

workflow with 25 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express1.325s (-33.0% 🟢)2.008s (-11.1% 🟢)0.682s451.00x
🐘 PostgresNitro1.351s (-29.9% 🟢)2.030s (-3.4%)0.679s451.02x
💻 LocalNitro1.510s (-50.3% 🟢)2.006s (-46.6% 🟢)0.497s451.14x
💻 LocalExpress1.515s (-49.8% 🟢)2.006s (-44.1% 🟢)0.491s451.14x
🐘 PostgresNext.js (Turbopack)2.084s2.468s0.384s371.57x
💻 LocalNext.js (Turbopack)2.112s3.008s0.896s301.59x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express12.360s (-64.2% 🟢)17.479s (-52.5% 🟢)5.119s61.00x
▲ VercelNitro12.401s (-68.6% 🟢)15.005s (-63.7% 🟢)2.605s71.00x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

workflow with 50 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro2.594s (-36.8% 🟢)3.033s (-34.1% 🟢)0.439s401.00x
🐘 PostgresExpress2.702s (-32.3% 🟢)3.137s (-28.2% 🟢)0.434s391.04x
💻 LocalNitro3.229s (-65.3% 🟢)4.009s (-60.0% 🟢)0.780s301.24x
💻 LocalExpress3.324s (-63.9% 🟢)4.043s (-59.6% 🟢)0.719s301.28x
🐘 PostgresNext.js (Turbopack)3.925s4.010s0.085s301.51x
💻 LocalNext.js (Turbopack)4.452s5.052s0.601s241.72x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro25.276s (-73.9% 🟢)30.878s (-68.6% 🟢)5.602s41.00x
▲ VercelExpress26.350s (-79.7% 🟢)32.626s (-75.3% 🟢)6.276s41.04x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

workflow with 10 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.217s (-23.3% 🟢)1.006s (~)0.788s601.00x
🐘 PostgresExpress0.227s (-19.6% 🟢)1.006s (~)0.779s601.05x
🐘 PostgresNext.js (Turbopack)0.305s1.023s0.719s591.40x
💻 LocalNitro0.424s (-29.9% 🟢)1.004s (-1.7%)0.581s601.95x
💻 LocalExpress0.441s (-21.3% 🟢)1.004s (~)0.563s602.03x
💻 LocalNext.js (Turbopack)0.627s1.022s0.395s592.89x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express2.394s (+22.5% 🔺)12.031s (+230.8% 🔺)9.638s51.00x
▲ VercelNitro3.625s (+118.3% 🔺)10.359s (+209.1% 🔺)6.733s61.51x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

workflow with 25 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.339s (-31.7% 🟢)1.006s (~)0.668s901.00x
🐘 PostgresExpress0.361s (-29.1% 🟢)1.006s (~)0.645s901.07x
🐘 PostgresNext.js (Turbopack)0.515s1.007s0.492s901.52x
💻 LocalNitro2.152s (-15.2% 🟢)2.638s (-12.3% 🟢)0.486s356.35x
💻 LocalExpress2.471s (-1.7%)2.979s (-1.0%)0.508s317.29x
💻 LocalNext.js (Turbopack)2.513s3.225s0.712s287.42x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro4.568s (+41.6% 🔺)10.630s (+120.5% 🔺)6.062s91.00x
▲ VercelExpress5.640s (+85.1% 🔺)10.451s (+117.4% 🔺)4.811s101.23x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

workflow with 50 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.683s (-13.6% 🟢)1.006s (~)0.323s1201.00x
🐘 PostgresExpress0.705s (-13.9% 🟢)1.015s (~)0.310s1191.03x
🐘 PostgresNext.js (Turbopack)1.048s1.960s0.912s621.53x
💻 LocalNitro9.742s (-12.9% 🟢)10.277s (-11.9% 🟢)0.534s1214.27x
💻 LocalNext.js (Turbopack)10.810s11.575s0.766s1115.83x
💻 LocalExpress11.232s (~)11.856s (-0.7%)0.624s1116.45x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express13.763s (+85.5% 🔺)17.466s (+88.9% 🔺)3.702s71.00x
▲ VercelNitro15.302s (+98.1% 🔺)21.654s (+130.4% 🔺)6.352s61.11x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

Stream Benchmarks(includes TTFB metrics)
workflow with stream

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.156s (+463.8% 🔺)2.000s (+100.1% 🔺)0.001s (-6.7% 🟢)2.010s (+98.8% 🔺)0.855s101.00x
💻 LocalExpress1.163s (+484.4% 🔺)2.005s (+99.6% 🔺)0.011s (-13.2% 🟢)2.018s (+98.2% 🔺)0.854s101.01x
💻 LocalNitro1.165s (+445.3% 🔺)2.005s (+99.6% 🔺)0.012s (-0.8%)2.020s (+98.2% 🔺)0.854s101.01x
🐘 PostgresExpress1.169s (+469.8% 🔺)1.995s (+99.8% 🔺)0.001s (-31.3% 🟢)2.010s (+98.7% 🔺)0.841s101.01x
💻 LocalNext.js (Turbopack)1.214s2.003s0.011s2.017s0.804s101.05x
🐘 PostgresNext.js (Turbopack)1.233s2.003s0.001s2.012s0.779s101.07x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express2.318s (-7.5% 🟢)6.376s (+55.9% 🔺)1.539s (+60.1% 🔺)8.459s (+51.3% 🔺)6.140s101.00x
▲ VercelNitro3.129s (-18.4% 🟢)6.747s (+27.9% 🔺)1.486s (+100.3% 🔺)9.559s (+47.4% 🔺)6.431s101.35x
▲ VercelNext.js (Turbopack)⚠️missing-----

🔍 Observability: Express | Nitro

stream pipeline with 5 transform steps (1MB)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Nitro1.584s (+88.9% 🔺)2.010s (+98.6% 🔺)0.011s (+14.5% 🔺)2.022s (+81.2% 🔺)0.438s301.00x
🐘 PostgresNitro1.588s (+154.4% 🔺)2.007s (+99.4% 🔺)0.004s (-9.7% 🟢)2.026s (+98.1% 🔺)0.438s301.00x
🐘 PostgresExpress1.621s (+157.3% 🔺)2.001s (+98.8% 🔺)0.004s (~)2.027s (+98.1% 🔺)0.406s301.02x
💻 LocalExpress1.722s (+127.5% 🔺)2.043s (+98.6% 🔺)0.013s (+36.7% 🔺)2.059s (+98.0% 🔺)0.336s301.09x
🐘 PostgresNext.js (Turbopack)1.809s2.011s0.004s2.029s0.220s301.14x
💻 LocalNext.js (Turbopack)1.917s2.008s0.010s2.201s0.284s281.21x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express6.501s (~)13.670s (+70.7% 🔺)0.154s (-62.3% 🟢)14.972s (+69.5% 🔺)8.471s51.00x
▲ VercelNitro7.642s (-74.0% 🟢)7.694s (-75.0% 🟢)0.328s (+192.9% 🔺)10.227s (-67.8% 🟢)2.585s61.18x
▲ VercelNext.js (Turbopack)⚠️missing-----

🔍 Observability: Express | Nitro

10 parallel streams (1MB each)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express0.699s (-27.3% 🟢)1.012s (-20.8% 🟢)0.000s (-22.0% 🟢)1.027s (-21.4% 🟢)0.328s591.00x
🐘 PostgresNitro0.704s (-27.3% 🟢)1.015s (-18.6% 🟢)0.000s (+22.0% 🔺)1.032s (-18.0% 🟢)0.328s591.01x
🐘 PostgresNext.js (Turbopack)0.835s1.091s0.000s1.099s0.264s551.19x
💻 LocalNitro1.375s (+12.5% 🔺)2.013s (~)0.000s (+100.0% 🔺)2.015s (~)0.640s301.97x
💻 LocalNext.js (Turbopack)1.497s2.013s0.001s2.016s0.520s302.14x
💻 LocalExpress1.602s (+30.8% 🔺)2.018s (~)0.000s (-40.0% 🟢)2.020s (~)0.418s302.29x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro3.997s (+31.0% 🔺)8.575s (+95.2% 🔺)0.000s (-100.0% 🟢)9.792s (+103.6% 🔺)5.796s71.00x
▲ VercelExpress5.270s (+40.9% 🔺)8.952s (+75.4% 🔺)0.001s (+358.3% 🔺)10.718s (+93.8% 🔺)5.448s61.32x
▲ VercelNext.js (Turbopack)⚠️missing-----

🔍 Observability: Nitro | Express

fan-out fan-in 10 streams (1MB each)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.409s (-21.3% 🟢)2.142s (~)0.000s (-100.0% 🟢)2.154s (-0.9%)0.745s281.00x
🐘 PostgresExpress1.513s (-14.6% 🟢)2.174s (~)0.000s (+Infinity% 🔺)2.189s (~)0.677s281.07x
🐘 PostgresNext.js (Turbopack)1.650s2.145s0.000s2.162s0.512s281.17x
💻 LocalNitro3.097s (-8.6% 🟢)3.775s (-6.4% 🟢)0.001s (+40.6% 🔺)3.777s (-6.4% 🟢)0.681s162.20x
💻 LocalNext.js (Turbopack)3.186s3.674s0.000s3.678s0.492s172.26x
💻 LocalExpress3.351s (-3.4%)4.028s (~)0.001s (+41.7% 🔺)4.032s (~)0.681s152.38x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express5.775s (+25.9% 🔺)12.656s (+110.2% 🔺)0.001s (+Infinity% 🔺)15.088s (+133.7% 🔺)9.313s41.00x
▲ VercelNitro5.828s (+42.4% 🔺)17.093s (+218.1% 🔺)0.000s (-100.0% 🟢)17.759s (+206.5% 🔺)11.931s41.01x
▲ VercelNext.js (Turbopack)⚠️missing-----

🔍 Observability: Express | Nitro

Summary

Fastest Framework by World

Winner determined by most benchmark wins

World🥇 Fastest FrameworkWins
💻 LocalExpress9/21
🐘 PostgresNitro13/21
▲ VercelExpress11/21
Fastest World by Framework

Winner determined by most benchmark wins

Framework🥇 Fastest WorldWins
Express🐘 Postgres16/21
Next.js (Turbopack)🐘 Postgres15/21
Nitro🐘 Postgres17/21
Column Definitions
  • Workflow Time: Runtime reported by workflow (completedAt - createdAt) - primary metric
  • TTFB: Time to First Byte - time from workflow start until first stream byte received (stream benchmarks only)
  • Slurp: Time from first byte to complete stream consumption (stream benchmarks only)
  • Wall Time: Total testbench time (trigger workflow + poll for result)
  • Overhead: Testbench overhead (Wall Time - Workflow Time)
  • Samples: Number of benchmark iterations run
  • vs Fastest: How much slower compared to the fastest configuration for this benchmark

Worlds:

  • 💻 Local: In-memory filesystem world (local development)
  • 🐘 Postgres: PostgreSQL database world (local development)
  • ▲ Vercel: Vercel production/preview deployment
  • 🌐 Turso: Community world (local development)
  • 🌐 MongoDB: Community world (local development)
  • 🌐 Redis: Community world (local development)
  • 🌐 Jazz: Community world (local development)
  • 🌐 Redis: Community world (local development)
  • 🌐 Redis + BullMQ: Community world (local development)
  • 🌐 Cloudflare: Community world (local development)
  • 🌐 MySQL: Community world (local development)
  • 🌐 Azure: Community world (local development)
  • 🌐 NATS JetStream: Community world (local development)
  • 🌐 Upstash: Community world (local development)

📋 View full workflow run


Some benchmark jobs failed:

  • Local: success
  • Postgres: success
  • Vercel: failure

Check the workflow run for details.

@VaguelySerious
VaguelySerious marked this pull request as ready for review June 1, 2026 09:06
@VaguelySerious
VaguelySerious requested a review from a team as a code ownerJune 1, 2026 09:06
@VaguelySerious
VaguelySerious merged commit ae3c833 into mainJun 1, 2026
112 of 122 checks passed
@VaguelySerious
VaguelySerious deleted the peter/event-log-race-repro-classify-infra branch June 1, 2026 09:07
VaguelySerious added a commit that referenced this pull request Jun 1, 2026
(cherry picked from commit ae3c833)
(cherry picked from commit c1d7bab)
pranaygp added a commit that referenced this pull request Jun 2, 2026
* origin/main:
[world-vercel] Retry transient response-body parse failures in the HTTP client (#2204)
Add virtualization to the trace viewer (#2205)
Trace viewer: scroll-load events past an auto-load cap (#2200)
fix(core): resolve forwarded stream keys across deployments (#2191)
[e2e] Improve error labeling in event-log-race-repro CI job (#2190)
[core] Harden event pagination response parsing (#2180) (#2179)
Add loading skeleton to the new trace viewer (#2164)
Add tooltip components + apply on up/down detail pane (#2163)
fix(swc-plugin): allow wasm host imports during link (#2174)
[test] Forward-port reused-sleep replay divergence test (#2172)
[e2e] Add `event-log-race-repro` label for triggering CI stress-test (#2159)
Version Packages (beta) (#2162)
fix(world-local): skip Nov 2025 ghost versions on npm (#2168)
fix(core,errors): classify SDK encryption failures as RUNTIME_ERROR (#2145)
[web-shared][web] Fix events tab search (#2107)
Version Packages (beta) (#2147)
Allow setting workflow attributes from steps (#2157)
Better search handling on the trace viewer (#2144)
[docs] Document experimental attributes feature (#2141)
Sign up for freeto 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

@VaguelySerious
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); [e2e] Separate event-log-race-repro harness noise from real regressions by VaguelySerious · Pull Request #2190 · vercel/workflow · GitHub
Skip to content

[e2e] Separate event-log-race-repro harness noise from real regressions - #2190

Merged
VaguelySerious merged 1 commit into
mainfrom
peter/event-log-race-repro-classify-infra
Jun 1, 2026
Merged

[e2e] Separate event-log-race-repro harness noise from real regressions#2190
VaguelySerious merged 1 commit into
mainfrom
peter/event-log-race-repro-classify-infra

Conversation

@VaguelySerious

Copy link
Copy Markdown
Member

Summary

The event-log-race-repro job is currently red for the wrong reason. In a recent run, it reported 1231 of 2000 runs "did not complete cleanly" — yet CORRUPTED_EVENT_LOG / USER_ERROR / RUNTIME_ERROR were all 0. The entire count was harness-side noise.

What the other column was

The repro sorts each run into completed, CORRUPTED_EVENT_LOG, USER_ERROR, RUNTIME_ERROR, stuck, or other. Only the three named error codes mapped to their own bucket; everything else fell into other, and the --check gate failed the job on any non-completed run. So other conflated genuine corruption with:

  • HOOK_RESUME_FAILED — the run completed fine, but the harness's own resumeHook() rejected (typically because the sleep branch already finished the run and disposed the hook).
  • NO_WAKE_BRANCH — the run completed but the sleep branch won every iteration, so the wake path was never taken.
  • transport errors / timeouts thrown in the driver, and cancellations.

What was actually going wrong

A timing race in the test harness, not an SDK bug. The workflow's sleep budget is iterations × sleepMs = 5 × 5000 = 25000ms; the harness resumes the hook at resumeDelayMs + rand(resumeJitterMs) = up to 25000ms — the resume ceiling exactly equals the budget. On a fast/warm deployment the workflow exhausts its sleeps before the resume lands, so the resume hits a disposed hook and/or the wake branch is never taken.

The smoking gun: the #2 retry against the same already-warm deployment jumped 767→1231 other while stuck dropped to 0 and the step scenarios stayed perfect. Faster execution = the resume misses the window more often. It also means most "green" runs weren't even exercising the wake-branch shape the repro is meant to stress.

Changes

  1. Reclassify harness-side, non-corruption outcomes into a dedicated non-gating infra bucket (test + renderer). The job now gates only on regression-class outcomes (CORRUPTED_EVENT_LOG / USER_ERROR / RUNTIME_ERROR / stuck / other); infra is reported but never fails the job. The PR comment now reads "No event-log regressions… N runs hit harness-side infra outcomes (… do not fail the job)."
  2. Surface regressions ahead of infra in the failures table so the 20-row cap never hides a real failure behind a flood of timing rows.
  3. Restore wake-branch coverage: raise the default iterations ceiling (5 → 8). Because the run short-circuits via returnOnWake the moment the hook wins, a higher ceiling widens the window for the resume to land before sleep-budget exhaustion at ~no runtime cost. Added a beforeAll guard that warns when the resume ceiling is not below the sleep budget.
  4. Testability: the renderer's pure helpers are now exported and covered by node:test (run via a new lightweight Lint job).

Tests

node --test .github/scripts/**/*.test.js (8 tests) covers: infra is non-gating; regressionCount ignores completed/infra; an all-infra results file (mirroring the production comment) yields 0 regressions; regressions sort ahead of infra; --check exits 0 on infra-only and 1 on a corruption-class outcome.

Note: the full 2000-run repro only runs against a deployment behind the event-log-race-repro label, so the reclassification's end-to-end effect is best confirmed by adding that label to this PR.

🤖 Generated with Claude Code

The event-log-race-repro job classified every non-completed run into an
`other` grab-bag and gated on it. Hook-resume timing races (HOOK_RESUME_FAILED,
NO_WAKE_BRANCH) and transport errors in the repro driver — none of which are
event-log corruption — landed there and failed the job, drowning the signal it
exists to detect.
- Route harness-side, non-corruption outcomes to a dedicated non-gating `infra`
bucket (test + renderer). The job now gates only on regression-class outcomes
(CORRUPTED_EVENT_LOG / USER_ERROR / RUNTIME_ERROR / stuck / other).
- Sort regressions ahead of infra rows so the 20-row cap never hides a real
failure behind a flood of harness-timing rows.
- Raise the default hook/sleep iteration ceiling (5 -> 8). Because the run
short-circuits via returnOnWake the moment the hook wins, this widens the
window for the delayed resume to land before the sleep budget is exhausted,
at ~no runtime cost — restoring the wake-branch coverage the scenario exists
to exercise. Add a beforeAll guard that warns when the resume ceiling is not
below the sleep budget.
- Make the renderer's pure helpers unit-testable and add node:test coverage,
wired into the Lint workflow.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@changeset-bot

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: e100a60

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

This PR includes changesets to release 0 packages

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

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

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

@vercel

vercelBot commented May 31, 2026

Copy link
Copy Markdown
Contributor

@github-actions

github-actionsBot commented May 31, 2026

Copy link
Copy Markdown
Contributor

🧪 E2E Test Results

Some tests failed

Summary

PassedFailedSkippedTotal
❌ ▲ Vercel Production126332191485
❌ 💻 Local Development167012191890
✅ 📦 Local Production167102191890
✅ 🐘 Local Postgres167102191890
✅ 🪟 Windows13500135
❌ 📋 Other7681176945
Total7178510528235

❌ Failed Tests

▲ Vercel Production (3 failed)

express (1 failed):

  • instanceMethodStepWorkflow - instance methods with "use step" directive | wrun_01KSZ4H8N0DE044HA3WQ2AG25H | 🔍 observability

nextjs-webpack (2 failed):

  • AbortController abortHookOrderingWorkflow [listener-first-abort-first]: addEventListener → hook.then → abort() → resumeHook
  • AbortController abortHookOrderingWorkflow [listener-first-hook-first]: addEventListener → hook.then → resumeHook → abort()
💻 Local Development (1 failed)

express-stable (1 failed):

  • hookWithSleepFinalStepWorkflow - step only on final payload | wrun_01KSZ4NB8SC1XKHH9GSXQEKXZR
📋 Other (1 failed)

e2e-vercel-prod-tanstack-start (1 failed):

  • AbortController abortHookOrderingWorkflow [listener-first-abort-first]: addEventListener → hook.then → abort() → resumeHook

Details by Category

❌ ▲ Vercel Production
AppPassedFailedSkipped
✅ astro109026
✅ example109026
❌ express108126
✅ fastify109026
✅ hono109026
✅ nextjs-turbopack13302
❌ nextjs-webpack13122
✅ nitro109026
✅ nuxt109026
✅ sveltekit12807
✅ vite109026
❌ 💻 Local Development
AppPassedFailedSkipped
✅ astro-stable110025
❌ express-stable109125
✅ fastify-stable110025
✅ hono-stable110025
✅ nextjs-turbopack-canary116019
✅ nextjs-turbopack-stable-lazy-discovery-disabled13500
✅ nextjs-turbopack-stable-lazy-discovery-enabled13500
✅ nextjs-webpack-canary116019
✅ nextjs-webpack-stable-lazy-discovery-disabled13500
✅ nextjs-webpack-stable-lazy-discovery-enabled13500
✅ nitro-stable110025
✅ nuxt-stable110025
✅ sveltekit-stable12906
✅ vite-stable110025
✅ 📦 Local Production
AppPassedFailedSkipped
✅ astro-stable110025
✅ express-stable110025
✅ fastify-stable110025
✅ hono-stable110025
✅ nextjs-turbopack-canary116019
✅ nextjs-turbopack-stable-lazy-discovery-disabled13500
✅ nextjs-turbopack-stable-lazy-discovery-enabled13500
✅ nextjs-webpack-canary116019
✅ nextjs-webpack-stable-lazy-discovery-disabled13500
✅ nextjs-webpack-stable-lazy-discovery-enabled13500
✅ nitro-stable110025
✅ nuxt-stable110025
✅ sveltekit-stable12906
✅ vite-stable110025
✅ 🐘 Local Postgres
AppPassedFailedSkipped
✅ astro-stable110025
✅ express-stable110025
✅ fastify-stable110025
✅ hono-stable110025
✅ nextjs-turbopack-canary116019
✅ nextjs-turbopack-stable-lazy-discovery-disabled13500
✅ nextjs-turbopack-stable-lazy-discovery-enabled13500
✅ nextjs-webpack-canary116019
✅ nextjs-webpack-stable-lazy-discovery-disabled13500
✅ nextjs-webpack-stable-lazy-discovery-enabled13500
✅ nitro-stable110025
✅ nuxt-stable110025
✅ sveltekit-stable12906
✅ vite-stable110025
✅ 🪟 Windows
AppPassedFailedSkipped
✅ nextjs-turbopack13500
❌ 📋 Other
AppPassedFailedSkipped
✅ e2e-local-dev-nest-stable110025
✅ e2e-local-dev-tanstack-start-110025
✅ e2e-local-postgres-nest-stable110025
✅ e2e-local-postgres-tanstack-start-110025
✅ e2e-local-prod-nest-stable110025
✅ e2e-local-prod-tanstack-start-110025
❌ e2e-vercel-prod-tanstack-start108126

📋 View full workflow run


Some E2E test jobs failed:

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

Check the workflow run for details.

@github-actions

github-actionsBot commented May 31, 2026

Copy link
Copy Markdown
Contributor

📊 Benchmark Results

📈 Comparing against baseline from main branch. Green 🟢 = faster, Red 🔺 = slower.

workflow with no steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Express0.042s (-5.9% 🟢)1.006s (~)0.964s101.00x
💻 LocalNitro0.045s (+5.3% 🔺)1.006s (~)0.961s101.09x
💻 LocalNext.js (Turbopack)0.059s1.007s0.947s101.42x
🐘 PostgresExpress0.060s (+2.8%)1.012s (~)0.952s101.43x
🐘 PostgresNitro0.062s (-35.2% 🟢)1.012s (-2.9%)0.951s101.48x
🐘 PostgresNext.js (Turbopack)0.071s1.013s0.941s101.71x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express0.304s (+29.2% 🔺)9.230s (+332.2% 🔺)8.926s101.00x
▲ VercelNitro0.467s (+14.0% 🔺)8.212s (+227.3% 🔺)7.745s101.54x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

workflow with 1 step

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Nitro1.090s (-3.6%)2.007s (~)0.917s101.00x
💻 LocalExpress1.094s (-2.8%)2.006s (~)0.912s101.00x
🐘 PostgresNitro1.100s (-3.5%)2.008s (~)0.909s101.01x
🐘 PostgresExpress1.108s (-3.4%)2.011s (~)0.903s101.02x
💻 LocalNext.js (Turbopack)1.137s2.006s0.869s101.04x
🐘 PostgresNext.js (Turbopack)1.154s2.011s0.856s101.06x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro1.951s (-49.9% 🟢)8.918s (+50.9% 🔺)6.967s101.00x
▲ VercelExpress2.816s (+50.2% 🔺)11.043s (+190.0% 🔺)8.227s101.44x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

workflow with 10 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Express10.509s (-3.8%)11.022s (~)0.513s31.00x
🐘 PostgresExpress10.527s (-4.0%)11.018s (~)0.490s31.00x
🐘 PostgresNitro10.543s (-3.0%)11.018s (~)0.475s31.00x
💻 LocalNitro10.549s (-3.6%)11.023s (~)0.475s31.00x
💻 LocalNext.js (Turbopack)10.771s11.022s0.251s31.02x
🐘 PostgresNext.js (Turbopack)10.864s11.019s0.155s31.03x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro13.250s (-44.2% 🟢)17.759s (-29.3% 🟢)4.509s31.00x
▲ VercelExpress18.536s (+9.2% 🔺)25.082s (+25.3% 🔺)6.546s21.40x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

workflow with 25 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro13.713s (-6.0% 🟢)14.018s (-6.7% 🟢)0.304s51.00x
💻 LocalExpress13.737s (-8.2% 🟢)14.027s (-6.7% 🟢)0.290s51.00x
🐘 PostgresExpress13.748s (-5.7% 🟢)14.016s (-6.7% 🟢)0.268s51.00x
💻 LocalNitro13.768s (-8.6% 🟢)14.027s (-12.5% 🟢)0.260s51.00x
💻 LocalNext.js (Turbopack)14.375s15.031s0.656s41.05x
🐘 PostgresNext.js (Turbopack)14.516s15.019s0.503s41.06x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro22.401s (-65.2% 🟢)41.317s (-38.0% 🟢)18.916s21.00x
▲ VercelExpress22.701s (-54.9% 🟢)31.002s (-41.0% 🟢)8.301s21.01x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

workflow with 50 sequential steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro12.332s (-11.7% 🟢)13.018s (-9.0% 🟢)0.687s71.00x
🐘 PostgresExpress12.367s (-11.7% 🟢)13.017s (-10.8% 🟢)0.649s71.00x
💻 LocalExpress12.445s (-25.0% 🟢)13.025s (-23.5% 🟢)0.580s71.01x
💻 LocalNitro12.686s (-24.4% 🟢)13.168s (-22.7% 🟢)0.482s71.03x
💻 LocalNext.js (Turbopack)13.628s14.028s0.400s71.11x
🐘 PostgresNext.js (Turbopack)13.797s14.164s0.367s71.12x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express27.762s (-77.1% 🟢)31.197s (-74.8% 🟢)3.435s31.00x
▲ VercelNitro28.303s (-93.3% 🟢)36.682s (-91.4% 🟢)8.379s31.02x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

Promise.all with 10 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express1.186s (-5.9% 🟢)2.008s (~)0.822s151.00x
💻 LocalExpress1.198s (-19.6% 🟢)2.006s (~)0.808s151.01x
💻 LocalNitro1.206s (-26.1% 🟢)2.007s (-3.2%)0.800s151.02x
🐘 PostgresNitro1.214s (-4.8%)2.007s (~)0.794s151.02x
🐘 PostgresNext.js (Turbopack)1.258s2.007s0.750s151.06x
💻 LocalNext.js (Turbopack)1.347s2.005s0.659s151.14x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express2.716s (-5.0% 🟢)19.336s (+318.3% 🔺)16.620s21.00x
▲ VercelNitro2.825s (~)9.853s (+127.9% 🔺)7.027s41.04x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

Promise.all with 25 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express1.236s (-47.7% 🟢)2.008s (-33.3% 🟢)0.772s151.00x
🐘 PostgresNitro1.255s (-46.6% 🟢)2.007s (-33.3% 🟢)0.752s151.02x
🐘 PostgresNext.js (Turbopack)1.428s2.008s0.579s151.16x
💻 LocalNext.js (Turbopack)1.687s2.074s0.387s151.36x
💻 LocalExpress1.717s (-41.9% 🟢)2.006s (-41.9% 🟢)0.289s151.39x
💻 LocalNitro2.000s (-36.4% 🟢)2.365s (-39.1% 🟢)0.365s141.62x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro3.186s (-21.4% 🟢)11.331s (+91.4% 🔺)8.145s31.00x
▲ VercelExpress6.602s (+82.4% 🔺)18.243s (+257.0% 🔺)11.642s32.07x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

Promise.all with 50 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express1.383s (-60.3% 🟢)2.007s (-50.0% 🟢)0.624s151.00x
🐘 PostgresNitro1.398s (-59.8% 🟢)2.007s (-49.9% 🟢)0.609s151.01x
🐘 PostgresNext.js (Turbopack)1.735s2.315s0.580s131.25x
💻 LocalNext.js (Turbopack)4.602s5.298s0.696s73.33x
💻 LocalExpress4.827s (-42.1% 🟢)5.514s (-38.9% 🟢)0.687s63.49x
💻 LocalNitro6.170s (-26.1% 🟢)6.617s (-26.6% 🟢)0.447s54.46x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express5.289s (+24.7% 🔺)7.700s (+25.7% 🔺)2.411s41.00x
▲ VercelNitro5.461s (+54.9% 🔺)11.366s (+105.4% 🔺)5.905s31.03x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

Promise.race with 10 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.178s (-6.3% 🟢)2.009s (~)0.831s151.00x
🐘 PostgresExpress1.193s (-5.1% 🟢)2.008s (~)0.815s151.01x
🐘 PostgresNext.js (Turbopack)1.249s2.009s0.760s151.06x
💻 LocalNext.js (Turbopack)1.407s2.006s0.599s151.19x
💻 LocalExpress1.456s (-23.1% 🟢)2.007s (-15.1% 🟢)0.551s151.24x
💻 LocalNitro1.681s (-9.9% 🟢)2.073s (-11.4% 🟢)0.392s151.43x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express2.482s (-3.8%)8.298s (+90.8% 🔺)5.816s41.00x
▲ VercelNitro2.653s (+7.9% 🔺)5.245s (+25.8% 🔺)2.592s61.07x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

Promise.race with 25 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.242s (-46.9% 🟢)2.009s (-33.3% 🟢)0.767s151.00x
🐘 PostgresExpress1.261s (-46.1% 🟢)2.010s (-33.3% 🟢)0.748s151.02x
🐘 PostgresNext.js (Turbopack)1.403s2.008s0.605s151.13x
💻 LocalExpress1.970s (-37.1% 🟢)2.392s (-36.4% 🟢)0.423s131.59x
💻 LocalNext.js (Turbopack)2.017s2.591s0.574s121.62x
💻 LocalNitro2.086s (-31.9% 🟢)2.591s (-33.3% 🟢)0.505s121.68x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro3.436s (+6.3% 🔺)10.457s (+106.0% 🔺)7.020s31.00x
▲ VercelExpress3.725s (+16.7% 🔺)8.451s (+76.3% 🔺)4.726s41.08x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

Promise.race with 50 concurrent steps

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.382s (-60.3% 🟢)2.008s (-49.9% 🟢)0.626s151.00x
🐘 PostgresExpress1.385s (-60.4% 🟢)2.008s (-49.9% 🟢)0.622s151.00x
🐘 PostgresNext.js (Turbopack)1.746s2.156s0.411s141.26x
💻 LocalExpress4.650s (-47.2% 🟢)5.180s (-44.1% 🟢)0.530s63.36x
💻 LocalNext.js (Turbopack)5.127s5.683s0.557s63.71x
💻 LocalNitro5.886s (-35.6% 🟢)6.413s (-36.0% 🟢)0.527s54.26x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro6.106s (+19.9% 🔺)10.232s (+50.1% 🔺)4.125s51.00x
▲ VercelExpress10.634s (+65.7% 🔺)15.236s (+86.3% 🔺)4.602s21.74x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

workflow with 10 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express0.565s (-32.6% 🟢)1.007s (-1.6%)0.442s601.00x
💻 LocalExpress0.578s (-41.3% 🟢)1.005s (-6.6% 🟢)0.427s601.02x
🐘 PostgresNitro0.593s (-27.7% 🟢)1.040s (+3.4%)0.447s591.05x
💻 LocalNitro0.697s (-29.0% 🟢)1.096s (~)0.399s551.23x
🐘 PostgresNext.js (Turbopack)0.837s1.007s0.170s601.48x
💻 LocalNext.js (Turbopack)0.868s1.004s0.136s601.54x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro4.851s (-78.0% 🟢)7.522s (-68.7% 🟢)2.672s81.00x
▲ VercelExpress4.974s (-73.8% 🟢)12.581s (-41.0% 🟢)7.606s61.03x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

workflow with 25 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express1.325s (-33.0% 🟢)2.008s (-11.1% 🟢)0.682s451.00x
🐘 PostgresNitro1.351s (-29.9% 🟢)2.030s (-3.4%)0.679s451.02x
💻 LocalNitro1.510s (-50.3% 🟢)2.006s (-46.6% 🟢)0.497s451.14x
💻 LocalExpress1.515s (-49.8% 🟢)2.006s (-44.1% 🟢)0.491s451.14x
🐘 PostgresNext.js (Turbopack)2.084s2.468s0.384s371.57x
💻 LocalNext.js (Turbopack)2.112s3.008s0.896s301.59x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express12.360s (-64.2% 🟢)17.479s (-52.5% 🟢)5.119s61.00x
▲ VercelNitro12.401s (-68.6% 🟢)15.005s (-63.7% 🟢)2.605s71.00x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

workflow with 50 sequential data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro2.594s (-36.8% 🟢)3.033s (-34.1% 🟢)0.439s401.00x
🐘 PostgresExpress2.702s (-32.3% 🟢)3.137s (-28.2% 🟢)0.434s391.04x
💻 LocalNitro3.229s (-65.3% 🟢)4.009s (-60.0% 🟢)0.780s301.24x
💻 LocalExpress3.324s (-63.9% 🟢)4.043s (-59.6% 🟢)0.719s301.28x
🐘 PostgresNext.js (Turbopack)3.925s4.010s0.085s301.51x
💻 LocalNext.js (Turbopack)4.452s5.052s0.601s241.72x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro25.276s (-73.9% 🟢)30.878s (-68.6% 🟢)5.602s41.00x
▲ VercelExpress26.350s (-79.7% 🟢)32.626s (-75.3% 🟢)6.276s41.04x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

workflow with 10 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.217s (-23.3% 🟢)1.006s (~)0.788s601.00x
🐘 PostgresExpress0.227s (-19.6% 🟢)1.006s (~)0.779s601.05x
🐘 PostgresNext.js (Turbopack)0.305s1.023s0.719s591.40x
💻 LocalNitro0.424s (-29.9% 🟢)1.004s (-1.7%)0.581s601.95x
💻 LocalExpress0.441s (-21.3% 🟢)1.004s (~)0.563s602.03x
💻 LocalNext.js (Turbopack)0.627s1.022s0.395s592.89x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express2.394s (+22.5% 🔺)12.031s (+230.8% 🔺)9.638s51.00x
▲ VercelNitro3.625s (+118.3% 🔺)10.359s (+209.1% 🔺)6.733s61.51x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

workflow with 25 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.339s (-31.7% 🟢)1.006s (~)0.668s901.00x
🐘 PostgresExpress0.361s (-29.1% 🟢)1.006s (~)0.645s901.07x
🐘 PostgresNext.js (Turbopack)0.515s1.007s0.492s901.52x
💻 LocalNitro2.152s (-15.2% 🟢)2.638s (-12.3% 🟢)0.486s356.35x
💻 LocalExpress2.471s (-1.7%)2.979s (-1.0%)0.508s317.29x
💻 LocalNext.js (Turbopack)2.513s3.225s0.712s287.42x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro4.568s (+41.6% 🔺)10.630s (+120.5% 🔺)6.062s91.00x
▲ VercelExpress5.640s (+85.1% 🔺)10.451s (+117.4% 🔺)4.811s101.23x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Nitro | Express

workflow with 50 concurrent data payload steps (10KB)

💻 Local Development

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro0.683s (-13.6% 🟢)1.006s (~)0.323s1201.00x
🐘 PostgresExpress0.705s (-13.9% 🟢)1.015s (~)0.310s1191.03x
🐘 PostgresNext.js (Turbopack)1.048s1.960s0.912s621.53x
💻 LocalNitro9.742s (-12.9% 🟢)10.277s (-11.9% 🟢)0.534s1214.27x
💻 LocalNext.js (Turbopack)10.810s11.575s0.766s1115.83x
💻 LocalExpress11.232s (~)11.856s (-0.7%)0.624s1116.45x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express13.763s (+85.5% 🔺)17.466s (+88.9% 🔺)3.702s71.00x
▲ VercelNitro15.302s (+98.1% 🔺)21.654s (+130.4% 🔺)6.352s61.11x
▲ VercelNext.js (Turbopack)⚠️missing----

🔍 Observability: Express | Nitro

Stream Benchmarks(includes TTFB metrics)
workflow with stream

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.156s (+463.8% 🔺)2.000s (+100.1% 🔺)0.001s (-6.7% 🟢)2.010s (+98.8% 🔺)0.855s101.00x
💻 LocalExpress1.163s (+484.4% 🔺)2.005s (+99.6% 🔺)0.011s (-13.2% 🟢)2.018s (+98.2% 🔺)0.854s101.01x
💻 LocalNitro1.165s (+445.3% 🔺)2.005s (+99.6% 🔺)0.012s (-0.8%)2.020s (+98.2% 🔺)0.854s101.01x
🐘 PostgresExpress1.169s (+469.8% 🔺)1.995s (+99.8% 🔺)0.001s (-31.3% 🟢)2.010s (+98.7% 🔺)0.841s101.01x
💻 LocalNext.js (Turbopack)1.214s2.003s0.011s2.017s0.804s101.05x
🐘 PostgresNext.js (Turbopack)1.233s2.003s0.001s2.012s0.779s101.07x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express2.318s (-7.5% 🟢)6.376s (+55.9% 🔺)1.539s (+60.1% 🔺)8.459s (+51.3% 🔺)6.140s101.00x
▲ VercelNitro3.129s (-18.4% 🟢)6.747s (+27.9% 🔺)1.486s (+100.3% 🔺)9.559s (+47.4% 🔺)6.431s101.35x
▲ VercelNext.js (Turbopack)⚠️missing-----

🔍 Observability: Express | Nitro

stream pipeline with 5 transform steps (1MB)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
💻 Local🥇 Nitro1.584s (+88.9% 🔺)2.010s (+98.6% 🔺)0.011s (+14.5% 🔺)2.022s (+81.2% 🔺)0.438s301.00x
🐘 PostgresNitro1.588s (+154.4% 🔺)2.007s (+99.4% 🔺)0.004s (-9.7% 🟢)2.026s (+98.1% 🔺)0.438s301.00x
🐘 PostgresExpress1.621s (+157.3% 🔺)2.001s (+98.8% 🔺)0.004s (~)2.027s (+98.1% 🔺)0.406s301.02x
💻 LocalExpress1.722s (+127.5% 🔺)2.043s (+98.6% 🔺)0.013s (+36.7% 🔺)2.059s (+98.0% 🔺)0.336s301.09x
🐘 PostgresNext.js (Turbopack)1.809s2.011s0.004s2.029s0.220s301.14x
💻 LocalNext.js (Turbopack)1.917s2.008s0.010s2.201s0.284s281.21x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express6.501s (~)13.670s (+70.7% 🔺)0.154s (-62.3% 🟢)14.972s (+69.5% 🔺)8.471s51.00x
▲ VercelNitro7.642s (-74.0% 🟢)7.694s (-75.0% 🟢)0.328s (+192.9% 🔺)10.227s (-67.8% 🟢)2.585s61.18x
▲ VercelNext.js (Turbopack)⚠️missing-----

🔍 Observability: Express | Nitro

10 parallel streams (1MB each)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Express0.699s (-27.3% 🟢)1.012s (-20.8% 🟢)0.000s (-22.0% 🟢)1.027s (-21.4% 🟢)0.328s591.00x
🐘 PostgresNitro0.704s (-27.3% 🟢)1.015s (-18.6% 🟢)0.000s (+22.0% 🔺)1.032s (-18.0% 🟢)0.328s591.01x
🐘 PostgresNext.js (Turbopack)0.835s1.091s0.000s1.099s0.264s551.19x
💻 LocalNitro1.375s (+12.5% 🔺)2.013s (~)0.000s (+100.0% 🔺)2.015s (~)0.640s301.97x
💻 LocalNext.js (Turbopack)1.497s2.013s0.001s2.016s0.520s302.14x
💻 LocalExpress1.602s (+30.8% 🔺)2.018s (~)0.000s (-40.0% 🟢)2.020s (~)0.418s302.29x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Nitro3.997s (+31.0% 🔺)8.575s (+95.2% 🔺)0.000s (-100.0% 🟢)9.792s (+103.6% 🔺)5.796s71.00x
▲ VercelExpress5.270s (+40.9% 🔺)8.952s (+75.4% 🔺)0.001s (+358.3% 🔺)10.718s (+93.8% 🔺)5.448s61.32x
▲ VercelNext.js (Turbopack)⚠️missing-----

🔍 Observability: Nitro | Express

fan-out fan-in 10 streams (1MB each)

💻 Local Development

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
🐘 Postgres🥇 Nitro1.409s (-21.3% 🟢)2.142s (~)0.000s (-100.0% 🟢)2.154s (-0.9%)0.745s281.00x
🐘 PostgresExpress1.513s (-14.6% 🟢)2.174s (~)0.000s (+Infinity% 🔺)2.189s (~)0.677s281.07x
🐘 PostgresNext.js (Turbopack)1.650s2.145s0.000s2.162s0.512s281.17x
💻 LocalNitro3.097s (-8.6% 🟢)3.775s (-6.4% 🟢)0.001s (+40.6% 🔺)3.777s (-6.4% 🟢)0.681s162.20x
💻 LocalNext.js (Turbopack)3.186s3.674s0.000s3.678s0.492s172.26x
💻 LocalExpress3.351s (-3.4%)4.028s (~)0.001s (+41.7% 🔺)4.032s (~)0.681s152.38x

▲ Production (Vercel)

WorldFrameworkWorkflow TimeTTFBSlurpWall TimeOverheadSamplesvs Fastest
▲ Vercel🥇 Express5.775s (+25.9% 🔺)12.656s (+110.2% 🔺)0.001s (+Infinity% 🔺)15.088s (+133.7% 🔺)9.313s41.00x
▲ VercelNitro5.828s (+42.4% 🔺)17.093s (+218.1% 🔺)0.000s (-100.0% 🟢)17.759s (+206.5% 🔺)11.931s41.01x
▲ VercelNext.js (Turbopack)⚠️missing-----

🔍 Observability: Express | Nitro

Summary

Fastest Framework by World

Winner determined by most benchmark wins

World🥇 Fastest FrameworkWins
💻 LocalExpress9/21
🐘 PostgresNitro13/21
▲ VercelExpress11/21
Fastest World by Framework

Winner determined by most benchmark wins

Framework🥇 Fastest WorldWins
Express🐘 Postgres16/21
Next.js (Turbopack)🐘 Postgres15/21
Nitro🐘 Postgres17/21
Column Definitions
  • Workflow Time: Runtime reported by workflow (completedAt - createdAt) - primary metric
  • TTFB: Time to First Byte - time from workflow start until first stream byte received (stream benchmarks only)
  • Slurp: Time from first byte to complete stream consumption (stream benchmarks only)
  • Wall Time: Total testbench time (trigger workflow + poll for result)
  • Overhead: Testbench overhead (Wall Time - Workflow Time)
  • Samples: Number of benchmark iterations run
  • vs Fastest: How much slower compared to the fastest configuration for this benchmark

Worlds:

  • 💻 Local: In-memory filesystem world (local development)
  • 🐘 Postgres: PostgreSQL database world (local development)
  • ▲ Vercel: Vercel production/preview deployment
  • 🌐 Turso: Community world (local development)
  • 🌐 MongoDB: Community world (local development)
  • 🌐 Redis: Community world (local development)
  • 🌐 Jazz: Community world (local development)
  • 🌐 Redis: Community world (local development)
  • 🌐 Redis + BullMQ: Community world (local development)
  • 🌐 Cloudflare: Community world (local development)
  • 🌐 MySQL: Community world (local development)
  • 🌐 Azure: Community world (local development)
  • 🌐 NATS JetStream: Community world (local development)
  • 🌐 Upstash: Community world (local development)

📋 View full workflow run


Some benchmark jobs failed:

  • Local: success
  • Postgres: success
  • Vercel: failure

Check the workflow run for details.

@VaguelySerious
VaguelySerious marked this pull request as ready for review June 1, 2026 09:06
@VaguelySerious
VaguelySerious requested a review from a team as a code ownerJune 1, 2026 09:06
@VaguelySerious
VaguelySerious merged commit ae3c833 into mainJun 1, 2026
112 of 122 checks passed
@VaguelySerious
VaguelySerious deleted the peter/event-log-race-repro-classify-infra branch June 1, 2026 09:07
VaguelySerious added a commit that referenced this pull request Jun 1, 2026
(cherry picked from commit ae3c833)
(cherry picked from commit c1d7bab)
pranaygp added a commit that referenced this pull request Jun 2, 2026
* origin/main:
[world-vercel] Retry transient response-body parse failures in the HTTP client (#2204)
Add virtualization to the trace viewer (#2205)
Trace viewer: scroll-load events past an auto-load cap (#2200)
fix(core): resolve forwarded stream keys across deployments (#2191)
[e2e] Improve error labeling in event-log-race-repro CI job (#2190)
[core] Harden event pagination response parsing (#2180) (#2179)
Add loading skeleton to the new trace viewer (#2164)
Add tooltip components + apply on up/down detail pane (#2163)
fix(swc-plugin): allow wasm host imports during link (#2174)
[test] Forward-port reused-sleep replay divergence test (#2172)
[e2e] Add `event-log-race-repro` label for triggering CI stress-test (#2159)
Version Packages (beta) (#2162)
fix(world-local): skip Nov 2025 ghost versions on npm (#2168)
fix(core,errors): classify SDK encryption failures as RUNTIME_ERROR (#2145)
[web-shared][web] Fix events tab search (#2107)
Version Packages (beta) (#2147)
Allow setting workflow attributes from steps (#2157)
Better search handling on the trace viewer (#2144)
[docs] Document experimental attributes feature (#2141)
Sign up for freeto 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

@VaguelySerious