Skip to content

[.github] Point manual-backport instructions at the input the dialog shows - #3720

Draft
VaguelySerious wants to merge 1 commit into
mainfrom
peter/backport-dispatch-instructions
Draft

[.github] Point manual-backport instructions at the input the dialog shows#3720
VaguelySerious wants to merge 1 commit into
mainfrom
peter/backport-dispatch-instructions

Conversation

@VaguelySerious

Copy link
Copy Markdown
Member

Draft. The manual-backport instructions the workflow posts on PRs point at a field the Run workflow dialog does not have, and promise more than a forced dispatch delivers.

What was wrong

1. The input is named by something the UI never shows. Both comments said "paste this commit SHA into the ref input". ref is the input's YAML name; GitHub labels workflow_dispatch fields with their description, so no field called "ref" is visible. The one visibly ref-named control in that dialog is "Use workflow from", which picks which branch the workflow file is read from and rejects a raw SHA. Now named by its visible label, with an explicit "not the branch selector".

2. "Once the underlying issue is fixed, re-run" is wrong advice when the AI side is the failure. A manual dispatch forces the AI decision to yes (Decide whether to backport short-circuits on force_backport). It does not skip AI conflict resolution: Resolve conflicts with opencode is gated only on steps.cherry-pick.outputs.status == 'conflict'. So for a commit that does not apply cleanly, re-dispatching during an AI Gateway outage lands on the identical error.

That is exactly what happened. Every Backport to stable run since 2026-08-21 18:31 fails with API key budget exceeded. Current spend: $10001.21, limit: $10000.00the push run at Decide whether to backport, and the forced dispatch at Resolve conflicts with opencode after correctly resolving the pasted SHA and cherry-picking. The comment sent the reader back to a button that could not work.

3. The manual recipe was unreachable from an infra failure. It lives in Comment on conflict failure, which requires ai-resolve.outputs.resolved == 'false' — a step that exited non-zero sets no outputs, so an infra failure never posts it. The failure comment now carries the recipe itself, and lists an out-of-budget key among the likely causes.

Verification

Rendered both comment bodies by extracting the github-script blocks and running them against stubbed github/context (the YAML-plus-template-literal escaping of backticks and \ continuations is the part worth checking, and it comes out correct). All five script blocks in the file still parse.

The AI Gateway budget itself is not something this PR fixes: the key needs its limit raised before the workflow can back-port anything that conflicts.

Related: #3718 and #3719 back-port #3406 and #3700 to stable by hand, which is what the recipe added here describes.

…shows

The backport workflow's PR comments told people to "paste this commit SHA
into the `ref` input". `ref` is the input's YAML name and appears nowhere in
the Run workflow dialog, which labels inputs by their description. The one
visibly ref-named control there is "Use workflow from", which selects the
branch the workflow file is read from and rejects a raw SHA.

Name the field by its visible label instead, and say which control it is not.

Also correct what a manual dispatch actually buys you. A forced run skips the
AI *decision*; it does not skip AI *conflict resolution*, which runs
unconditionally whenever the cherry-pick conflicts. So "once the underlying
issue is fixed, re-run" was the wrong advice for the failure that prompted
this: every run since 2026-08-21 18:31 died on `API key budget exceeded` from
the AI Gateway, including a forced dispatch that resolved its SHA and
cherry-picked correctly before hitting the same wall. The failure comment now
lists an out-of-budget key among the causes and carries the manual cherry-pick
recipe, which previously lived only in the conflict comment that an infra
failure never reaches.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@changeset-bot

changeset-bot Bot commented Aug 21, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 2a2ff2b

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

vercel Bot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

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

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

@github-actions

github-actions Bot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

🧪 E2E Test Results

Some tests failed

❌ Failed E2E Tests

▲ Vercel Production (251 failed)

astro-node (8 failed):

  • hookCleanupTestWorkflow - hook token reuse after workflow completion | wrun_41M0K0DXC20GH99R88CSP2GVTH | 🔍 observability
  • hookGetConflictWorkflow - hook.getConflict() resolves with the conflicting run when token is already registered | wrun_41M0K0E3VP0GZ1CE8ZQNYW4XS6 | 🔍 observability
  • hookMinRetentionWorkflow - terminal Hook cannot resume and its token stays unavailable | wrun_41M0K0EY610GNRKRWYJXWFVR19 | 🔍 observability
  • setAttributes start: initial attributes are seeded on run creation
  • setAttributes start: reserved-prefix initial attributes are seeded with allowReservedAttributes
  • setAttributes setAttributesWorkflow: workflow-body calls append native attr_set events and merge correctly
  • setAttributes fire-and-forget: void setAttributes lands without awaiting
  • setAttributes validation DX: invalid writes throw catchable FatalErrors naming rule and limit

astro-quickjs (11 failed):

  • hookCleanupTestWorkflow - hook token reuse after workflow completion | wrun_41M0K0DXC20GH99R88CSP2GVTH | 🔍 observability
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_41M0K0CYV50GJ8ZT86A2090BR6 | 🔍 observability
  • hookGetConflictWorkflow - hook.getConflict() resolves with the conflicting run when token is already registered | wrun_41M0K0E3VP0GZ1CE8ZQNYW4XS6 | 🔍 observability
  • hookMinRetentionWorkflow - terminal Hook cannot resume and its token stays unavailable | wrun_41M0K0EY610GNRKRWYJXWFVR19 | 🔍 observability
  • AbortController abortAnyInStepWorkflow: AbortSignal.any inside a step composes deserialized signals
  • setAttributes start: initial attributes are seeded on run creation
  • setAttributes start: reserved-prefix initial attributes are seeded with allowReservedAttributes
  • setAttributes setAttributesWorkflow: workflow-body calls append native attr_set events and merge correctly
  • setAttributes fire-and-forget: void setAttributes lands without awaiting
  • setAttributes Promise.all of disjoint-key writes: every key lands
  • setAttributes workflow throws after awaited setAttributes: attribute still persists on the failed run

