Skip to content

feat(core): deterministic sandbox hardening - #3045

Merged
NathanColosimo merged 7 commits into
mainfrom
nathanc/vm-determinism-hardening
Jul 27, 2026
Merged

feat(core): deterministic sandbox hardening#3045
NathanColosimo merged 7 commits into
mainfrom
nathanc/vm-determinism-hardening

Conversation

@NathanColosimo

@NathanColosimoNathanColosimo commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Summary

First of a 3-PR stack extracted from #2990 (retained-VM replay) for easier review. This PR contains only the sandbox determinism changes — every piece is a standalone win, independent of retention:

  • crypto.subtle.digest computes synchronously via node:crypto — byte-identical to WebCrypto (verified for SHA-1/256/384/512; createHash is stable and undeprecated through Node 26), so the promise settles at a deterministic point during replay instead of host threadpool timing. Full BufferSource contract: TypeError on non-buffer input, internal-slot view metadata reads, SharedArrayBuffer-backed views rejected.
  • Removed from the sandbox: Atomics.waitAsync (a wall-clock timer via SharedArrayBuffer), async WebAssembly compilation (compile/instantiate/…Streaming; the sync new WebAssembly.Module()/Instance() constructors remain), WeakRef, and FinalizationRegistry. Wall-clock timing and GC observation are unreplayable with or without retention.

No prototypes are frozen and no global bindings are pinned — workflow code can patch built-ins freely (Temporal / core-js polyfills keep working). Serialization safety is instead handled in part 3 of the stack, where serialization reads values through captured host intrinsics and reports when it had to execute workflow code.

Review focus

The user-facing semantic changes of the whole stack are isolated here: the compat question is "does deleting X break any real workflow bundle?"

Validation

  • pnpm --filter @workflow/core typecheck + build
  • full core unit suite green: 1,525 passed, 3 expected failures
  • sandbox tests cover: digest value parity vs WebCrypto + input validation, removed-API absence

Stack: this PR → #3046 (feature, primitives-gated) → #3047 (full argument-type support via taint-reporting hardened serialization). #2990 stays open as the reference implementation.

@NathanColosimo
NathanColosimo requested review from a team and ijjk as code ownersJuly 22, 2026 02:32
@changeset-bot

changeset-botBot commented Jul 22, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: f809de2

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

This PR includes changesets to release 16 packages
NameType
@workflow/coreMajor
workflowMajor
@workflow/buildersPatch
@workflow/cliPatch
@workflow/nextPatch
@workflow/nitroPatch
@workflow/vitestPatch
@workflow/web-sharedPatch
@workflow/webPatch
@workflow/world-testingPatch
@workflow/astroPatch
@workflow/nestPatch
@workflow/nuxtPatch
@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

@vercel

vercelBot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

@NathanColosimo
NathanColosimoforce-pushed the nathanc/vm-determinism-hardening branch from 02636d5 to cb05683CompareJuly 22, 2026 02:32
@github-actions

github-actionsBot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

🧪 E2E Test Results

All tests passed

E2E Test Summary

Summary
PassedFailedSkippedTotal
✅ ▲ Vercel Production145502391694
✅ 💻 Local Development162102271848
✅ 📦 Local Production162102271848
✅ 🐘 Local Postgres162102271848
✅ 🪟 Windows15400154
✅ 📋 Other102002121232
✅ vercel-multi-region270027
Total7519011328651
Details by Category

✅ ▲ Vercel Production

AppPassedFailedSkipped
✅ astro126028
✅ example126028
✅ express126028
✅ fastify126028
✅ hono126028
✅ nextjs-turbopack15103
✅ nextjs-webpack15103
✅ nitro126028
✅ nuxt126028
✅ sveltekit14509
✅ vite126028

✅ 💻 Local Development

AppPassedFailedSkipped
✅ astro-stable128026
✅ express-stable128026
✅ fastify-stable128026
✅ hono-stable128026
✅ nextjs-turbopack-canary135019
✅ nextjs-turbopack-stable15400
✅ nextjs-webpack-canary135019
✅ nextjs-webpack-stable15400
✅ nitro-stable128026
✅ nuxt-stable128026
✅ sveltekit-stable14707
✅ vite-stable128026

✅ 📦 Local Production

