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

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

vercelBot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

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

ProjectDeploymentActionsUpdated (UTC)
example-nextjs-workflow-turbopackReadyReadyPreview, v0Aug 21, 2026 8:29pm
example-nextjs-workflow-webpackReadyReadyPreview, v0Aug 21, 2026 8:29pm
example-workflowReadyReadyPreview, v0Aug 21, 2026 8:29pm
workbench-astro-workflowReadyReadyPreview, v0Aug 21, 2026 8:29pm
workbench-express-workflowReadyReadyPreview, v0Aug 21, 2026 8:29pm
workbench-fastify-workflowReadyReadyPreview, v0Aug 21, 2026 8:29pm
workbench-hono-workflowReadyReadyPreview, v0Aug 21, 2026 8:29pm
workbench-nestjs-workflowReadyReadyPreview, v0Aug 21, 2026 8:29pm
workbench-nitro-workflowReadyReadyPreview, v0Aug 21, 2026 8:29pm
workbench-nuxt-workflowReadyReadyPreview, v0Aug 21, 2026 8:29pm
workbench-python-workflowReadyReadyPreview, v0Aug 21, 2026 8:29pm
workbench-sveltekit-workflowReadyReadyPreview, v0Aug 21, 2026 8:29pm
workbench-tanstack-start-workflowReadyReadyPreview, v0Aug 21, 2026 8:29pm
workbench-vite-workflowReadyReadyPreview, v0Aug 21, 2026 8:29pm
workflow-docsReadyReadyPreview, v0Aug 21, 2026 8:29pm
workflow-swc-playgroundReadyReadyPreview, v0Aug 21, 2026 8:29pm
workflow-tarballsReadyReadyPreview, v0Aug 21, 2026 8:29pm
workflow-webReadyReadyPreview, v0Aug 21, 2026 8:29pm

@github-actions

github-actionsBot 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
PassedFailedSkippedTotal
❌ ▲ Vercel Production33272517424320
✅ 💻 Local Development392205584480
✅ 📦 Local Production392205584480
✅ 🐘 Local Postgres392205584480
✅ 🪟 Windows32000320
❌ 🌐 Cross-language Conformance09132141
✅ vercel-multi-region270027
Total15440260254818248
Details by Category

❌ ▲ Vercel Production

AppPassedFailedSkipped
❌ astro-node124828
❌ astro-quickjs1211128
❌ example-node1221028
❌ example-quickjs123928
❌ express-node125728
❌ express-quickjs1221028
❌ fastify-node1221028
❌ fastify-quickjs1221028
❌ hono-node123928
❌ hono-quickjs1191328
❌ nest-node124828
❌ nest-quickjs1221028
❌ nextjs-turbopack-node15343
❌ nextjs-turbopack-quickjs147103
❌ nextjs-webpack-node15073
❌ nextjs-webpack-quickjs14893
❌ nitro-node1221028
❌ nitro-quickjs1211128
❌ nuxt-node124828
❌ nuxt-quickjs1211128
❌ python-node08152
❌ sveltekit-node14389
❌ sveltekit-quickjs141109
❌ tanstack-start-node125728
❌ tanstack-start-quickjs1211128
❌ vite-node1211128
❌ vite-quickjs1211128

✅ 💻 Local Development

AppPassedFailedSkipped
✅ astro-stable-node134026
✅ astro-stable-quickjs134026
✅ express-stable-node134026
✅ express-stable-quickjs134026
✅ fastify-stable-node134026
✅ fastify-stable-quickjs134026
✅ hono-stable-node134026
✅ hono-stable-quickjs134026
✅ nest-stable-node134026
✅ nest-stable-quickjs134026
✅ nextjs-turbopack-canary-node141019
✅ nextjs-turbopack-canary-quickjs141019
✅ nextjs-turbopack-stable-node16000
✅ nextjs-turbopack-stable-quickjs16000
✅ nextjs-webpack-canary-node141019
✅ nextjs-webpack-canary-quickjs141019
✅ nextjs-webpack-stable-node16000
✅ nextjs-webpack-stable-quickjs16000
✅ nitro-stable-node134026
✅ nitro-stable-quickjs134026
✅ nuxt-stable-node134026
✅ nuxt-stable-quickjs134026
✅ sveltekit-stable-node15307
✅ sveltekit-stable-quickjs15307
✅ tanstack-start-node134026
✅ tanstack-start-quickjs134026
✅ vite-stable-node134026
✅ vite-stable-quickjs134026

✅ 📦 Local Production

AppPassedFailedSkipped
✅ astro-stable-node134026
✅ astro-stable-quickjs134026
✅ express-stable-node134026
✅ express-stable-quickjs134026
✅ fastify-stable-node134026
✅ fastify-stable-quickjs134026
✅ hono-stable-node134026
✅ hono-stable-quickjs134026
✅ nest-stable-node134026
✅ nest-stable-quickjs134026
✅ nextjs-turbopack-canary-node141019
✅ nextjs-turbopack-canary-quickjs141019
✅ nextjs-turbopack-stable-node16000
✅ nextjs-turbopack-stable-quickjs16000
✅ nextjs-webpack-canary-node141019
✅ nextjs-webpack-canary-quickjs141019
✅ nextjs-webpack-stable-node16000
✅ nextjs-webpack-stable-quickjs16000
✅ nitro-stable-node134026
✅ nitro-stable-quickjs134026
✅ nuxt-stable-node134026
✅ nuxt-stable-quickjs134026
✅ sveltekit-stable-node15307
✅ sveltekit-stable-quickjs15307
✅ tanstack-start-node134026
✅ tanstack-start-quickjs134026
✅ vite-stable-node134026
✅ vite-stable-quickjs134026