example-node (10 failed):

  • hookCleanupTestWorkflow - hook token reuse after workflow completion | wrun_41M0K0DXC20GH99R88CSP2GVTH | 🔍 observability
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_41M0K0CYV50GJ8ZT86A2090BR6 | 🔍 observability
  • hookGetConflictWorkflow - hook.getConflict() resolves with the conflicting run when token is already registered | wrun_41M0K0E3VP0GZ1CE8ZQNYW4XS6 | 🔍 observability
  • hookMinRetentionWorkflow - terminal Hook cannot resume and its token stays unavailable | wrun_41M0K0EY610GNRKRWYJXWFVR19 | 🔍 observability
  • setAttributes start: initial attributes are seeded on run creation
  • setAttributes start: reserved-prefix initial attributes are seeded with allowReservedAttributes
  • setAttributes setAttributesWorkflow: workflow-body calls append native attr_set events and merge correctly
  • setAttributes fire-and-forget: void setAttributes lands without awaiting
  • setAttributes workflow throws after awaited setAttributes: attribute still persists on the failed run
  • setAttributes validation DX: invalid writes throw catchable FatalErrors naming rule and limit

example-quickjs (9 failed):

  • hookCleanupTestWorkflow - hook token reuse after workflow completion | wrun_41M0K0DXC20GH99R88CSP2GVTH | 🔍 observability
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_41M0K0CYV50GJ8ZT86A2090BR6 | 🔍 observability
  • hookGetConflictWorkflow - hook.getConflict() resolves with the conflicting run when token is already registered | wrun_41M0K0E3VP0GZ1CE8ZQNYW4XS6 | 🔍 observability
  • hookMinRetentionWorkflow - terminal Hook cannot resume and its token stays unavailable | wrun_41M0K0EY610GNRKRWYJXWFVR19 | 🔍 observability
  • setAttributes start: initial attributes are seeded on run creation
  • setAttributes setAttributesWorkflow: workflow-body calls append native attr_set events and merge correctly
  • setAttributes setAttributesInsideStepWorkflow: step-body calls append attributed native events
  • setAttributes fire-and-forget: void setAttributes lands without awaiting
  • setAttributes validation DX: invalid writes throw catchable FatalErrors naming rule and limit

express-node (7 failed):

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

express-quickjs (10 failed):

  • hookCleanupTestWorkflow - hook token reuse after workflow completion | wrun_41M0K0DXC20GH99R88CSP2GVTH | 🔍 observability
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_41M0K0CYV50GJ8ZT86A2090BR6 | 🔍 observability
  • hookGetConflictWorkflow - hook.getConflict() resolves with the conflicting run when token is already registered | wrun_41M0K0E3VP0GZ1CE8ZQNYW4XS6 | 🔍 observability
  • AbortController abortThrowIfAbortedMidFlightWorkflow: throwIfAborted in a polling loop bails when abort fires
  • setAttributes start: initial attributes are seeded on run creation
  • setAttributes start: reserved-prefix initial attributes are seeded with allowReservedAttributes
  • setAttributes setAttributesWorkflow: workflow-body calls append native attr_set events and merge correctly
  • setAttributes setAttributesInsideStepWorkflow: step-body calls append attributed native events
  • setAttributes fire-and-forget: void setAttributes lands without awaiting
  • setAttributes validation DX: invalid writes throw catchable FatalErrors naming rule and limit

fastify-node (10 failed):

  • hookCleanupTestWorkflow - hook token reuse after workflow completion | wrun_41M0K0DXC20GH99R88CSP2GVTH | 🔍 observability
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_41M0K0CYV50GJ8ZT86A2090BR6 | 🔍 observability
  • hookGetConflictWorkflow - hook.getConflict() resolves with the conflicting run when token is already registered | wrun_41M0K0E3VP0GZ1CE8ZQNYW4XS6 | 🔍 observability
  • hookMinRetentionWorkflow - terminal Hook cannot resume and its token stays unavailable | wrun_41M0K0EY610GNRKRWYJXWFVR19 | 🔍 observability
  • hookAdoptOwnerResultWorkflow - duplicate adopts the owner result via conflict.returnValue | wrun_41M0K0E8TR0GKR0MYPXYED5H8T | 🔍 observability
  • distributedAbortController - manual abort triggers signal | wrun_41M0K0PQ190GTFC8JWMFV99VHF | 🔍 observability
  • setAttributes start: initial attributes are seeded on run creation
  • setAttributes start: reserved-prefix initial attributes are seeded with allowReservedAttributes
  • setAttributes setAttributesWorkflow: workflow-body calls append native attr_set events and merge correctly
  • setAttributes fire-and-forget: void setAttributes lands without awaiting