AppPassedFailedSkipped
✅ astro-stable128026
✅ express-stable128026
✅ fastify-stable128026
✅ hono-stable128026
✅ nextjs-turbopack-canary135019
✅ nextjs-turbopack-stable15400
✅ nextjs-webpack-canary135019
✅ nextjs-webpack-stable15400
✅ nitro-stable128026
✅ nuxt-stable128026
✅ sveltekit-stable14707
✅ vite-stable128026

✅ 🐘 Local Postgres

AppPassedFailedSkipped
✅ astro-stable128026
✅ express-stable128026
✅ fastify-stable128026
✅ hono-stable128026
✅ nextjs-turbopack-canary135019
✅ nextjs-turbopack-stable15400
✅ nextjs-webpack-canary135019
✅ nextjs-webpack-stable15400
✅ nitro-stable128026
✅ nuxt-stable128026
✅ sveltekit-stable14707
✅ vite-stable128026

✅ 🪟 Windows

AppPassedFailedSkipped
✅ nextjs-turbopack15400

✅ 📋 Other

AppPassedFailedSkipped
✅ e2e-local-dev-nest-stable128026
✅ e2e-local-dev-tanstack-start-128026
✅ e2e-local-postgres-nest-stable128026
✅ e2e-local-postgres-tanstack-start-128026
✅ e2e-local-prod-nest-stable128026
✅ e2e-local-prod-tanstack-start-128026
✅ e2e-vercel-prod-nest126028
✅ e2e-vercel-prod-tanstack-start126028

✅ vercel-multi-region

AppPassedFailedSkipped
✅ nextjs-turbopack2700

📋 View full workflow run

@github-actions

github-actionsBot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

📊 Workflow Benchmarks

commit f809de2 · Sat, 25 Jul 2026 00:07:28 GMT · run logs

Backend: vercel · app: nextjs-turbopack

MetricScenarioBest (ms)P75 (ms)P90 (ms)P99 (ms)Samples
TTFSstep1295 (+31%) 🔻1381 🔴 (+27%) 🔻1400 🔴 (+21%) 🔻1411 🔴 (+17%) 🔻30
TTFSstream340 (+47%) 🔻1346 🔴 (+24%) 🔻1364 🔴 (+21%) 🔻1426 🔴 (±0%)30
TTFShook + stream1505 (+53%) 🔻1641 🔴 (+14%)1676 🔴 (+11%)1938 🔴 (+17%) 🔻30
STSO1020 steps (1-20)183 (-9.9%)263 🔴 (-5.4%)297 🔴 (-21%) 💚545 🔴 (+20%) 🔻19
STSO1020 steps (101-120)205 (-11%)306 🔴 (-7.6%)590 🔴 (+46%) 🔻997 🔴 (-16%) 💚19
STSO1020 steps (1001-1020)450 (-11%)561 🔴 (-3.8%)583 🔴 (-6.9%)658 🔴 (-4.2%)19
WO1020 steps401305 (-5.4%)401305 (-5.4%)401305 (-5.4%)401305 (-5.4%)1
SLstream latency97 (-10%)211 🔴 (+31%) 🔻376 🔴 (+102%) 🔻426 🔴 (+70%) 🔻30
SOstream overhead (text)120 (-20%) 💚172 (-28%) 💚206 (-21%) 💚308 (-17%) 💚30
SOstream overhead (structured)110 (-29%) 💚169 (-26%) 💚207 (-14%)280 (-12%)30
📜 Previous results (6)

db1665f

Fri, 24 Jul 2026 23:23:29 GMT · run logs

vercel / nextjs-turbopack

MetricScenarioBest (ms)P75 (ms)P90 (ms)P99 (ms)Samples
TTFSstep1367 (+91%) 🔻1427 🔴 (+38%) 🔻1450 🔴 (+35%) 🔻1625 🔴 (+29%) 🔻30
TTFSstream222 (-76%) 💚1332 🔴 (+30%) 🔻1395 🔴 (+35%) 🔻1440 🔴 (+24%) 🔻30
TTFShook + stream492 (-58%) 💚1602 🔴 (+25%) 🔻1632 🔴 (+25%) 🔻1669 🔴 (+17%) 🔻30
STSO1020 steps (1-20)201 (+22%) 🔻321 🔴 (+16%) 🔻510 🔴 (+26%) 🔻544 🔴 (+31%) 🔻19
STSO1020 steps (101-120)206 (+19%) 🔻307 🔴 (+30%) 🔻346 🔴 (+32%) 🔻495 🔴 (+21%) 🔻19
STSO1020 steps (1001-1020)517 (+12%)557 🔴 (+5.7%)639 🔴 (+14%)806 🔴 (+43%) 🔻19
WO1020 steps425419 (+9.0%)425419 (+9.0%)425419 (+9.0%)425419 (+9.0%)1
SLstream latency102 (+28%) 🔻156 🔴 (+42%) 🔻179 🔴 (+30%) 🔻679 🔴 (+97%) 🔻30

