Skip to content

feat(core): widen retained boundaries to plain data and standard built-ins#3047

Draft
NathanColosimo wants to merge 1 commit into
nathanc/retained-vm-corefrom
nathanc/retained-vm-passivity
Draft

feat(core): widen retained boundaries to plain data and standard built-ins#3047
NathanColosimo wants to merge 1 commit into
nathanc/retained-vm-corefrom
nathanc/retained-vm-passivity

Conversation

@NathanColosimo

Copy link
Copy Markdown
Contributor

Summary

Third of the 3-PR stack from #2990 — replaces #3046's primitives-only retention gate with the retained-input walker, so real-world step arguments keep the fast path:

  • Accepted: plain objects and arrays (own enumerable string-keyed data properties only — devalue traverses these purely via own reads), and workflow-realm Map/Set/Date/typed arrays/ArrayBuffer (their prototypes are frozen by feat(core): deterministic sandbox hardening #3045, so serialization can execute nothing workflow-planted — including constructor reads)
  • Declined per boundary (one ordinary replay, retention resumes at the next clean boundary): accessors, proxies, functions, symbols/hidden keys, custom class serializers, RegExp/DataView/SAB, host-realm built-in instances, subclassed collections
  • Host dispatch verification: the shared host constructors/prototypes serialization consults can't be frozen process-wide but are reachable from workflow code (structuredClone results, exposed classes) — ~40 own-descriptor reads per retained batch verify no planted Symbol.hasInstance, serializer statics (incl. inherited via host Function.prototype/Object.prototype), or BigInt.prototype.toString
  • The checker executes no user code itself: descriptor-only walking, module-load-captured primordials throughout
  • Coupling test: instruments every member on the frozen prototypes and asserts serialization executes nothing outside the measured surface — serde drift fails CI loudly

Why this is safe (one invariant)

Step-argument serialization runs once (at suspension) and never re-runs during replay, so its only hazard is executing workflow code whose side effects live on in the retained VM. Bytes cannot differ by mode — there is a single serialization path shared by all modes. The walker + freeze + host verification together prove the no-code property; anything unprovable serializes identically and demotes.

Known residual (deliberate, documented): generic host-realm escape (replacing shared host statics via constructor chains) breaks the whole process for every mode and is tracked by the realm-local-intrinsics follow-up.

Review focus

Pure policy — every line answers "does serializing this value execute workflow code?". The state machine and loop integration were reviewed in #3046; the sandbox semantics in #3045.

Validation

Full core suite green in both modes: 74 files, 1,556 passed, 3 expected failures each. Walker tests cover accept/decline matrices, non-invocation guarantees (getters/proxies/serializers never fire during checking), freeze semantics, host-spoof demotion, and the instrumentation coverage test.

Stack: #3045#3046 → this. #2990 stays open as the reference implementation.

…t-ins

Replace the primitives-only retention gate with the retained-input
walker: descriptor-only inspection (getters/proxies never fire) accepts
plain objects and arrays (own enumerable string-keyed data properties),
and workflow-realm Map/Set/Date/typed arrays/ArrayBuffer whose frozen
prototypes guarantee serialization executes nothing workflow-planted.
Host dispatch points that cannot be frozen (shared constructors,
inherited serializer statics, BigInt.prototype.toString) are verified
per boundary via own-descriptor reads; the checker itself runs
exclusively on module-load-captured primordials. An instrumentation
test locks the serializer's measured prototype touch-surface so serde
drift fails CI loudly.
@NathanColosimo
NathanColosimo requested review from a team and ijjk as code owners July 22, 2026 02:37
@changeset-bot

changeset-bot Bot commented Jul 22, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 6590434

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

This PR includes changesets to release 16 packages
Name Type
@workflow/core Patch
workflow Patch
@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/astro Patch
@workflow/nest Patch
@workflow/nuxt Patch
@workflow/rollup Patch
@workflow/sveltekit Patch
@workflow/vite 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

@vercel

vercel Bot commented Jul 22, 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, Comment Jul 22, 2026 2:40am
example-nextjs-workflow-webpack Ready Ready Preview, Comment Jul 22, 2026 2:40am
example-workflow Ready Ready Preview, Comment Jul 22, 2026 2:40am
workbench-astro-workflow Ready Ready Preview, Comment Jul 22, 2026 2:40am
workbench-express-workflow Ready Ready Preview, Comment Jul 22, 2026 2:40am
workbench-fastify-workflow Ready Ready Preview, Comment Jul 22, 2026 2:40am
workbench-hono-workflow Ready Ready Preview, Comment Jul 22, 2026 2:40am
workbench-nestjs-workflow Ready Ready Preview, Comment Jul 22, 2026 2:40am
workbench-nitro-workflow Ready Ready Preview, Comment Jul 22, 2026 2:40am
workbench-nuxt-workflow Ready Ready Preview, Comment Jul 22, 2026 2:40am
workbench-sveltekit-workflow Ready Ready Preview, Comment Jul 22, 2026 2:40am
workbench-tanstack-start-workflow Ready Ready Preview, Comment Jul 22, 2026 2:40am
workbench-vite-workflow Ready Ready Preview, Comment Jul 22, 2026 2:40am
workflow-docs Ready Ready Preview, Comment, Open in v0 Jul 22, 2026 2:40am
workflow-swc-playground Ready Ready Preview, Comment Jul 22, 2026 2:40am
workflow-tarballs Ready Ready Preview, Comment Jul 22, 2026 2:40am
workflow-web Ready Ready Preview, Comment Jul 22, 2026 2:40am

@github-actions

github-actions Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

🧪 E2E Test Results

All tests passed

Summary

Passed Failed Skipped Total
✅ ▲ Vercel Production 1455 0 239 1694
✅ 💻 Local Development 1621 0 227 1848
✅ 📦 Local Production 1621 0 227 1848
✅ 🐘 Local Postgres 1621 0 227 1848
✅ 🪟 Windows 154 0 0 154
✅ 📋 Other 1020 0 212 1232
✅ vercel-multi-region 27 0 0 27
Total 7519 0 1132 8651

Details by Category

✅ ▲ Vercel Production
App Passed Failed Skipped
✅ astro 126 0 28
✅ example 126 0 28
✅ express 126 0 28
✅ fastify 126 0 28
✅ hono 126 0 28
✅ nextjs-turbopack 151 0 3
✅ nextjs-webpack 151 0 3
✅ nitro 126 0 28
✅ nuxt 126 0 28
✅ sveltekit 145 0 9
✅ vite 126 0 28
✅ 💻 Local Development
App Passed Failed Skipped
✅ astro-stable 128 0 26
✅ express-stable 128 0 26
✅ fastify-stable 128 0 26
✅ hono-stable 128 0 26
✅ nextjs-turbopack-canary 135 0 19
✅ nextjs-turbopack-stable 154 0 0
✅ nextjs-webpack-canary 135 0 19
✅ nextjs-webpack-stable 154 0 0
✅ nitro-stable 128 0 26
✅ nuxt-stable 128 0 26
✅ sveltekit-stable 147 0 7
✅ vite-stable 128 0 26
✅ 📦 Local Production
App Passed Failed Skipped
✅ astro-stable 128 0 26
✅ express-stable 128 0 26
✅ fastify-stable 128 0 26
✅ hono-stable 128 0 26
✅ nextjs-turbopack-canary 135 0 19
✅ nextjs-turbopack-stable 154 0 0
✅ nextjs-webpack-canary 135 0 19
✅ nextjs-webpack-stable 154 0 0
✅ nitro-stable 128 0 26
✅ nuxt-stable 128 0 26
✅ sveltekit-stable 147 0 7
✅ vite-stable 128 0 26
✅ 🐘 Local Postgres
App Passed Failed Skipped
✅ astro-stable 128 0 26
✅ express-stable 128 0 26
✅ fastify-stable 128 0 26
✅ hono-stable 128 0 26
✅ nextjs-turbopack-canary 135 0 19
✅ nextjs-turbopack-stable 154 0 0
✅ nextjs-webpack-canary 135 0 19
✅ nextjs-webpack-stable 154 0 0
✅ nitro-stable 128 0 26
✅ nuxt-stable 128 0 26
✅ sveltekit-stable 147 0 7
✅ vite-stable 128 0 26
✅ 🪟 Windows
App Passed Failed Skipped
✅ nextjs-turbopack 154 0 0
✅ 📋 Other
App Passed Failed Skipped
✅ e2e-local-dev-nest-stable 128 0 26
✅ e2e-local-dev-tanstack-start- 128 0 26
✅ e2e-local-postgres-nest-stable 128 0 26
✅ e2e-local-postgres-tanstack-start- 128 0 26
✅ e2e-local-prod-nest-stable 128 0 26
✅ e2e-local-prod-tanstack-start- 128 0 26
✅ e2e-vercel-prod-nest 126 0 28
✅ e2e-vercel-prod-tanstack-start 126 0 28
✅ vercel-multi-region
App Passed Failed Skipped
✅ nextjs-turbopack 27 0 0

📋 View full workflow run

@NathanColosimo
NathanColosimo marked this pull request as draft July 22, 2026 05:15
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