fastify-quickjs (10 failed):

  • hookCleanupTestWorkflow - hook token reuse after workflow completion | wrun_41M0K0DXC20GH99R88CSP2GVTH | 🔍 observability
  • hookGetConflictWorkflow - hook.getConflict() resolves with the conflicting run when token is already registered | wrun_41M0K0E3VP0GZ1CE8ZQNYW4XS6 | 🔍 observability
  • hookMinRetentionWorkflow - terminal Hook cannot resume and its token stays unavailable | wrun_41M0K0EY610GNRKRWYJXWFVR19 | 🔍 observability
  • AbortController abortDeterministicBranchFromStepWorkflow: branches stay consistent when abort comes from a step
  • setAttributes start: initial attributes are seeded on run creation
  • setAttributes setAttributesWorkflow: workflow-body calls append native attr_set events and merge correctly
  • setAttributes setAttributesInsideStepWorkflow: step-body calls append attributed native events
  • setAttributes fire-and-forget: void setAttributes lands without awaiting
  • setAttributes Promise.all of disjoint-key writes: every key lands
  • setAttributes validation DX: invalid writes throw catchable FatalErrors naming rule and limit

hono-node (9 failed):

  • hookCleanupTestWorkflow - hook token reuse after workflow completion | wrun_41M0K0DXC20GH99R88CSP2GVTH | 🔍 observability
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_41M0K0CYV50GJ8ZT86A2090BR6 | 🔍 observability
  • hookGetConflictWorkflow - hook.getConflict() resolves with the conflicting run when token is already registered | wrun_41M0K0E3VP0GZ1CE8ZQNYW4XS6 | 🔍 observability
  • hookMinRetentionWorkflow - terminal Hook cannot resume and its token stays unavailable | wrun_41M0K0EY610GNRKRWYJXWFVR19 | 🔍 observability
  • hookAdoptOwnerResultWorkflow - duplicate adopts the owner result via conflict.returnValue | wrun_41M0K0E8TR0GKR0MYPXYED5H8T | 🔍 observability
  • resume-or-start route pattern - resumeHook retried after start() reaches the new run | wrun_41M0K0J1PC0GJG8803GDMK7QSK | 🔍 observability
  • setAttributes start: reserved-prefix initial attributes are seeded with allowReservedAttributes
  • setAttributes setAttributesWorkflow: workflow-body calls append native attr_set events and merge correctly
  • setAttributes fire-and-forget: void setAttributes lands without awaiting

hono-quickjs (13 failed):

  • hookCleanupTestWorkflow - hook token reuse after workflow completion | wrun_41M0K0DXC20GH99R88CSP2GVTH | 🔍 observability
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_41M0K0CYV50GJ8ZT86A2090BR6 | 🔍 observability
  • hookGetConflictWorkflow - hook.getConflict() resolves with the conflicting run when token is already registered | wrun_41M0K0E3VP0GZ1CE8ZQNYW4XS6 | 🔍 observability
  • hookMinRetentionWorkflow - terminal Hook cannot resume and its token stays unavailable | wrun_41M0K0EY610GNRKRWYJXWFVR19 | 🔍 observability
  • AbortController abortFromStepWorkflow: step abort cancels an in-flight sibling step
  • AbortController abortListenerWorkflow: signal.addEventListener fires on the deserialized step signal
  • AbortController abortThrowIfAbortedMidFlightWorkflow: throwIfAborted in a polling loop bails when abort fires
  • setAttributes start: initial attributes are seeded on run creation
  • setAttributes start: reserved-prefix initial attributes are seeded with allowReservedAttributes
  • setAttributes setAttributesWorkflow: workflow-body calls append native attr_set events and merge correctly
  • setAttributes fire-and-forget: void setAttributes lands without awaiting
  • setAttributes Promise.all of disjoint-key writes: every key lands
  • setAttributes workflow throws after awaited setAttributes: attribute still persists on the failed run

nest-node (8 failed):

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

nest-quickjs (10 failed):

  • hookCleanupTestWorkflow - hook token reuse after workflow completion | wrun_41M0K0DXC20GH99R88CSP2GVTH | 🔍 observability
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_41M0K0CYV50GJ8ZT86A2090BR6 | 🔍 observability
  • hookGetConflictWorkflow - hook.getConflict() resolves with the conflicting run when token is already registered | wrun_41M0K0E3VP0GZ1CE8ZQNYW4XS6 | 🔍 observability
  • AbortController abortFromStepWorkflow: step abort cancels an in-flight sibling step
  • AbortController abortAnyInStepWorkflow: AbortSignal.any inside a step composes deserialized signals
  • AbortController abortThrowIfAbortedMidFlightWorkflow: throwIfAborted in a polling loop bails when abort fires
  • setAttributes start: initial attributes are seeded on run creation
  • setAttributes setAttributesWorkflow: workflow-body calls append native attr_set events and merge correctly
  • setAttributes setAttributesInsideStepWorkflow: step-body calls append attributed native events
  • setAttributes fire-and-forget: void setAttributes lands without awaiting

nextjs-turbopack-node (4 failed):

  • hookCleanupTestWorkflow - hook token reuse after workflow completion | wrun_41M0K0DXC20GH99R88CSP2GVTH | 🔍 observability
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_41M0K0CYV50GJ8ZT86A2090BR6 | 🔍 observability
  • setAttributes start: reserved-prefix initial attributes are seeded with allowReservedAttributes
  • setAttributes fire-and-forget: void setAttributes lands without awaiting