9abf488

Fri, 24 Jul 2026 21:50:34 GMT · run logs

vercel / nextjs-turbopack

MetricScenarioBest (ms)P75 (ms)P90 (ms)P99 (ms)Samples
TTFSstep449 (-54%) 💚1403 🔴 (+32%) 🔻1426 🔴 (+31%) 🔻1453 🔴 (-3.6%)30
TTFSstream1270 (+29%) 🔻1385 🔴 (+31%) 🔻1404 🔴 (+31%) 🔻1440 🔴 (+33%) 🔻30
TTFShook + stream639 (-46%) 💚1542 🔴 (+17%) 🔻1577 🔴 (+11%)1748 🔴 (-16%) 💚30
STSO1020 steps (1-20)165 (+1.2%)255 🔴 (-1.9%)319 🔴 (-1.8%)373 🔴 (-14%)19
STSO1020 steps (101-120)178 (-4.8%)230 🔴 (-10%)298 🔴 (-18%) 💚568 🔴 (+38%) 🔻19
STSO1020 steps (1001-1020)466 (+1.1%)568 🔴 (+1.6%)702 🔴 (+1.9%)3429 🔴 (+378%) 🔻19
WO1020 steps374546 (-2.8%)374546 (-2.8%)374546 (-2.8%)374546 (-2.8%)1
SLstream latency91 (+8.3%)128 🔴 (+8.5%)141 🔴 (-12%)198 🔴 (-7.0%)30

8e23cfa

Thu, 23 Jul 2026 23:42:57 GMT · run logs

vercel / nextjs-turbopack

MetricScenarioBest (ms)P75 (ms)P90 (ms)P99 (ms)Samples
TTFSstep1230 (+252%) 🔻1281 🔴 (+26%) 🔻1333 🔴 (+29%) 🔻1598 🔴 (+15%) 🔻30
TTFSstream1225 (+34%) 🔻1277 🔴 (+22%) 🔻1302 🔴 (+23%) 🔻3379 🔴 (+134%) 🔻30
TTFShook + stream505 (-55%) 💚1556 🔴 (+16%) 🔻1567 🔴 (+11%)1704 🔴 (+12%)30
STSO1020 steps (1-20)153 (-13%)293 🔴 (+5.8%)306 🔴 (-32%) 💚543 🔴 (+21%) 🔻19
STSO1020 steps (101-120)174 (-7.4%)222 🔴 (-20%) 💚237 🔴 (-27%) 💚277 🔴 (-17%) 💚19
STSO1020 steps (1001-1020)474 (+4.6%)604 🔴 (+6.3%)706 🔴 (+2.0%)3411 🔴 (+309%) 🔻19
WO1020 steps374335 (-4.7%)374335 (-4.7%)374335 (-4.7%)374335 (-4.7%)1
SLstream latency79 (-1.3%)122 🔴 (-3.2%)129 🔴 (-12%)142 🔴 (-66%) 💚30

9395b2d

Thu, 23 Jul 2026 23:12:23 GMT · run logs

vercel / nextjs-turbopack

MetricScenarioBest (ms)P75 (ms)P90 (ms)P99 (ms)Samples
TTFSstep221 (-37%) 💚1277 🔴 (+25%) 🔻1295 🔴 (+25%) 🔻1366 🔴 (-1.7%)30
TTFSstream236 (-74%) 💚1323 🔴 (+27%) 🔻1330 🔴 (+25%) 🔻1478 🔴 (+2.6%)30
TTFShook + stream415 (-63%) 💚1535 🔴 (+15%)1574 🔴 (+11%)1627 🔴 (+7.3%)30
STSO1020 steps (1-20)169 (-4.0%)280 🔴 (+1.1%)340 🔴 (-24%) 💚356 🔴 (-21%) 💚19
STSO1020 steps (101-120)192 (+2.1%)270 🔴 (-2.2%)321 🔴 (-0.9%)1123 🔴 (+236%) 🔻19
STSO1020 steps (1001-1020)480 (+6.0%)540 🔴 (-4.9%)563 🔴 (-19%) 💚616 🔴 (-26%) 💚19
WO1020 steps403173 (+2.6%)403173 (+2.6%)403173 (+2.6%)403173 (+2.6%)1
SLstream latency88 (+10%)156 🔴 (+24%) 🔻179 🔴 (+23%) 🔻215 🔴 (-49%) 💚30

