Problem
Every queued step execution pays a blocking world.runs.get(runId) before its step_started claim — one extra round trip per branch on the TTLS-critical path. Under a 256-branch fan-out burst the read amplification makes it much worse: measured GET /api/v2/runs/:runId p90 = 5.1s during the burst (durabench parallel sweeps, run wrun_41KZR0MW890GWZK34RD4Y1JBDT), directly smearing branch starts.
What the consumer actually uses from that read:
status !== 'running' early exit — redundant: the step_started claim is already rejected server-side on a terminal run (RunExpiredError → gone)
deploymentId, specVersion — needed by guardDeployment (Pick<WorkflowRun, 'runId' | 'deploymentId' | 'specVersion'>) and executeStep
startedAt, attributes (→ rootRunId) — executeStep params
- full run row for the post-completion inline-replay synthesis — only the LAST completer needs it
All of the per-start fields are known to the producer at dispatch time and are immutable for the life of a run (runs are deployment-pinned).
Proposal
Carry them on the step message: additive WorkflowInvokePayload.runContext (deploymentId, specVersion, startedAt, rootRunId), stamped by the dispatch sites. A consumer that receives it skips the blocking runs.get entirely; the inline-replay path fetches the run lazily only when it is the last completer. Messages without runContext (older producers) keep today's path — messages are deployment-pinned, so mixed-version handling within a run cannot occur.
Wins: −1 RTT per queued step start at all scales (~30–80ms p50), and removes ~N reads per fan-out from the run's hot partition (compounding with #3455).
Problem
Every queued step execution pays a blocking
world.runs.get(runId)before itsstep_startedclaim — one extra round trip per branch on the TTLS-critical path. Under a 256-branch fan-out burst the read amplification makes it much worse: measuredGET /api/v2/runs/:runIdp90 = 5.1s during the burst (durabench parallel sweeps, runwrun_41KZR0MW890GWZK34RD4Y1JBDT), directly smearing branch starts.What the consumer actually uses from that read:
status !== 'running'early exit — redundant: thestep_startedclaim is already rejected server-side on a terminal run (RunExpiredError→gone)deploymentId,specVersion— needed byguardDeployment(Pick<WorkflowRun, 'runId' | 'deploymentId' | 'specVersion'>) andexecuteStepstartedAt,attributes(→ rootRunId) —executeStepparamsAll of the per-start fields are known to the producer at dispatch time and are immutable for the life of a run (runs are deployment-pinned).
Proposal
Carry them on the step message: additive
WorkflowInvokePayload.runContext(deploymentId,specVersion,startedAt,rootRunId), stamped by the dispatch sites. A consumer that receives it skips the blockingruns.getentirely; the inline-replay path fetches the run lazily only when it is the last completer. Messages withoutrunContext(older producers) keep today's path — messages are deployment-pinned, so mixed-version handling within a run cannot occur.Wins: −1 RTT per queued step start at all scales (~30–80ms p50), and removes ~N reads per fan-out from the run's hot partition (compounding with #3455).