nextjs-turbopack-quickjs (10 failed):

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

nextjs-webpack-node (7 failed):

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

nextjs-webpack-quickjs (9 failed):

  • hookCleanupTestWorkflow - hook token reuse after workflow completion | wrun_41M0K0DXC20GH99R88CSP2GVTH | 🔍 observability
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_41M0K0CYV50GJ8ZT86A2090BR6 | 🔍 observability
  • hookGetConflictWorkflow - hook.getConflict() resolves with the conflicting run when token is already registered | wrun_41M0K0E3VP0GZ1CE8ZQNYW4XS6 | 🔍 observability
  • hookMinRetentionWorkflow - terminal Hook cannot resume and its token stays unavailable | wrun_41M0K0EY610GNRKRWYJXWFVR19 | 🔍 observability
  • AbortController abortFromStepWorkflow: step abort cancels an in-flight sibling step
  • AbortController abortDeterministicBranchFromStepWorkflow: branches stay consistent when abort comes from a step
  • setAttributes start: initial attributes are seeded on run creation
  • setAttributes start: reserved-prefix initial attributes are seeded with allowReservedAttributes
  • setAttributes setAttributesWorkflow: workflow-body calls append native attr_set events and merge correctly

nitro-node (10 failed):

  • hookCleanupTestWorkflow - hook token reuse after workflow completion | wrun_41M0K0DXC20GH99R88CSP2GVTH | 🔍 observability
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_41M0K0CYV50GJ8ZT86A2090BR6 | 🔍 observability
  • hookGetConflictWorkflow - hook.getConflict() resolves with the conflicting run when token is already registered | wrun_41M0K0E3VP0GZ1CE8ZQNYW4XS6 | 🔍 observability
  • hookMinRetentionWorkflow - terminal Hook cannot resume and its token stays unavailable | wrun_41M0K0EY610GNRKRWYJXWFVR19 | 🔍 observability
  • resume-or-start route pattern - resumeHook retried after start() reaches the new run | wrun_41M0K0J1PC0GJG8803GDMK7QSK | 🔍 observability
  • setAttributes start: initial attributes are seeded on run creation
  • setAttributes start: reserved-prefix initial attributes are seeded with allowReservedAttributes
  • setAttributes setAttributesWorkflow: workflow-body calls append native attr_set events and merge correctly
  • setAttributes setAttributesInsideStepWorkflow: step-body calls append attributed native events
  • setAttributes fire-and-forget: void setAttributes lands without awaiting

nitro-quickjs (11 failed):

  • hookCleanupTestWorkflow - hook token reuse after workflow completion | wrun_41M0K0DXC20GH99R88CSP2GVTH | 🔍 observability
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_41M0K0CYV50GJ8ZT86A2090BR6 | 🔍 observability
  • hookGetConflictWorkflow - hook.getConflict() resolves with the conflicting run when token is already registered | wrun_41M0K0E3VP0GZ1CE8ZQNYW4XS6 | 🔍 observability
  • AbortController abortThrowIfAbortedMidFlightWorkflow: throwIfAborted in a polling loop bails when abort fires
  • setAttributes start: initial attributes are seeded on run creation
  • setAttributes start: reserved-prefix initial attributes are seeded with allowReservedAttributes
  • setAttributes setAttributesWorkflow: workflow-body calls append native attr_set events and merge correctly
  • setAttributes setAttributesInsideStepWorkflow: step-body calls append attributed native events
  • setAttributes fire-and-forget: void setAttributes lands without awaiting
  • setAttributes workflow throws after awaited setAttributes: attribute still persists on the failed run
  • setAttributes validation DX: invalid writes throw catchable FatalErrors naming rule and limit

nuxt-node (8 failed):

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

nuxt-quickjs (11 failed):

  • hookCleanupTestWorkflow - hook token reuse after workflow completion | wrun_41M0K0DXC20GH99R88CSP2GVTH | 🔍 observability
  • hookGetConflictWorkflow - hook.getConflict() resolves with the conflicting run when token is already registered | wrun_41M0K0E3VP0GZ1CE8ZQNYW4XS6 | 🔍 observability
  • AbortController abortFromStepWorkflow: step abort cancels an in-flight sibling step
  • AbortController abortDeterministicBranchFromStepWorkflow: branches stay consistent when abort comes from a step
  • setAttributes start: initial attributes are seeded on run creation
  • setAttributes start: reserved-prefix initial attributes are seeded with allowReservedAttributes
  • setAttributes setAttributesWorkflow: workflow-body calls append native attr_set events and merge correctly
  • setAttributes setAttributesInsideStepWorkflow: step-body calls append attributed native events
  • setAttributes fire-and-forget: void setAttributes lands without awaiting
  • setAttributes Promise.all of disjoint-key writes: every key lands
  • setAttributes workflow throws after awaited setAttributes: attribute still persists on the failed run

