Skip to content

[core] Add a retention option to start() - #3786

Closed
VaguelySerious wants to merge 2 commits into
mainfrom
retention-start-option
Closed

[core] Add a retention option to start()#3786
VaguelySerious wants to merge 2 commits into
mainfrom
retention-start-option

Conversation

@VaguelySerious

@VaguelySerious VaguelySerious commented Aug 25, 2026

Copy link
Copy Markdown
Member

Description

Adds start({ retention }), a per-run data-retention preference the World applies once the run finishes. The value is recorded as the reserved $retention run attribute — attributes already ride along on run_created and on the resilient-start queue message, and are materialized onto the run entity, so the World can read the preference at finish time with no new wire field.

Documented on StartOptions exactly as specified:

Set a preference for data retention after run completion.

Worlds control the retention of user data (event payloads and stream chunks), the event log, and any analytics data. Options are:

  • 'default': same as omission, the World will decide. On Vercel, this is based on your team's plan.
  • 'none': if supported, data is deleted immediately after your run completes/fails. On Vercel, user data is deleted, but metadata may be persist for your plan's default retention period.
  • string: Custom value to pass to the World. Refer to your World's documentation on which values are supported. Not currently supported on Vercel.

Behavior notes, in the order a reader hits them:

  • 'default' and omission are byte-identical. Neither writes an attribute, so "same as omission" is literally true rather than approximately true — no attribute slot burned, nothing for a World to interpret.
  • The typed option wins over a hand-written $retention. Caller attributes are spread between lineage and retention, so a framework caller with allowReservedAttributes can still deliberately re-parent a run, but cannot silently weaken a retention preference. Quietly keeping data the caller asked to drop is the worse failure of the two.
  • Pre-spec-4 Worlds throw. The preference rides on run attributes, so a World that can't carry attributes can't carry the preference — failing loudly beats retaining data on a run whose caller believed it wouldn't be.
  • Values are validated but not interpreted. Empty/non-string values are rejected up front with a clear message, and the value is length-checked against the attribute-value limit. Beyond that the SDK passes it through: 'none' and World-specific strings are recorded verbatim.

The Vercel side of 'none' is implemented in vercel/workflow-server#858.

How did you test your changes?

packages/core/src/runtime/start.test.ts gains a retention block: seeding on both payloads for 'none' (including the allowReservedAttributes flag each needs), verbatim pass-through of a World-specific string, no attribute at all for 'default'/omission, merging with caller attributes, precedence over a hand-written $retention, the pre-v4 rejection, and rejection of empty/non-string/oversized values.

packages/core/src/runtime/start-retention.world.test.ts then checks the same thing against a real World (@workflow/world-local) rather than mocks: that the reserved key survives validation on the way in, that a World-specific string is stored verbatim, and that 'default' really does leave the created run's attributes identical to omission.

packages/core $ pnpm vitest run src/runtime/start.test.ts
 Test Files  1 passed (1)
      Tests  65 passed (65)

packages/core $ pnpm vitest run src/runtime/start-retention.world.test.ts
 Test Files  1 passed (1)
      Tests  3 passed (3)

Also ran the full packages/core suite (2126 passed) and packages/world (110 passed). Two pre-existing failures in this sandbox are unrelated and reproduce on main: src/runtime/quickjs-runtime.test.ts needs the Rust-built QuickJS asset, and packages/world/src/spec-version.test.ts asserts SPEC_VERSION_CURRENT === 5.

PR Checklist - Required to merge

  • 📦 pnpm changeset was run to create a changelog for this PR
  • 🔒 DCO sign-off passes
  • 📝 Ping @vercel/workflow in a comment once the PR is ready, and the above checklist is complete

🤖 Generated with Claude Code

Records a data-retention preference on the run for the World to apply once
the run finishes, as the reserved `$retention` attribute.

`'default'` and omission write nothing, so a run that states the default is
indistinguishable from one that says nothing. `'none'` and any World-specific
string are recorded verbatim; the SDK assigns no meaning beyond validating
that the value fits in an attribute. The preference rides on run attributes,
so a World that cannot carry them throws rather than silently retaining data
the caller asked to have dropped.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Peter Wielander <29887157+VaguelySerious@users.noreply.github.com>

Co-Authored-By: Peter Wielander <29887157+VaguelySerious@users.noreply.github.com>
@vercel

vercel Bot commented Aug 25, 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 25, 2026 7:57pm
example-nextjs-workflow-webpack Ready Ready Preview, v0 Aug 25, 2026 7:57pm
example-workflow Ready Ready Preview, v0 Aug 25, 2026 7:57pm
workbench-astro-workflow Ready Ready Preview, v0 Aug 25, 2026 7:57pm
workbench-express-workflow Ready Ready Preview, v0 Aug 25, 2026 7:57pm
workbench-fastify-workflow Ready Ready Preview, v0 Aug 25, 2026 7:57pm
workbench-hono-workflow Ready Ready Preview, v0 Aug 25, 2026 7:57pm
workbench-nestjs-workflow Ready Ready Preview, v0 Aug 25, 2026 7:57pm
workbench-nitro-workflow Ready Ready Preview, v0 Aug 25, 2026 7:57pm
workbench-nuxt-workflow Ready Ready Preview, v0 Aug 25, 2026 7:57pm
workbench-python-workflow Ready Ready Preview, v0 Aug 25, 2026 7:57pm
workbench-sveltekit-workflow Ready Ready Preview, v0 Aug 25, 2026 7:57pm
workbench-tanstack-start-workflow Ready Ready Preview, v0 Aug 25, 2026 7:57pm
workbench-vite-workflow Ready Ready Preview, v0 Aug 25, 2026 7:57pm
workflow-docs Ready Ready Preview, v0 Aug 25, 2026 7:57pm
workflow-swc-playground Building Building Preview, v0 Aug 25, 2026 7:57pm
workflow-tarballs Ready Ready Preview, v0 Aug 25, 2026 7:57pm
workflow-web Ready Ready Preview, v0 Aug 25, 2026 7:57pm

@changeset-bot

changeset-bot Bot commented Aug 25, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: aa5f325

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

This PR includes changesets to release 20 packages
Name Type
@workflow/core Minor
workflow Minor
@workflow/world Minor
@workflow/builders Patch
@workflow/cli Patch
@workflow/next Patch
@workflow/nitro Patch
@workflow/vitest Patch
@workflow/web-shared Patch
@workflow/web Patch
@workflow/world-testing Patch
@workflow/world-local Patch
@workflow/world-postgres Patch
@workflow/world-vercel Patch
@workflow/astro Patch
@workflow/nest Patch
@workflow/rollup Patch
@workflow/sveltekit Patch
@workflow/vite Patch
@workflow/nuxt Patch

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

The mocked tests in start.test.ts pin what the SDK sends. This pins what a
World stores: that the reserved key survives validation on the way in, and
that 'default' really is indistinguishable from omission on the created run.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Peter Wielander <29887157+VaguelySerious@users.noreply.github.com>

Co-Authored-By: Peter Wielander <29887157+VaguelySerious@users.noreply.github.com>
@VaguelySerious

Copy link
Copy Markdown
Member Author

closed in favor of #3787

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