Commit Graph

1130 Commits

Author SHA1 Message Date
github-actions[bot] 822197c886 Version Packages (#2426) workflow@4.6.0 2026-07-06 12:23:48 -07:00
Peter Wielander d0e4191b7e [core] Correct byte-stream framing capability cutoff (stable) (#2768) 2026-07-03 15:59:58 -07:00
github-actions[bot] 6dbe2de33f fix(world-local): rebuild hook caches from event log (#2747) (#2766)
Signed-off-by: Nathan Colosimo <110621881+NathanColosimo@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-07-02 23:18:24 +00:00
github-actions[bot] b534da2388 Fix Postgres step lifecycle event ordering (#2714) (#2756)
* Fix Postgres step start event ordering

* Document Postgres step start transaction

* Increase canary HMR e2e timeouts

* Address Postgres lifecycle review comments

Signed-off-by: Nathan Colosimo <110621881+NathanColosimo@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-07-02 12:04:14 -07:00
github-actions[bot] 980933fd43 fix(nitro): pass workflow dirs to builders (#2722) (#2754)
Signed-off-by: Nathan Colosimo <110621881+NathanColosimo@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-07-02 19:00:35 +00:00
github-actions[bot] 4b422493cd fix(vitest): derive workflow cwd from project root (#2726) (#2755)
* fix(vitest): derive workflow cwd from project root

* chore(vitest): simplify project root options

Signed-off-by: Nathan Colosimo <110621881+NathanColosimo@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-07-02 18:59:15 +00:00
github-actions[bot] 01265b748c fix(next): derive workflow project root (#2729) (#2743)
* fix(next): derive workflow project root

* test(next): clean temp root after leaving app dir

* chore(next): simplify project root detection

* chore(next): mirror root detection

Signed-off-by: Nathan Colosimo <110621881+NathanColosimo@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-07-02 11:10:57 -07:00
github-actions[bot] c4bc5a1590 fix(vite-frameworks): derive workflow roots (#2725) (#2753)
* fix(vite-frameworks): derive workflow roots

* chore(vite-frameworks): simplify derived roots

* chore(vite-frameworks): simplify root derivation

* fix(sveltekit): respect configured routes directory

* test(frameworks): cover builder option pass-through

* test(frameworks): remove builder option tests

* fix(sveltekit): assert loaded routes config

* docs(sveltekit): note internal config loader

Signed-off-by: Nathan Colosimo <110621881+NathanColosimo@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-07-02 11:10:42 -07:00
github-actions[bot] aa9919b14e fix(next): prewarm SWC plugin cache (#2538) (#2576)
Co-authored-by: Nathan Colosimo <110621881+NathanColosimo@users.noreply.github.com>
2026-07-02 11:08:23 -07:00
github-actions[bot] ef60d31963 fix(ai): recover from invalid tool-call input instead of aborting the agent stream (#2699) (#2703)
#2192 by @boomyao

Co-authored-by: yao <zhangyaoruo@outlook.com>
Co-authored-by: Peter Wielander <mittgfu@gmail.com>
2026-07-01 20:12:22 +00:00
github-actions[bot] f927d6933b fix(nitro): use workspaceDir for monorepos (#2713) (#2720)
* fix(nitro): use workspaceDir for monorepos

* test: stabilize Next canary HMR e2e

Signed-off-by: Nathan Colosimo <110621881+NathanColosimo@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-07-01 20:10:56 +00:00
github-actions[bot] cfb8f770ac fix(ai): continue durable agent tool loops (#2730) (#2740)
Co-authored-by: Nathan Colosimo <110621881+NathanColosimo@users.noreply.github.com>
2026-07-01 18:31:14 +00:00
github-actions[bot] 50492d760c Fix workflow Postgres enum schemas (#2705) (#2717)
Signed-off-by: Nathan Colosimo <110621881+NathanColosimo@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-30 14:37:49 -07:00
github-actions[bot] 643cae23d3 test: reduce e2e timing flakes (#2665) (#2701)
* test: reduce e2e timing flakes

* test: tighten e2e timing bounds

Signed-off-by: Nathan Colosimo <110621881+NathanColosimo@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-30 10:33:34 -07:00
github-actions[bot] 02c8e4d9d4 Upgrade workspace to TypeScript 6 (#2700) (#2706)
* Upgrade workspace to TypeScript 6

* Restore Nest baseUrl for SWC builds

* Use empty changeset for TS6 upgrade

* Remove TS6 changeset

Signed-off-by: Nathan Colosimo <110621881+NathanColosimo@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Nathan Colosimo <110621881+NathanColosimo@users.noreply.github.com>
2026-06-30 10:33:13 -07:00
github-actions[bot] 504cf88465 Fix graph extraction for annotated step proxies (#2702) (#2710)
Signed-off-by: Nathan Colosimo <110621881+NathanColosimo@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-30 10:32:55 -07:00
Nathan Colosimo db90c40a13 Fix Nitro Vercel workflow routes (#2645)
* Fix Nitro Vercel workflow routes

* Simplify Nitro Vercel route fix

* Support latest Nitro 3 stable builds

* Remove unused Nitro Vercel webhook function output

* Use generated Vercel functions for Nitro workflow routes
2026-06-30 06:06:53 +00:00
github-actions[bot] 04e78129dc Propagate trace context to vercel-workflow.com in workbench instrumentation (#2601) (#2602)
* Propagate trace context to vercel-workflow.com in workbench instrumentation

@vercel/otel only propagates W3C trace context to Vercel deployment URLs
by default, so outgoing requests to the workflow-server
(vercel-workflow.com) got a client span with no `traceparent` header —
breaking the APM trace link to workflow-server's spans. Add
`instrumentationConfig.fetch.propagateContextUrls` for the workflow-server
domain in every workbench that uses @vercel/otel: example,
nextjs-turbopack, nextjs-webpack, and sveltekit. The Next.js and SvelteKit
apps already declared @vercel/otel but weren't registering it at all; they
now do.



* Also propagate trace context to the Vercel Queue Service (vercel-queue.com)

The workflow-server queue path (@vercel/queue) sends to regional
vercel-queue.com subdomains (e.g. iad1.vercel-queue.com) when not using the
queues proxy, which were missing a `traceparent` header for the same reason
as vercel-workflow.com. Add `/vercel-queue\.com/` to propagateContextUrls in
all four workbench instrumentation configs.



---------

Signed-off-by: Pranay Prakash <pranay.gp@gmail.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Peter Wielander <mittgfu@gmail.com>
2026-06-29 13:04:09 -07:00
github-actions[bot] 67fcf1a750 Redrive on transient workflow-server transport failures instead of failing the run (#2445) (#2689)
* Redrive on transient workflow-server transport failures instead of failing the run

A firewall in front of workflow-server shedding load with sustained 429/503
makes undici's shared RetryAgent exhaust its retries and throw
UND_ERR_REQ_RETRY. That raw error was rethrown unwrapped, so it was
classified as USER_ERROR and the replay terminal branch wrote run_failed —
permanently failing a run on a transient blip (or, in an outage, falling back
to the ~5min queue visibility-timeout redrive).

- world-vercel: map exhausted-retry / socket / connect / DNS / timeout
  failures to a typed WorkflowWorldError (code TRANSPORT/TIMEOUT) by walking
  the fetch() cause chain.
- core: add isRetryableWorldError (429 / 5xx / TRANSPORT / TIMEOUT) and
  rethrow such errors from the replay terminal branch so the queue redrives
  quickly (1s->60s backoff) instead of failing the run. Reuse it in start()
  and step_started handling.
- world-vercel: surface the Vercel firewall x-vercel-mitigated
  (challenge/deny) header alongside x-vercel-id in error diagnostics and logs.



* Address review: back off + cap on every retry path; fix mock; refine scope

Revises the transport-error handling per PR review (VaguelySerious,
karthikscale3).

Blocking fix — step_started no longer self-enqueues a throttled defer for
transient world errors. Returning `{ type: 'throttled', timeoutSeconds: 1 }`
acked the delivery and enqueued a fresh message, resetting the delivery count
so the path never backed off and never reached MAX_QUEUE_DELIVERIES — an
unbounded flat-1s loop if step_started kept failing. It now throws, so the
error flows through the replay loop's retryable-world-error rethrow and earns
both the delivery-count backoff and the max-delivery cap. Throwing is safe on
step_started (the body hasn't run; a write that landed dedupes to skipped).

Also in this revision:
- Backoff that lasts: raise the queue handler-error retry ceiling 60s -> 900s.
  VQS clamps each redelivery to its 900s SQS limit and adds its own post-32
  exponential, so ramping our base toward 900s stretches survival from ~3.7h to
  most of the 24h message-visibility window. Corrected the stale
  MAX_QUEUE_DELIVERIES comment to match the real VQS schedule.
- Stop amplifying firewall challenges: the undici RetryAgent no longer retries
  429 in-process (a challenge is a 429 the client can't solve). 429s surface
  immediately as ThrottleError carrying x-vercel-mitigated / x-vercel-id, so
  the diagnostic header now reaches us for the challenge case too.
- Track world faults as WORLD_CONTRACT_ERROR (not USER_ERROR) in
  classifyRunError so an outage isn't attributed to user code.
- Fix queue.test.ts mock that `biome check --write` had rewritten from a
  newable `function` into an arrow (broke `new QueueClient`); pin with a
  biome-ignore.

All Vercel-specific logic stays in @workflow/world-vercel; @workflow/core
operates only on the generic WorkflowWorldError abstraction.



* Update .changeset/transport-error-redrive.md



* Trim changeset to a single sentence per review



* Route firewall-challenge 429s to the retryable transport path, not ThrottleError

A 429 carrying `x-vercel-mitigated: challenge` is a firewall challenge our
server-to-server client cannot solve, so it recurs for the life of the
incident. Mapping it to `ThrottleError` meant the `step_started` write deferred
it as `{ type: 'throttled' }`, which self-enqueues a FRESH queue message and
resets the delivery count — so it never backed off past `retryAfter` and never
reached `MAX_QUEUE_DELIVERIES`, hot-looping against an already-overloaded
firewall (the exact amplification this PR set out to remove, and contrary to
the "step_started can't loop unbounded" invariant, which only held for 5xx).

Map a challenge to a retryable transport `WorkflowWorldError` (`code:
'TRANSPORT'`) in both the v3 `makeRequest` and v4 `throwForErrorResponse`
(the hot event-write path) error mappings, via a shared `isFirewallChallenge429`
helper. It then propagates through the V1/V2 step paths and the replay loop's
retryable-world-error rethrow, earning the delivery-count backoff AND the
delivery cap. A genuine application-level 429 (no `challenge` mitigation) stays
a `ThrottleError` and keeps its `Retry-After`-paced defer.

Also correct the survival-window comments: with the 900s ceiling,
MAX_QUEUE_DELIVERIES=48 spans ~9-10h (~35,000s), not "the better part of 24h";
reaching 24h would need a higher delivery cap, not a higher per-hop ceiling.



---------

Signed-off-by: Peter Wielander <mittgfu@gmail.com>
Signed-off-by: Pranay Prakash <pranay.gp@gmail.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Peter Wielander <mittgfu@gmail.com>
Co-authored-by: Peter Wielander <peter.wielander@vercel.com>
2026-06-29 13:03:50 -07:00
github-actions[bot] 8db7b7f864 Backport #2564: fix(next): discover root entrypoints (#2578) 2026-06-29 13:02:01 -07:00
github-actions[bot] af08c04da6 fix(nitro): reload steps during Vite HMR (#2572) (#2639) 2026-06-29 13:01:42 -07:00
github-actions[bot] 6f8730acc1 [ai] Fix WorkflowChatTransport reconnect test stale after framing normalizer (#2681) (#2682)
Co-authored-by: Peter Wielander <mittgfu@gmail.com>
2026-06-26 17:04:04 -07:00
github-actions[bot] cee802dd85 fix(ai): ignore intentional stream aborts (#2635) (#2641)
Co-authored-by: Nathan Colosimo <110621881+NathanColosimo@users.noreply.github.com>
2026-06-26 22:17:26 +00:00
github-actions[bot] a06f4250b1 [ai] Fix "missing text part" stream crash by repairing UI message framing (#2537) (#2672)
Signed-off-by: Peter Wielander <mittgfu@gmail.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-26 14:58:26 -07:00
github-actions[bot] b2e667ea2e [ci] Fix release "Premature close" by bounding changelog GraphQL batch size (#2669) (#2671)
Co-authored-by: Peter Wielander <mittgfu@gmail.com>
2026-06-26 14:45:48 -07:00
github-actions[bot] 280a34a403 [ai] Drop orphan UI chunks after negative-index reconnect (#2082) (#2670)
Co-authored-by: Peter Wielander <mittgfu@gmail.com>
2026-06-26 21:38:27 +00:00
github-actions[bot] af6ff4f358 [world-local] Scope untagged startup recovery to untagged runs (#2667) (#2668)
Co-authored-by: Peter Wielander <mittgfu@gmail.com>
2026-06-26 13:55:06 -07:00
github-actions[bot] 92ddf7a435 fix(world-postgres): defer loopback worker startup (#2657) (#2664)
Co-authored-by: Nathan Colosimo <110621881+NathanColosimo@users.noreply.github.com>
2026-06-26 19:26:50 +00:00
github-actions[bot] 97d4bd334d chore: ignore workflow swc caches (#2640) (#2650)
Signed-off-by: Nathan Colosimo <110621881+NathanColosimo@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-26 11:53:34 -07:00
github-actions[bot] 3eb7e97677 fix(world-postgres): rename setup command (#2644) (#2651)
Signed-off-by: Nathan Colosimo <110621881+NathanColosimo@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-25 16:54:42 -07:00
github-actions[bot] a0c030ad1c feat(web-shared): extend cn with custom tailwind-merge class groups (#2619) (#2623)
Move cn to its own lib/cn module that teaches tailwind-merge about the
design-system text-heading/text-label/text-copy/text-button/material
utilities, and import it directly from lib/cn.

Signed-off-by: Mitul Shah <mitulxshah@gmail.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
2026-06-25 14:25:20 -07:00
github-actions[bot] 87d213c096 [world] Make @workflow/world own its Zod dependency (#2622) (#2624)
* Make world own zod dependency

* Relax zod catalog range

Signed-off-by: Karthik Kalyan <105607645+karthikscale3@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-25 02:58:56 -07:00
github-actions[bot] 8bbf3312ad Backport #2594: Fix discovery of dotted JS workflow imports (#2611)
Signed-off-by: JJ Kasper <jj@jjsweb.site>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-24 18:19:47 +00:00
github-actions[bot] a4dd59be8c Backport #2565: Reduce workflow build log noise (#2598)
* Reduce workflow build log noise

* Label subsequent workflow builds as rebuilds

* apply suggestions from review

Signed-off-by: JJ Kasper <jj@jjsweb.site>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-24 11:11:24 -07:00
github-actions[bot] 9b972a7dd3 Thread occurredAt into web-shared entities (#2608) (#2609)
Signed-off-by: Karthik Kalyan <105607645+karthikscale3@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-23 17:50:48 -07:00
github-actions[bot] 9fba14e409 Send occurredAt with workflow events (#2580) (#2589)
* Send occurredAt with workflow events

* Fix occurredAt detail typing

Signed-off-by: Karthik Kalyan <105607645+karthikscale3@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Karthik Kalyan <105607645+karthikscale3@users.noreply.github.com>
2026-06-23 12:14:26 -07:00
github-actions[bot] 7b4998f1c6 Display occurredAt in trace details (#2581) (#2588)
Signed-off-by: Karthik Kalyan <105607645+karthikscale3@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-23 11:56:25 -07:00
github-actions[bot] ba62f575e2 Backport #2546: Optimize and fix the default eager build mode (#2558)
* Optimize and fix the default eager build mode (#2546)

Signed-off-by: JJ Kasper <jj@jjsweb.site>

* Fix stable backport eager step discovery

---------

Signed-off-by: JJ Kasper <jj@jjsweb.site>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Peter Wielander <mittgfu@gmail.com>
Co-authored-by: JJ Kasper <jj@jjsweb.site>
2026-06-22 23:04:30 +00:00
github-actions[bot] 0a5e2aa247 perf(core): memoize step return value hydration across inline replays (#2472) (#2563)
Co-authored-by: Pranay Prakash <pranay.gp@gmail.com>
2026-06-22 15:26:48 -07:00
github-actions[bot] 2a688f0a03 Backport #2055 + #2415 to stable: [world-vercel] v4 event wire format + lazy metadata-only listings (#2414)
Co-authored-by: Peter Wielander <mittgfu@gmail.com>
2026-06-22 15:19:55 -07:00
github-actions[bot] bec85d078b Backport #2334: [core] Retry stream reopen against the reconnect budget (#2574)
Co-authored-by: Peter Wielander <mittgfu@gmail.com>
2026-06-22 22:15:55 +00:00
github-actions[bot] 22730357b1 [docs] Document minimum SDK version for using hook.getConflict (#2423) (#2561)
Signed-off-by: Peter Wielander <mittgfu@gmail.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-22 13:26:22 -07:00
github-actions[bot] 3848f3cb6c Amend lazy discovery removal changeset (#2560) (#2562) 2026-06-22 13:22:09 -07:00
github-actions[bot] c5d14c8a89 Backport #2545: Remove lazy discovery from workflow/next (#2557)
* Remove lazy discovery from workflow/next (#2545)

Signed-off-by: JJ Kasper <jj@jjsweb.site>

* Remove lazy discovery config from Next workbenches

---------

Signed-off-by: JJ Kasper <jj@jjsweb.site>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: JJ Kasper <jj@jjsweb.site>
2026-06-22 20:10:34 +00:00
github-actions[bot] e0a4da4f9c Update default CODEOWNERS (#2556) (#2559)
Co-authored-by: JJ Kasper <jj@jjsweb.site>
2026-06-22 13:08:39 -07:00
Peter Wielander 5a4c6cff3e perf(core): cache local dev server port per process (backport #2522) (#2528) 2026-06-22 12:59:44 -07:00
github-actions[bot] 2783ae3f21 Backport #2351: [vitest] Fix local imports failing to load in test step bundles (#2542)
Co-authored-by: Peter Wielander <mittgfu@gmail.com>
Co-authored-by: Peter Wielander <peter.wielander@vercel.com>
2026-06-22 11:31:14 -07:00
github-actions[bot] 4c49cc8895 [builders] Fix unicode-escape crash in workflow graph extraction (#2324) (#2541)
Co-authored-by: EfeDurmaz16 <efebarandurmaz05@gmail.com>
Co-authored-by: Peter Wielander <mittgfu@gmail.com>
2026-06-20 12:49:09 -07:00
github-actions[bot] 015452a70c perf(core): drain consumable replay events synchronously (#2473) (#2504)
* docs(core): document scheduleWhenIdle macrotask is load-bearing

Revert the synchronous consume-loop drain optimization: it caused a
replay divergence (ReplayDivergenceError on step_started →
CorruptedEventLogError) in the world-testing inline-batches parallel
workflow on the Windows CI runner. The per-event `process.nextTick` in
the consume loop is load-bearing — it guarantees at most one event is
consumed per macrotask, letting the cross-VM `resolve → workflow VM body
→ subscribe()` chain register the next operation's consumer before the
drain advances. A synchronous drain races ahead of that registration.

What remains is a documentation comment on `scheduleWhenIdle` capturing
why its initial `setTimeout(0)` must not be downgraded to a microtask
(empirically: queueMicrotask breaks hook/sleep Promise.race ordering →
CorruptedEventLogError). No behavior change.



* docs(core): use empty changeset for comment-only macrotask doc

The scheduleWhenIdle change is a pure code comment with no consumer-facing
effect, so it does not warrant a patch bump / changelog entry. Replace the
patch changeset with an empty one to satisfy the changeset-bot convention
without claiming a release. Per the PR template's `pnpm changeset --empty`
guidance for non-releasing changes.




* perf(core): drain consumable replay events synchronously

The EventsConsumer rescheduled `process.nextTick(this.consume)` after every
consumed event, so replaying N already-consumable events (structural
lifecycle events, step_created/step_started, completed deliveries) cost N
macrotask hops — O(N) per consume wave across a sequential replay.

Drain consecutively consumable events within a single synchronous pass
instead. This is safe because callbacks only ever consume events with a
consumer that is already registered; new consumers are registered by
workflow VM body code that runs asynchronously off ctx.promiseQueue after a
delivery resolve(). When the next event's consumer is not yet registered,
no callback consumes it and we fall through to the existing cross-VM-safe
deferred unconsumed-event check, exactly as before. A null end-of-events
sentinel never continues the drain, so it cannot spin past end-of-log.

scheduleWhenIdle is intentionally left unchanged: its initial setTimeout(0)
is load-bearing for cross-VM propagation (pendingDeliveries is already 0
between a delivery resolve() and the VM body registering its next
subscriber). Replacing it with queueMicrotask empirically breaks hook/sleep
Promise.race ordering (CorruptedEventLogError); a comment now records this.

Re-validated after a premature revert: the windows-unit flake that prompted
the revert reproduces on unmodified main at the same rate (local 8-way
harness: opt 4/80 vs main 7/80; main historical windows-unit ~13%), so it is
a pre-existing flake, not a regression from this change.



---------

Signed-off-by: Pranay Prakash <pranay.gp@gmail.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 09:18:50 -07:00
github-actions[bot] 170ea9659a perf(core): cache compiled workflow-bundle vm.Script across replays (#2471) (#2506)
* perf(core): cache compiled workflow-bundle vm.Script across replays

The inline replay loop calls runWorkflow on every iteration, and each call
re-parsed the entire workflow bundle string via vm.runInContext. For a bundle
containing many workflow definitions (the production shape: one workflow called
per replay), this re-scans every definition on every replay.

Cache the compiled vm.Script per process, keyed by (workflowCode, filename),
and run it against the fresh context instead of recompiling. Compilation is a
pure function of (code, filename), so the result is byte-identical to the
previous re-parse-every-time behaviour — determinism is preserved. filename is
part of the key because it drives source attribution in stack traces (consumed
by remapErrorStack).

Measured per-replay savings scale with bundle size (and multiply by replay
count): ~34% for a 50-workflow app, ~59% for 155 workflows, ~80% for 400.



* perf(core): bound script cache with LRU; soften determinism claim; add tests

Addresses review on #2471:

- Bound `scriptCache` to a small LRU (cap 8 bundle versions). Production
  serves one bundle per process so the bound is never reached; it exists for
  dev/watch mode, where each edit produces a new bundle string that would
  otherwise be pinned forever (~0.8MB/edit, monotonic). Touch-on-access keeps
  the latest bundle hot; evicting a `code` entry drops its per-filename scripts
  together, restoring pre-cache GC behaviour.
- Document precisely why keying includes `filename` (intentional: drives
  stack-trace attribution via `remapErrorStack`; NOT a dedupe key), and that
  the whole bundle is compiled once per distinct filename.
- Soften the "byte-identical including thrown errors" claim to
  same-workflow-function + same-`filename`-attribution, noting the one caveat:
  a lookup-expression error's line number shifts to line 1 of the separate
  lookup Script. Updated in both the code comment and the PR description.
- Add tests: cache-is-bounded regression (eviction past the cap), LRU recency
  (hot bundle survives churn), and a realistic multi-workflow collision test
  (distinct code/filename never returns the wrong Script, results carry their
  own bundle marker).



---------

Signed-off-by: Pranay Prakash <pranay.gp@gmail.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 09:18:06 -07:00