python-node (8 failed):

  • promiseAllWorkflow | wrun_41M0K04ZYE0GT7TGREB857V3QF | 🔍 observability
  • sleepingWorkflow | wrun_41M0K072WY0GM5KZ62SE0TXPD9 | 🔍 observability
  • parallelSleepWorkflow | wrun_41M0K074250GYPXS3X105C6XSS | 🔍 observability
  • nullByteWorkflow | wrun_41M0K082EC0GY0M5PB1QJ2D4D7 | 🔍 observability
  • cancelRun - cancelling a running workflow | wrun_41M0K0MC6G0GQE4D030E8ZJB75 | 🔍 observability
  • cancelRun via CLI - cancelling a running workflow | wrun_41M0K0MD140GNHVSEAK2WWD7B9 | 🔍 observability
  • sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration | wrun_41M0K0MQ0W0GHAZZXWERVWPZN4 | 🔍 observability
  • resilient start: addTenWorkflow completes when run_created returns 500 | wrun_41M0K0PA7H0GSK4CHVC43A87TN | 🔍 observability

sveltekit-node (8 failed):

  • hookCleanupTestWorkflow - hook token reuse after workflow completion | wrun_41M0K0DXC20GH99R88CSP2GVTH | 🔍 observability
  • hookGetConflictWorkflow - hook.getConflict() resolves with the conflicting run when token is already registered | wrun_41M0K0E3VP0GZ1CE8ZQNYW4XS6 | 🔍 observability
  • resume-or-start route pattern - resumeHook retried after start() reaches the new run | wrun_41M0K0J1PC0GJG8803GDMK7QSK | 🔍 observability
  • distributedAbortController - reconnect to existing controller | wrun_41M0K0TNM70GY117WDSX5HQAZE | 🔍 observability
  • setAttributes start: initial attributes are seeded on run creation
  • setAttributes start: reserved-prefix initial attributes are seeded with allowReservedAttributes
  • setAttributes setAttributesWorkflow: workflow-body calls append native attr_set events and merge correctly
  • setAttributes fire-and-forget: void setAttributes lands without awaiting

sveltekit-quickjs (10 failed):

  • hookCleanupTestWorkflow - hook token reuse after workflow completion | wrun_41M0K0DXC20GH99R88CSP2GVTH | 🔍 observability
  • hookGetConflictWorkflow - hook.getConflict() resolves with the conflicting run when token is already registered | wrun_41M0K0E3VP0GZ1CE8ZQNYW4XS6 | 🔍 observability
  • hookMinRetentionWorkflow - terminal Hook cannot resume and its token stays unavailable | wrun_41M0K0EY610GNRKRWYJXWFVR19 | 🔍 observability
  • AbortController abortFromStepWorkflow: step abort cancels an in-flight sibling step
  • AbortController abortListenerWorkflow: signal.addEventListener fires on the deserialized step signal
  • AbortController abortThrowIfAbortedMidFlightWorkflow: throwIfAborted in a polling loop bails when abort fires
  • setAttributes start: initial attributes are seeded on run creation
  • setAttributes start: reserved-prefix initial attributes are seeded with allowReservedAttributes
  • setAttributes setAttributesWorkflow: workflow-body calls append native attr_set events and merge correctly
  • setAttributes fire-and-forget: void setAttributes lands without awaiting

tanstack-start-node (7 failed):

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

tanstack-start-quickjs (11 failed):

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

vite-node (11 failed):

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

vite-quickjs (11 failed):

  • hookCleanupTestWorkflow - hook token reuse after workflow completion | wrun_41M0K0DXC20GH99R88CSP2GVTH | 🔍 observability
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously | wrun_41M0K0CYV50GJ8ZT86A2090BR6 | 🔍 observability
  • hookGetConflictWorkflow - hook.getConflict() resolves with the conflicting run when token is already registered | wrun_41M0K0E3VP0GZ1CE8ZQNYW4XS6 | 🔍 observability
  • AbortController abortFromStepWorkflow: step abort cancels an in-flight sibling step
  • AbortController abortListenerWorkflow: signal.addEventListener fires on the deserialized step signal
  • AbortController abortDeterministicBranchFromStepWorkflow: branches stay consistent when abort comes from a step
  • setAttributes start: initial attributes are seeded on run creation
  • setAttributes start: reserved-prefix initial attributes are seeded with allowReservedAttributes
  • setAttributes setAttributesWorkflow: workflow-body calls append native attr_set events and merge correctly
  • setAttributes setAttributesInsideStepWorkflow: step-body calls append attributed native events
  • setAttributes fire-and-forget: void setAttributes lands without awaiting

🌐 Cross-language Conformance (9 failed)

python (9 failed):

  • deploymentId: 'latest' is a no-op in non-Vercel worlds | wrun_01M0K0ADF83BSSN3GS8WBY0WK8
  • promiseAllWorkflow | wrun_41M0K04ZYE0GT7TGREB857V3QF
  • sleepingWorkflow | wrun_41M0K072WY0GM5KZ62SE0TXPD9
  • parallelSleepWorkflow | wrun_41M0K074250GYPXS3X105C6XSS
  • nullByteWorkflow | wrun_41M0K082EC0GY0M5PB1QJ2D4D7
  • cancelRun - cancelling a running workflow | wrun_41M0K0MC6G0GQE4D030E8ZJB75
  • cancelRun via CLI - cancelling a running workflow | wrun_41M0K0MD140GNHVSEAK2WWD7B9
  • sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration | wrun_41M0K0MQ0W0GHAZZXWERVWPZN4
  • resilient start: addTenWorkflow completes when run_created returns 500 | wrun_41M0K0PA7H0GSK4CHVC43A87TN

⚠️ Flaky E2E Tests (passed on retry)

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