b908241

Wed, 22 Jul 2026 17:59:42 GMT · run logs

vercel / nextjs-turbopack

MetricScenarioBest (ms)P75 (ms)P90 (ms)P99 (ms)Samples
TTFSstep167 (+4.4%)331 🔴 (-18%) 💚354 🔴 (-24%) 💚555 (+5.9%)30
TTFSstream151 (-9.0%)336 🔴 (+28%) 🔻371 🔴 (+24%) 🔻431 (-14%)30
TTFShook + stream349 (+4.5%)499 🔴 (-9.4%)588 🔴 (-6.1%)938 🔴 (+15%)30
STSO1020 steps (1-20)212 (+10%)353 🔴 (+17%) 🔻377 🔴 (+7.7%)561 🔴 (-19%) 💚19
STSO1020 steps (101-120)250 (+1.6%)392 🔴 (+3.7%)425 🔴 (-16%) 💚694 🔴 (+9.5%)19
STSO1020 steps (1001-1020)688 (±0%)977 🔴 (+11%)1202 🔴 (+17%) 🔻6811 🔴 (+561%) 🔻19
WO1020 steps627015 (-6.1%)627015 (-6.1%)627015 (-6.1%)627015 (-6.1%)1
SLstream latency96 (+16%) 🔻145 🔴 (+21%) 🔻200 🔴 (+9.9%)436 🔴 (+27%) 🔻30

cb05683

Wed, 22 Jul 2026 02:47:52 GMT · run logs

vercel / nextjs-turbopack

MetricScenarioBest (ms)P75 (ms)P90 (ms)P99 (ms)Samples
TTFSstep148 (+21%) 🔻222 🔴 (-7.5%)382 🔴 (+18%) 🔻2459 🔴 (+471%) 🔻30
TTFSstream128 (-17%) 💚210 🔴 (-38%) 💚277 (-25%) 💚582 (+26%) 🔻30
TTFShook + stream332 (+7.8%)518 🔴 (+12%)539 🔴 (+6.1%)672 🔴 (+8.2%)30
STSO1020 steps (1-20)208 (+9.5%)376 🔴 (+28%) 🔻432 🔴 (+28%) 🔻516 🔴 (+48%) 🔻19
STSO1020 steps (101-120)256 (+15%)353 🔴 (+10.0%)431 🔴 (-11%)474 🔴 (-5.4%)19
STSO1020 steps (1001-1020)634 (+4.8%)741 🔴 (-5.2%)806 🔴 (-7.4%)833 🔴 (-25%) 💚19
WO1020 steps479397 (-9.3%)479397 (-9.3%)479397 (-9.3%)479397 (-9.3%)1
SLstream latency107 (+19%) 🔻151 🔴 (+0.7%)184 🔴 (+1.7%)336 🔴 (+47%) 🔻30
ℹ️ Metric definitions & methodology

Best/P75/P90/P99 deltas compare against the most recent benchmark run on main at the time of this run. 🔻 flags a delta worse than +15%, 💚 one better than −15%.

Metrics — TTFS: time to first step body (in-deployment start() → first step body, deployment clocks) · STSO: step-to-step overhead (gap between consecutive step bodies) · WO: workflow overhead (whole-run time outside step bodies, in-deployment anchored) · SL: stream latency (in-deployment write → read propagation, readAt - writtenAt) · SO: stream overhead (end-to-end write+consume time beyond the modelled generation window)