✅ 🐘 Local Postgres

AppPassedFailedSkipped
✅ astro-stable-node134026
✅ astro-stable-quickjs134026
✅ express-stable-node134026
✅ express-stable-quickjs134026
✅ fastify-stable-node134026
✅ fastify-stable-quickjs134026
✅ hono-stable-node134026
✅ hono-stable-quickjs134026
✅ nest-stable-node134026
✅ nest-stable-quickjs134026
✅ nextjs-turbopack-canary-node141019
✅ nextjs-turbopack-canary-quickjs141019
✅ nextjs-turbopack-stable-node16000
✅ nextjs-turbopack-stable-quickjs16000
✅ nextjs-webpack-canary-node141019
✅ nextjs-webpack-canary-quickjs141019
✅ nextjs-webpack-stable-node16000
✅ nextjs-webpack-stable-quickjs16000
✅ nitro-stable-node134026
✅ nitro-stable-quickjs134026
✅ nuxt-stable-node134026
✅ nuxt-stable-quickjs134026
✅ sveltekit-stable-node15307
✅ sveltekit-stable-quickjs15307
✅ tanstack-start-node134026
✅ tanstack-start-quickjs134026
✅ vite-stable-node134026
✅ vite-stable-quickjs134026

✅ 🪟 Windows

AppPassedFailedSkipped
✅ nextjs-turbopack-node16000
✅ nextjs-turbopack-quickjs16000

❌ 🌐 Cross-language Conformance

AppPassedFailedSkipped
❌ python09132

✅ vercel-multi-region

AppPassedFailedSkipped
✅ nextjs-turbopack2700

📋 View full workflow run

@github-actions

github-actionsBot 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

MetricScenarioBest (ms)P75 (ms)P90 (ms)P99 (ms)Samples
TTFSstep554 (-18%) 💚1415 🔴 (+37%) 🔻1447 🔴 (+30%) 🔻1768 🔴 (+17%) 🔻30
TTFSstream1141 (+315%) 🔻1402 🔴 (+29%) 🔻1446 🔴 (+32%) 🔻1538 🔴 (+36%) 🔻30
TTFShook + stream1406 (+10%)1579 🔴 (+10%)1596 🔴 (-4.0%)1710 🔴 (-63%) 💚30
Fan-out TTFSPromise.all(100 steps)525 (+21%) 🔻911 (+47%) 🔻1906 (+184%) 🔻1946 (-0.6%)10
Fan-out TTLSPromise.all(100 steps)1687 (-62%) 💚2734 (-64%) 💚3150 (-59%) 💚8636 (-2.0%)10
STSO1020 steps (inline)120 (-5.5%)169 (-31%) 💚184 (-35%) 💚302 (-34%) 💚1019
WO1020 steps165984 (-28%) 💚165984 (-28%) 💚165984 (-28%) 💚165984 (-28%) 💚1
CRTTfirst chunk (pooled)84 (-4.5%)137 (+6.2%)155 (+3.3%)287 (-29%) 💚28

Streams

ScenarioCRTT 1stp75p90p99CDV maxiters
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-2000teaf22f5946e7c61f3c65c7006d550df180cfabd4e706254a09f22aec0cfb420d · gateway-gpt-5.4-nano-2000t6f24ac518b6b83ff1d0e85a5fe78230db192716d66a7fc6b2fe022752001d041

🔴 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

scenariooutcomeeventsvirtreplayviolations
smoke-no-stepscompleted30msok0
smoke-one-stepcompleted60msok0
hook-at-step-startedcompleted120msok0
hook-at-step-completedcompleted120msok0
hook-at-hook-createdcompleted120msok0
deadline-hook-winscompleted71.0hok0
deadline-expirescompleted71.0hok0
long-sleepcompleted1130.0dok0
hook-never-arrivesstalled30msskipped0
step-retries-twicecompleted102.0sok0
parallel-stepscompleted90msok0
hook-on-execution-statecompleted120msok0
peek-hook-before-branchcompleted120msok0
peek-hook-after-branchcompleted120msok0
peek-hook-at-registrationcompleted120msok0
race-hook-before-probecompleted120msok0
race-hook-after-probecompleted120msok0
race-duplicate-deliverycompleted130msok0
attr-hook-before-stepcompleted110msok0
attr-hook-after-stepcompleted110msok0
attr-from-step-bodycompleted130msok0
fork-hook-after-timeoutcompleted141.0mok0
fork-hook-before-timeoutcompleted141.0mok0
count-hook-after-timeoutcompleted171.0mok0
count-hook-before-timeoutcompleted201.0mok0
stale-read-step-count-forkcompleted201.0mok0
stale-read-equal-step-countscompleted141.0mok0
step-vs-step-forkcompleted120msok0
step-vs-step-fork-fencedcompleted120msok0
fence-catches-benign-directioncompleted125msok0
in-flight-before-decisioncompleted171.0mok0
in-flight-before-decision-countedcompleted171.0mok0
in-flight-after-decisioncompleted192.0mok0
stale-read-step-count-fork-fencedcompleted201.0mok0
fork-hook-winscompleted131.0mok0
fork-timeout-winscompleted131.0mok0
unclaimed-payload-under-forkcompleted171.0mok0
claimed-payload-under-forkcompleted171.0mok0
writers-independent-step-bodiescompleted120msok0
writers-scripted-tempocompleted120msok0
cancel-mid-stepcancelled70msskipped0

Full trace: world-sim.txt

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