34 flaky tests
  • abortAnyInStepWorkflow: AbortSignal.any inside a step composes deserialized signals (fastify)
  • abortDeterministicBranchFromStepWorkflow: branches stay consistent when abort comes from a step (astro)
  • abortFromStepWorkflow: step abort cancels an in-flight sibling step (fastify)
  • abortListenerWorkflow: signal.addEventListener fires on the deserialized step signal (fastify)
  • addTenWorkflow (vite)
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously (express)
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously (nextjs-webpack)
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously (sveltekit)
  • deploymentId: 'latest' is a no-op in non-Vercel worlds (nitro)
  • distributedAbortController - manual abort triggers signal (vite)
  • distributedAbortController - reconnect to existing controller (express)
  • distributedAbortController - reconnect to existing controller (nextjs-webpack)
  • distributedAbortController - reconnect to existing controller (nuxt)
  • distributedAbortController - reconnect to existing controller (tanstack-start)
  • hookAdoptOwnerResultWorkflow - duplicate adopts the owner result via conflict.returnValue (nest)
  • hookAdoptOwnerResultWorkflow - duplicate adopts the owner result via conflict.returnValue (nextjs-webpack)
  • hookAdoptOwnerResultWorkflow - duplicate adopts the owner result via conflict.returnValue (nuxt)
  • hookAdoptOwnerResultWorkflow - duplicate adopts the owner result via conflict.returnValue (tanstack-start)
  • hookClaimOnlyMutexWorkflow - hook works as a pure run mutex without payload data (nextjs-webpack)
  • hookGetConflictThenStepParallelWorkflow - hook.getConflict() continuation step runs alongside other steps (nextjs-webpack)
  • hookMinRetentionWorkflow - terminal Hook cannot resume and its token stays unavailable (sveltekit)
  • hookMinRetentionWorkflow - terminal Hook cannot resume and its token stays unavailable (tanstack-start)
  • parallelStepsThenWebhookWorkflow - no hook_conflict from same-tick replay race (express)
  • parallelStepsThenWebhookWorkflow - no hook_conflict from same-tick replay race (vite)
  • Promise.all of disjoint-key writes: every key lands (express)
  • Promise.all of disjoint-key writes: every key lands (nuxt)
  • setAttributesInsideStepWorkflow: step-body calls append attributed native events (nuxt)
  • setAttributesInsideStepWorkflow: step-body calls append attributed native events (sveltekit)
  • validation DX: invalid writes throw catchable FatalErrors naming rule and limit (hono)
  • validation DX: invalid writes throw catchable FatalErrors naming rule and limit (nuxt)
  • validation DX: invalid writes throw catchable FatalErrors naming rule and limit (tanstack-start)
  • workflow throws after awaited setAttributes: attribute still persists on the failed run (nest)
  • workflow throws after awaited setAttributes: attribute still persists on the failed run (nextjs-turbopack)
  • workflow throws after awaited setAttributes: attribute still persists on the failed run (nuxt)

🛠 Infra Events (absorbed by the harness)

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

