Skip to content

Allow product-specific step span attributes - #3825

Merged
alangenfeld merged 1 commit into
mainfrom
alangenfeld/cache-sidebar-step-detail
Aug 27, 2026
Merged

Allow product-specific step span attributes#3825
alangenfeld merged 1 commit into
mainfrom
alangenfeld/cache-sidebar-step-detail

Conversation

@alangenfeld

@alangenfeldalangenfeld commented Aug 26, 2026

Copy link
Copy Markdown
Collaborator

Summary & Motivation

Products such as the Vercel dashboard enrich canonical workflow events with backend-specific metadata. buildTrace now takes an optional getStepAttributes callback so those attributes reach step span details without @workflow/web-shared knowing the fields; canonical event-derived fields win on key collision.

Test Plan

Unit test added.

@vercel

vercelBot commented Aug 26, 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 26, 2026 9:23pm
example-nextjs-workflow-webpackReadyReadyPreview, v0Aug 26, 2026 9:23pm
example-workflowReadyReadyPreview, v0Aug 26, 2026 9:23pm
workbench-astro-workflowReadyReadyPreview, v0Aug 26, 2026 9:23pm
workbench-express-workflowReadyReadyPreview, v0Aug 26, 2026 9:23pm
workbench-fastify-workflowReadyReadyPreview, v0Aug 26, 2026 9:23pm
workbench-hono-workflowReadyReadyPreview, v0Aug 26, 2026 9:23pm
workbench-nestjs-workflowReadyReadyPreview, v0Aug 26, 2026 9:23pm
workbench-nitro-workflowReadyReadyPreview, v0Aug 26, 2026 9:23pm
workbench-nuxt-workflowReadyReadyPreview, v0Aug 26, 2026 9:23pm
workbench-python-workflowReadyReadyPreview, v0Aug 26, 2026 9:23pm
workbench-sveltekit-workflowReadyReadyPreview, v0Aug 26, 2026 9:23pm
workbench-tanstack-start-workflowReadyReadyPreview, v0Aug 26, 2026 9:23pm
workbench-vite-workflowReadyReadyPreview, v0Aug 26, 2026 9:23pm
workflow-docsReadyReadyPreview, v0Aug 26, 2026 9:23pm
workflow-swc-playgroundReadyReadyPreview, v0Aug 26, 2026 9:23pm
workflow-tarballsReadyReadyPreview, v0Aug 26, 2026 9:23pm
workflow-webReadyReadyPreview, v0Aug 26, 2026 9:23pm

@changeset-bot

changeset-botBot commented Aug 26, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: b8647a4

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

This PR includes changesets to release 16 packages
NameType
@workflow/web-sharedPatch
@workflow/webPatch
@workflow/cliPatch
@workflow/nitroPatch
workflowPatch
@workflow/world-testingPatch
@workflow/nuxtPatch
@workflow/corePatch
@workflow/buildersPatch
@workflow/nextPatch
@workflow/vitestPatch
@workflow/astroPatch
@workflow/nestPatch
@workflow/rollupPatch
@workflow/sveltekitPatch
@workflow/vitePatch

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

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

@github-actions

Copy link
Copy Markdown
Contributor

🧪 E2E Test Results

Tests are running...

This comment will be updated with the results when the tests complete.


_Started at: _

@github-actions

github-actionsBot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

📊 Workflow Benchmarks

Benchmarks are running for 3d1fb2c... (run logs)

ℹ️ Metric definitions & methodology

Metrics —

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

github-actionsBot commented Aug 26, 2026

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

@github-actions

Copy link
Copy Markdown
Contributor
FrameworkFlow routeStep reg.Framework output
hono200.9 KiB (±0)40.3 KiB (±0)1.76 MiB (±0)
nextjs-turbopack206.3 KiB (±0)439 B (±0)763.1 KiB (±0)
About these numbers

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

3d1fb2c · run

@alangenfeld
alangenfeldforce-pushed the alangenfeld/cache-sidebar-step-detail branch from 3d1fb2c to ce72f03CompareAugust 26, 2026 21:00
@alangenfeldalangenfeld changed the title Cache resolved trace span detailsProject step provenance onto trace spansAug 26, 2026
@alangenfeld
alangenfeldforce-pushed the alangenfeld/cache-sidebar-step-detail branch from ce72f03 to 1e2d97cCompareAugust 26, 2026 21:01
@vercel
vercelBottemporarily deployed to Preview – workflow-docs August 26, 2026 21:01 Inactive
@alangenfeld
alangenfeldforce-pushed the alangenfeld/cache-sidebar-step-detail branch from 515fc7c to 41a11bcCompareAugust 26, 2026 21:19
@alangenfeldalangenfeld changed the title Project step provenance onto trace spansAllow product-specific step span attributesAug 26, 2026
Signed-off-by: Alex Langenfeld <alex.langenfeld@vercel.com>
@alangenfeld
alangenfeldforce-pushed the alangenfeld/cache-sidebar-step-detail branch from 41a11bc to b8647a4CompareAugust 26, 2026 21:19
@vercel
vercelBottemporarily deployed to Preview – workflow-docs August 26, 2026 21:19 Inactive

@karthikscale3karthikscale3 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

AI Review: Approved with a few non-blocking API and test follow-ups.

}

export type GetStepAttributes = (
events: Event[]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

AI Review: This callback is meant to read product-specific enrichment fields, but its input is fixed to the base Event[]. The new test already has to cast to access externalAttemptId, and Front will need the same workaround for vercelId / computeInstanceId. Could we make GetStepAttributes, buildTrace, and TraceViewer generic over TEvent extends Event so consumers retain their enriched event type?


export type GetStepAttributes = (
events: Event[]
) => Record<string, unknown> | undefined;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

AI Review: The return type suggests any product-specific key can be surfaced, but the sidebar drops keys that are not registered in attributeToDisplayFn. The current Vercel fields happen to be registered, so this works for this use case; please either document that display registration is also required or expose a way for consumers to provide display metadata.

});
const stepSpan = trace.spans.find((span) => span.resource === 'step');

expect(stepSpan?.attributes.data).toMatchObject({

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

AI Review: Could we add a collision assertion here? The implementation intentionally spreads canonical step fields after extension attributes, so a test where the callback returns stepId or status would lock in the non-overridable guarantee documented in the implementation.

@karthikscale3karthikscale3 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

would be useful to add a link to the logs page from the side bar and filtering it by the requestId.

@github-actions

Copy link
Copy Markdown
Contributor

No backport to stable for 36944cd (AI decision).

This commit adds a new optional getStepAttributes callback to buildTrace/stepToSpan/TraceViewer, plus a new exported GetStepAttributes type — a purely additive API surface so products can inject their own step span attributes. That is feature work (the subject is even feat(web-shared)), not a fix to broken behavior on stable, so it stays on main.

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

36944cdcad824f3628c29ecc056f3b9d1293cb05

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.

2 participants

@alangenfeld@karthikscale3