Scenarios — step: one trivial no-op step, no stream; no hooks, so the run stays in turbo mode (in-process fast path) · stream: one streaming step; no hooks, so the run stays in turbo mode (in-process fast path) · hook + stream: registers a hook before one step, which exits turbo mode (dispatch path) · 1020 steps: 1020 trivial sequential steps; STSO is measured between consecutive steps in the given step ranges, and WO is the whole-run overhead outside step bodies · stream latency: parallel reader/writer steps on a dedicated stream; SL is the in-deployment write->read propagation (readAt - writtenAt) · stream overhead (text): writer streams 300 variable-length text token deltas paced at 100/s for 3s (a haiku-size LLM's token throughput) while a parallel reader drains the whole stream; SO is the end-to-end write+consume time beyond the 3s generation window (overhead/backpressure) · stream overhead (structured): same workload as stream overhead (text), but each delta is an AI-SDK-style structured object ({ type: 'text-delta', id, text }) instead of a raw string, so the SO gap vs the text scenario is the added serialization cost

🔴 marks a percentile over its target (within target is left unmarked). Targets (p75/p90/p99, ms) — TTFS 200/300/600 · SL 50/60/125 · SO 250/500/1000 · STSO (1-20) 20/30/60 · STSO (101-120) 30/45/90 · STSO (1001-1020) 40/60/120

All metrics are measured from deployment-side timestamps only. Runs are triggered by an in-deployment route that stamps the anchor (clientStart) right before start(), so the CI runner’s request and its path through api.vercel.com sit outside every measured window. TTFS = in-deployment start() → first step body (turbo uses the in-process fast path, non-turbo the dispatch path), and includes the VQS dispatch hop plus any /flow cold start. STSO/WO are measured between step bodies on the deployment. SL is measured inside the workflow (parallel reader/writer steps), so it no longer includes the api.vercel.com read path.

Cold starts are kept in the numbers on purpose — they are part of real bursty-workload latency. The workbench deployment cold-starts the /flow invocation for a large fraction of runs, inflating P75+; the Best column shows the fastest (warm-start) sample for comparison.

@vercel
vercelBottemporarily deployed to Preview – workflow-docs July 22, 2026 02:32 Inactive
@NathanColosimo
NathanColosimo marked this pull request as draft July 22, 2026 05:14
- crypto.subtle.digest computes synchronously via node:crypto:
byte-identical values, promise settles on a deterministic microtask,
full BufferSource validation (internal-slot view reads, SAB rejection)
- Atomics.waitAsync (a wall-clock timer), async WebAssembly compilation,
WeakRef, and FinalizationRegistry are removed from the sandbox — wall
clock and GC observation are unreplayable; sync WebAssembly
constructors remain
- freezeSerializationIntrinsics pins the universal dispatch surfaces:
Object.prototype/Array.prototype/Function.prototype are frozen (every
missed property read and hasInstance lookup terminates there) and
serialization-referenced global bindings are non-writable. Value-type
prototypes and constructor statics stay patchable so polyfills
(Temporal's Date.prototype.toTemporalInstant, core-js Set.prototype
.union / Object.groupBy) keep working — the retained-input gate
verifies the members serialization executes per boundary instead.
Groundwork for retained-VM replay (#2990).
@NathanColosimo
NathanColosimoforce-pushed the nathanc/vm-determinism-hardening branch from cb05683 to b908241CompareJuly 22, 2026 17:41
…escence
The remaining async subtle methods reject immediately through the crypto
proxy (brand check — the receiver is not a real SubtleCrypto), so they can
never mint a host-timing promise. Narrow the quiescence comment to what the
code actually enforces and add a test so the unreachability is not silently
"fixed" later.

@TooTallNateTooTallNate left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Reviewed with the Slack thread context in mind (including the rescope that dropped prototype freezing / global pinning in favor of part-3 hardened serialization — which I think was the right call, and matches the compatibility concerns raised in the thread).

What I verified

  • Sync digest correctness: the captured-intrinsic view-metadata reads (buffer/byteOffset/byteLength via prototype getters + util.types brand checks) are exactly the right pattern — cross-realm safe, immune to shadowed own properties, and consistent with the hardened-serialization direction for part 3. Copying out of the pooled Buffer allocation is a nice catch. Value parity + BufferSource contract (TypeError on non-buffers, SAB rejection, subviews) are all test-covered.
  • The quiescence argument: I walked the sandbox surface looking for other host-timed promise sources — remaining crypto.subtle methods (brand-check rejection through the proxy receiver is deterministic and test-locked), dynamic import() (microtask rejection), injected web APIs (all sync), sync Atomics.wait (return value is deterministic in a single-agent realm — correctly left in). I found no gaps.
  • No internal usage: nothing in packages/core (VM-side runtime) or the workbench fixtures uses WeakRef/FinalizationRegistry/Atomics.waitAsync/async WASM.

Blocking

One item, inline: the changeset bump type should be major, not patch (details on the comment). Trivial fix.

Non-blocking notes

  • The E2E failure (writableForwardedFromStepWorkflow on nest) is an unrelated streams test — needs a rerun before merge but isn't caused by this diff.
  • digest({ name: 123 }) / digest({}) rejects with TypeError (from name.toUpperCase()), where WebCrypto's algorithm normalization does ToString first and rejects with NotSupportedError. Trivial divergence; fine to leave.
  • The /must be of type SubtleCrypto/ assertion matches V8's error wording, which isn't guaranteed stable across Node majors. Consider also accepting a looser match (e.g. asserting rejection with TypeError) so a Node bump doesn't break the suite — the important invariant is "rejects deterministically before scheduling crypto work", not the message.

Comment thread.changeset/vm-determinism-hardening.md Outdated

@TooTallNateTooTallNate left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Re-reviewed after the update. My blocking item is fixed, both nits are addressed, and the sandbox surface got materially stronger than what I reviewed last time. Approving.

Blocking item resolved: the changeset is now major on @workflow/core + workflow, and the description accurately enumerates the removals (Atomics.waitAsync, async WebAssembly, WeakRef, FinalizationRegistry) alongside the digest change — that's the signal a consumer needs to know a global disappeared.

Both nits addressed, and one beyond what I asked:

  • The V8-wording assertion is gone; the new test asserts /not available inside a workflow function/ against the SDK's own error, so a Node bump can't break it.
  • The subtle proxy now explicitly blocks every non-digest method with a clear WorkflowRuntimeError naming the method and pointing at step functions. Previously those methods were passed through and merely happened to reject on a V8 brand check through the proxy receiver — same practical outcome, but the failure was incidental and the message inscrutable. This makes the invariant intentional and self-documenting, and the new loop test locks in importKey/encrypt/sign/deriveBits.
  • Bonus fidelity: an unrecognized algorithm name now rejects with DOMException(..., 'NotSupportedError'), matching WebCrypto instead of a generic error.

I re-verified the causation question the stricter proxy raises: packages/core/src/encryption.ts does call crypto.subtle.importKey/encrypt/decrypt, so I checked whether any of it runs VM-side. It doesn't — workflow.ts imports it import type only (CryptoKey), the encrypt/decrypt call sites live in the host-side serialization paths, and pre-PR those methods already failed inside the sandbox anyway (the proxy returned them unbound). So encrypted workflows are unaffected; this is strictly a better error for code that could never have worked. Also re-confirmed no VM-side runtime or workbench workflow uses any of the four removed globals.

Verified locally: 34/34 vm tests, full core suite 1526 (+3 pre-existing expected-fails). The new "does not expose any API that settles on host timing" test is a good invariant guard, and keeping synchronous new WebAssembly.Module()/Instance() available while dropping the async entry points is the right line.

CI: all three failures are non-causal, and two share one remedy — merge main:

  • Unit Tests (windows-latest): world-testing's inline-batches-debug timeout — the shared-data-dir flake fixed by #3055, which merged after this branch's base and isn't present here.
  • Benchmark (vercel, nextjs-turbopack): 404 Benchmark workflow "benchSoWorkflow" not found. Neat artifact of PR staleness — Actions tests the PR merge commit (which carries main's newer bench test referencing benchSoWorkflow) while Vercel deploys the branch head (whose workbench predates that workflow). The branch itself is self-consistent (neither its test nor its workbench mentions it), so it's not a bad merge.
  • E2E Local Prod Tests (nextjs-turbopack - stable): webhookWorkflow timeout, no plausible path from this diff (webhooks touch none of the removed globals; hook-token generation goes through the already-deterministic crypto.randomUUID override).

A main merge should clear the first two and re-roll the third.

@github-actions

Copy link
Copy Markdown
Contributor

No backport to stable for d813fb8 (AI decision).

This is intentional breaking behavior change for the next major (the changeset marks @workflow/core/workflow as major): it removes Atomics.waitAsync, async WebAssembly compilation, WeakRef, and FinalizationRegistry from the workflow sandbox and makes all non-digestcrypto.subtle methods throw, so workflow bundles that use those APIs would break on stable. It also reimplements crypto.subtle.digest on node:crypto as groundwork for the main-only retained-VM replay work (#2990), not to fix a user-visible defect on the maintenance line.

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

d813fb8ee835c378db4428e1a9a7edb64cb0b494

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.

3 participants

@NathanColosimo@TooTallNate@VaguelySerious