34 infra events
  • cold-start-warmup · suite warmup (tanstack-start) · at 20:28:53Z · abandoned wrun_01M0K05CFFD0P1P5F2X1D8EA1A
  • cold-start-warmup · suite warmup (python) · at 20:29:08Z · abandoned wrun_41M0K031DY0GMS55VG2W5KMNSQ · (+7 more)
  • run-pickup-stall · promiseAllWorkflow (python) · at 20:29:25Z · abandoned wrun_41M0K06PDT0GW2B3TCBXFRYNH3
  • run-pickup-stall · nullByteWorkflow (python) · at 20:29:25Z · abandoned wrun_41M0K06PE30GQVSN8YV5XT6Q21
  • run-pickup-stall · parallelSleepWorkflow (python) · at 20:29:25Z · abandoned wrun_41M0K06PDZ0GYCK83MXYNE952Q
  • run-pickup-stall · sleepingWorkflow (python) · at 20:29:25Z · abandoned wrun_41M0K06PDZ0GYCK83MXYNE952P
  • run-pickup-stall · cancelRun - cancelling a running workflow (python) · at 20:29:25Z · abandoned wrun_41M0K06PVN0GNCSTA3XBK354W3
  • cold-start-warmup · suite warmup (python) · at 20:29:55Z · abandoned wrun_01M0K04F1CGHS1MJVD03EVKTR5 · (+7 more)
  • run-pickup-stall · cancelRun - cancelling a running workflow (python) · at 20:29:59Z · abandoned wrun_41M0K07Q100GWD2MXHZWPZSWP4
  • run-pickup-stall · deploymentId: 'latest' is a no-op in non-Vercel worlds (python) · at 20:30:10Z · abandoned wrun_01M0K08463HGJF5KZ6ARMGPMR2
  • run-pickup-stall · parallelSleepWorkflow (python) · at 20:30:10Z · abandoned wrun_01M0K0846BCPYF1HMSJPG8CDDF
  • run-pickup-stall · sleepingWorkflow (python) · at 20:30:10Z · abandoned wrun_01M0K08469FJ3JRP3Z2YXVGG9H
  • run-pickup-stall · promiseAllWorkflow (python) · at 20:30:10Z · abandoned wrun_01M0K08464ATQP0WN47BZQWM5P
  • run-pickup-stall · nullByteWorkflow (python) · at 20:30:10Z · abandoned wrun_01M0K0846D5S8XM0XAK6G89C0F
  • run-pickup-stall · promiseAllWorkflow (python) · at 20:30:26Z · abandoned wrun_41M0K08HV30GRBXJFXBWP4PFH7
  • run-pickup-stall · sleepingWorkflow (python) · at 20:30:26Z · abandoned wrun_41M0K08HYY0GM1DHA8H7JME42C
  • run-pickup-stall · nullByteWorkflow (python) · at 20:30:26Z · abandoned wrun_41M0K08HYQ0GPTRAJAKD42WJWC
  • run-pickup-stall · parallelSleepWorkflow (python) · at 20:30:26Z · abandoned wrun_41M0K08J170GY87Y9XFK5K0QDV
  • run-pickup-stall · ChainableService.processWithThis - static step methods using this to reference the class (astro) · at 20:30:42Z · abandoned wrun_01M0K092M81MT1PVXJKZDB92VD
  • run-pickup-stall · promiseAllWorkflow (python) · at 20:31:10Z · abandoned wrun_01M0K09YSVN631D7Y79K14N9EJ
  • run-pickup-stall · deploymentId: 'latest' is a no-op in non-Vercel worlds (python) · at 20:31:10Z · abandoned wrun_01M0K09YSRN1K09G3KQSKYDCZN
  • run-pickup-stall · sleepingWorkflow (python) · at 20:31:10Z · abandoned wrun_01M0K09YT2QQSWMH6SQMA1BKM0
  • run-pickup-stall · parallelSleepWorkflow (python) · at 20:31:10Z · abandoned wrun_01M0K09YT5SV4Q2258PSGY7CTM
  • run-pickup-stall · nullByteWorkflow (python) · at 20:31:10Z · abandoned wrun_01M0K09YTBDMT7YNB8CCZWMN23
  • run-pickup-stall · cancelRun via CLI - cancelling a running workflow (python) · at 20:31:17Z · abandoned wrun_41M0K08Q4J0GJEFJ7Q9QSEA1CG
  • run-pickup-stall · cancelRun - cancelling a running workflow (python) · at 20:32:10Z · abandoned wrun_01M0K0BSDBQRGN6WBACJMNR3VV
  • run-pickup-stall · cancelRun via CLI - cancelling a running workflow (python) · at 20:32:10Z · abandoned wrun_01M0K0BSDKNE775RWES48EAVFN
  • run-pickup-stall · sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration (python) · at 20:32:10Z · abandoned wrun_01M0K0BSDRCP2CP74BQHEBBG7B
  • run-pickup-stall · cancelRun - cancelling a running workflow (python) · at 20:32:40Z · abandoned wrun_01M0K0CPRJYR7ZPVYQW9XTZ187
  • run-pickup-stall · cancelRun via CLI - cancelling a running workflow (python) · at 20:32:40Z · abandoned wrun_01M0K0CPS5HQ2SXHMM161A4MW2
  • run-pickup-stall · cancelRun via CLI - cancelling a running workflow (python) · at 20:32:58Z · abandoned wrun_41M0K0AKNJ0GHH2Q7Z9MH4VX4Z
  • run-pickup-stall · sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration (python) · at 20:32:58Z · abandoned wrun_41M0K0B9QN0GG3WXCYFA8EGM2H
  • run-pickup-stall · sleepInLoopWorkflow - sleep inside loop with steps actually delays each iteration (python) · at 20:33:10Z · abandoned wrun_01M0K0DM0VMN63GF50VGFKTSKT
  • run-pickup-stall · hookSupersedeOwnerWorkflow - duplicate cancels the owner and claims the released token (nextjs-webpack) · at 20:33:39Z · abandoned wrun_01M0K0EG0B1CXE1MJJ7YQJYKQ7

E2E Test Summary

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

❌ ▲ Vercel Production

App Passed Failed Skipped
❌ astro-node 124 8 28
❌ astro-quickjs 121 11 28
❌ example-node 122 10 28
❌ example-quickjs 123 9 28
❌ express-node 125 7 28
❌ express-quickjs 122 10 28
❌ fastify-node 122 10 28
❌ fastify-quickjs 122 10 28
❌ hono-node 123 9 28
❌ hono-quickjs 119 13 28
❌ nest-node 124 8 28
❌ nest-quickjs 122 10 28
❌ nextjs-turbopack-node 153 4 3
❌ nextjs-turbopack-quickjs 147 10 3
❌ nextjs-webpack-node 150 7 3
❌ nextjs-webpack-quickjs 148 9 3
❌ nitro-node 122 10 28
❌ nitro-quickjs 121 11 28
❌ nuxt-node 124 8 28
❌ nuxt-quickjs 121 11 28
❌ python-node 0 8 152
❌ sveltekit-node 143 8 9
❌ sveltekit-quickjs 141 10 9
❌ tanstack-start-node 125 7 28
❌ tanstack-start-quickjs 121 11 28
❌ vite-node 121 11 28
❌ vite-quickjs 121 11 28

✅ 💻 Local Development

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

✅ 📦 Local Production

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

✅ 🐘 Local Postgres

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

✅ 🪟 Windows

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

❌ 🌐 Cross-language Conformance

App Passed Failed Skipped
❌ python 0 9 132

✅ vercel-multi-region

App Passed Failed Skipped
✅ nextjs-turbopack 27 0 0

📋 View full workflow run

@github-actions

github-actions Bot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

📊 Workflow Benchmarks

