Files
vercel__workflow/.changeset/native-attribute-events.md
Pranay Prakash ae8d6feeda Add native v4 workflow attribute events (#2226)
* Add native workflow attribute events

* Fix abbreviated attributes docs sample

* Document attribute replay ordering for step races

* Address native attribute review feedback

* Validate before claiming attr_set dedup lock; clearer start() attribute errors

- world-local: claim the attr_set correlation lock only after validation,
  so a validation failure does not permanently mark the correlationId as
  written and wedge the run in a re-invoke loop on retry
- world-postgres: distinguish a concurrently-deleted run from a cap
  violation when the guarded attributes update matches no rows
- core: reject non-string initial attribute values in start() with a
  clear error instead of a downstream schema failure

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Add attribute edge-case tests across all layers

- core: normalizeAttributeChanges unit tests (non-object inputs, FatalError
  wrapping, key/value/batch limits, boundary lengths, UTF-8 byte counting)
- core: start() rejects reserved keys, oversized keys/values, and over-cap
  initial attribute batches before any write
- world-local + world-postgres: per-run cap enforced against existing
  attributes (upsert-at-cap allowed, removal frees room), oversized values
  rejected on attr_set, invalid initial attributes rejected on run_created
- e2e: validation DX workflow asserting every invalid write throws a
  catchable FatalError naming the violated rule and limit, with the run
  staying healthy; start() rejects invalid initial attributes client-side

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Remove accidentally committed local e2e diagnostics artifact

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Bump world-vercel to spec version 4 for native attributes

The deployed workflow-server (vercel/workflow-server#469) materializes
native attr_set events and accepts initial run attributes, but
world-vercel still advertised spec v3 — so start(..., { attributes })
rejected itself client-side ('requires spec version 4') on every Vercel
deployment, failing the new e2e seeding test across the prod matrix.
New runs are now stamped v4.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Reject duplicate correlated attr_set before materializing in Postgres

A redelivered duplicate — including one carrying different changes for
the same correlationId — previously re-applied the run attributes update
and only then failed the event insert, leaving the snapshot out of sync
with the event log. Pre-check the event log for the correlationId before
mutating; the unique index still guards the truly-concurrent race, which
is idempotent (deterministic replay carries identical changes). Also
apply the suggested docs wording for initial attributes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Apply suggestion from @VaguelySerious

Signed-off-by: Peter Wielander <mittgfu@gmail.com>

* Fail the run on World-rejected attribute writes; un-nest runtime test

Two fixes from review:

- runtime.test.ts: the pre-existing test "propagates transient
  step_created failures..." was accidentally nested inside the new
  attribute-race test, failing the new test ("Calling the test function
  inside another test function is not allowed") and preventing the old
  test from running. Restored it verbatim at describe level.

- A workflow-body attr_set the World rejects as invalid (e.g. the
  cumulative per-run attribute cap, which only the World can check) is
  deterministic: redelivering the orchestrator message replays the same
  write into the same rejection, wedging the run in redelivery with no
  terminal event. handleSuspension now wraps such rejections in
  FatalError, and workflowEntrypoint fails the run with the validation
  error instead of rejecting the delivery. Transient storage errors
  still propagate and retry via redelivery.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Signed-off-by: Peter Wielander <mittgfu@gmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Peter Wielander <mittgfu@gmail.com>
Co-authored-by: Peter Wielander <peter.wielander@vercel.com>
2026-06-11 10:19:08 -07:00

327 B

workflow, @workflow/core, @workflow/world, @workflow/world-local, @workflow/world-postgres, @workflow/world-vercel
workflow @workflow/core @workflow/world @workflow/world-local @workflow/world-postgres @workflow/world-vercel
minor minor minor minor minor minor

Allow passing initial run attributes through start(), and speed up workflow-level setAttribute calls by using native events for recording attributes.