commit 2a2ff2b · Fri, 21 Aug 2026 20:43:25 GMT · run logs

Backend: vercel · app: nextjs-turbopack

Metric Scenario Best (ms) P75 (ms) P90 (ms) P99 (ms) Samples
TTFS step 554 (-18%) 💚 1415 🔴 (+37%) 🔻 1447 🔴 (+30%) 🔻 1768 🔴 (+17%) 🔻 30
TTFS stream 1141 (+315%) 🔻 1402 🔴 (+29%) 🔻 1446 🔴 (+32%) 🔻 1538 🔴 (+36%) 🔻 30
TTFS hook + stream 1406 (+10%) 1579 🔴 (+10%) 1596 🔴 (-4.0%) 1710 🔴 (-63%) 💚 30
Fan-out TTFS Promise.all(100 steps) 525 (+21%) 🔻 911 (+47%) 🔻 1906 (+184%) 🔻 1946 (-0.6%) 10
Fan-out TTLS Promise.all(100 steps) 1687 (-62%) 💚 2734 (-64%) 💚 3150 (-59%) 💚 8636 (-2.0%) 10
STSO 1020 steps (inline) 120 (-5.5%) 169 (-31%) 💚 184 (-35%) 💚 302 (-34%) 💚 1019
WO 1020 steps 165984 (-28%) 💚 165984 (-28%) 💚 165984 (-28%) 💚 165984 (-28%) 💚 1
CRTT first chunk (pooled) 84 (-4.5%) 137 (+6.2%) 155 (+3.3%) 287 (-29%) 💚 28

Streams

Scenario CRTT 1st p75 p90 p99 CDV max iters
paced control (100/s, 60B) 95 (-11%) 115 (-7%) 240 (+13%) 460 (-9%) 98 (-22%) 10
size sweep (100/s, 160B-12KB) 104 (±0%) 121 (-8%) 176 (-20%) 342 (-36%) 101 (-39%) 10
replay gateway-gpt-5.4-nano-2000t (1x) 155 (+14%) 115 (-15%) 157 (-23%) 345 (-38%) 187 (+30%) 3
replay eve-gpt-5.6-sol-2000t (1x) 111 (-56%) 541 (+119%) 1633 (+19%) 4506 (+2%) 2249 (-4%) 2
replay eve-gpt-5.6-sol-2000t (2x) 140 (-7%) 156 (-12%) 217 (-30%) 758 (-22%) 235 (-59%) 3
📈 STSO distribution vs main (inline / queue-hop histograms)

1020 steps (inline)

Cumulative STSO time: main 231540ms → this run 165714ms (Δ -65826ms, -28%)

100-150 ms  █░░░░░░░░░┃               main   6  this 308  +302
150-200 ms  █████████████░░░░░░░░░░┃  main 344  this 656  +312
200-250 ms  ┃████████████████         main 451  this  35  -416
250-300 ms  ┃████                     main 144  this   8  -136
300-350 ms  ┃█                        main  45  this   6   -39
350-400 ms  ┃                         main   7  this   3    -4
400-450 ms  ┃                         main  10  this   1    -9
450-500 ms  ┃                         main   5  this   0    -5
500-550 ms  ┃                         main   1  this   1    +0
550-600 ms  ┃                         main   2  this   1    -1
600-650 ms  ┃                         main   1  this   0    -1
700-750 ms  ┃                         main   2  this   0    -2
800-850 ms  ┃                         main   1  this   0    -1
📈 CRTT drill-down vs main (RTT distributions & profiles)
variant  RTT 1ms→5s+             avg         p50          p90         p99     n
control  ······█▅▁····   102.6 (-7%)    95 (-3%)   240 (+13%)   460 (-9%)  3000
sweep    ·····▁██▁····  105.7 (-11%)   100 (-4%)   176 (-20%)  342 (-36%)  3000
gw 1x    ·····▁█▆▁····   99.3 (-11%)    94 (-5%)   157 (-23%)  345 (-38%)  5295
eve 1x   ·····▁█▆▁▁▁▁·   324.4 (+3%)   92 (-12%)  1633 (+19%)  4506 (+2%)  5186
eve 2x   ·····▁▆█▂▁···  130.6 (-15%)  109 (-14%)   217 (-30%)  758 (-22%)  7779

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

control  █▄▃▂▂▂▁▁▁▁  89–152ms
sweep    ▄▇▄▆█▅▁▅▂▃  95–116ms
gw 1x    ▄▄▅█▄▁▁▄▂▁  91–115ms
eve 1x   ▁▁▁▁▁▇█▄▃▁  84–1023ms
eve 2x   ▂▆▂▂▁▃▆█▄▂  97–188ms

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

sweep  ▇▇█▅▂▁▂  103–108ms

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

control  █▇▇▅█▅▄▆▃▁  24–31ms
sweep    ▁█▄█▇▅▃▂▃▄  37–52ms
gw 1x    ▅▃▆▇▇▄▅█▁▃  24–31ms
eve 1x   ▃▁▁▂▂█▆▆▄▂  19–47ms
eve 2x   ▄▅▁▃▁▄█▃▃▇  18–25ms
ℹ️ Metric definitions & methodology

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

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

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

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

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

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

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

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

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

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

@github-actions

Copy link
Copy Markdown
Contributor

Sim World

Simulated world deterministic testing for races. Traces

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

fence=per-spec

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

Full trace: world-sim.txt

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant