Skip to content

Conversation

@TooTallNate
Copy link
Member

@TooTallNate TooTallNate commented Feb 8, 2026

Summary

Adds the Encryptor interface and threads it through the serialization layer, preparing the codebase for E2E encryption without yet wiring in any actual encryption logic.

New types (@workflow/world)

  • Encryptor — optional encrypt(), decrypt(), and getKeyMaterial() methods
  • EncryptionContext — contains runId for per-run key derivation
  • KeyMaterial — key bytes + derivation metadata for external tooling (o11y)
  • World now extends Encryptor — all methods optional, so existing implementations are unaffected
  • World.getEncryptorForRun?(runId) — resolves an Encryptor for a specific run's deployment context, enabling cross-deployment encryption (e.g., resumeHook() from a newer deployment)

Serialization signature changes

All 8 dehydrate/hydrate functions gain encryptor: Encryptor as a new parameter (prefixed with _ since it's unused in this PR):

Before After
dehydrateWorkflowArguments(value, ops, runId, ...) dehydrateWorkflowArguments(value, runId, encryptor, ops, ...)
hydrateWorkflowArguments(value, global, ...) hydrateWorkflowArguments(value, runId, encryptor, global, ...)
dehydrateStepReturnValue(value, ops, runId, ...) dehydrateStepReturnValue(value, runId, encryptor, ops, ...)
(and so on for all 8 functions)

Runtime changes

  • WorkflowOrchestratorContext — adds runId: string and encryptor: Encryptor
  • runWorkflow() — accepts encryptor as 4th parameter
  • resumeHook() — restructured with getHookByTokenWithEncryptor() to resolve the encryptor once and reuse for both metadata decryption and payload encryption (zero redundant key resolutions)
  • hydrateResourceIO() — accepts encryptor parameter, threaded from CLI/web callers

Cross-deployment design

When resumeHook() is called from a different deployment than the target workflow run, the encryption keys differ. The new World.getEncryptorForRun(runId) method allows the World implementation to resolve the correct key (e.g., via an authenticated API endpoint). The resumeHook flow resolves the encryptor once via getHookByTokenWithEncryptor() and reuses it for both operations.

Test plan

All 305 core tests pass. Build succeeds. The encryptor parameter is unused (_encryptor) in this PR — actual encryption is wired in PR #957.

@github-actions
Copy link
Contributor

github-actions bot commented Feb 8, 2026

🧪 E2E Test Results

⚠️ Results below are stale and not from the latest commit. This comment will be updated when CI completes on the latest run.

Tests are running...


Started at: 2026-02-09T23:19:18Z


Some tests failed

Summary

Passed Failed Skipped Total
✅ ▲ Vercel Production 490 0 38 528
✅ 💻 Local Development 418 0 62 480
✅ 📦 Local Production 418 0 62 480
✅ 🐘 Local Postgres 418 0 62 480
✅ 🪟 Windows 45 0 3 48
❌ 🌍 Community Worlds 32 160 12 204
✅ 📋 Other 123 0 21 144
Total 1944 160 260 2364

❌ Failed Tests

🌍 Community Worlds (160 failed)

mongodb (37 failed):

  • addTenWorkflow
  • addTenWorkflow
  • should work with react rendering in step
  • promiseAllWorkflow
  • promiseRaceWorkflow
  • promiseAnyWorkflow
  • hookWorkflow
  • webhookWorkflow
  • sleepingWorkflow
  • nullByteWorkflow
  • workflowAndStepMetadataWorkflow
  • fetchWorkflow
  • promiseRaceStressTestWorkflow
  • error handling error propagation workflow errors nested function calls preserve message and stack trace
  • error handling error propagation workflow errors cross-file imports preserve message and stack trace
  • error handling error propagation step errors basic step error preserves message and stack trace
  • error handling error propagation step errors cross-file step error preserves message and function names in stack
  • error handling retry behavior regular Error retries until success
  • error handling retry behavior FatalError fails immediately without retries
  • error handling retry behavior RetryableError respects custom retryAfter delay
  • error handling retry behavior maxRetries=0 disables retries
  • error handling catchability FatalError can be caught and detected with FatalError.is()
  • hookCleanupTestWorkflow - hook token reuse after workflow completion
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously
  • stepFunctionPassingWorkflow - step function references can be passed as arguments (without closure vars)
  • stepFunctionWithClosureWorkflow - step function with closure variables passed as argument
  • closureVariableWorkflow - nested step functions with closure variables
  • spawnWorkflowFromStepWorkflow - spawning a child workflow using start() inside a step
  • pathsAliasWorkflow - TypeScript path aliases resolve correctly
  • Calculator.calculate - static workflow method using static step methods from another class
  • AllInOneService.processNumber - static workflow method using sibling static step methods
  • ChainableService.processWithThis - static step methods using this to reference the class
  • thisSerializationWorkflow - step function invoked with .call() and .apply()
  • customSerializationWorkflow - custom class serialization with WORKFLOW_SERIALIZE/WORKFLOW_DESERIALIZE
  • instanceMethodStepWorkflow - instance methods with "use step" directive
  • crossContextSerdeWorkflow - classes defined in step code are deserializable in workflow context
  • stepFunctionAsStartArgWorkflow - step function reference passed as start() argument

redis (40 failed):

  • addTenWorkflow
  • addTenWorkflow
  • should work with react rendering in step
  • promiseAllWorkflow
  • promiseRaceWorkflow
  • promiseAnyWorkflow
  • hookWorkflow
  • webhookWorkflow
  • sleepingWorkflow
  • nullByteWorkflow
  • workflowAndStepMetadataWorkflow
  • fetchWorkflow
  • promiseRaceStressTestWorkflow
  • error handling error propagation workflow errors nested function calls preserve message and stack trace
  • error handling error propagation workflow errors cross-file imports preserve message and stack trace
  • error handling error propagation step errors basic step error preserves message and stack trace
  • error handling error propagation step errors cross-file step error preserves message and function names in stack
  • error handling retry behavior regular Error retries until success
  • error handling retry behavior FatalError fails immediately without retries
  • error handling retry behavior RetryableError respects custom retryAfter delay
  • error handling retry behavior maxRetries=0 disables retries
  • error handling catchability FatalError can be caught and detected with FatalError.is()
  • hookCleanupTestWorkflow - hook token reuse after workflow completion
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously
  • stepFunctionPassingWorkflow - step function references can be passed as arguments (without closure vars)
  • stepFunctionWithClosureWorkflow - step function with closure variables passed as argument
  • closureVariableWorkflow - nested step functions with closure variables
  • spawnWorkflowFromStepWorkflow - spawning a child workflow using start() inside a step
  • pathsAliasWorkflow - TypeScript path aliases resolve correctly
  • Calculator.calculate - static workflow method using static step methods from another class
  • AllInOneService.processNumber - static workflow method using sibling static step methods
  • ChainableService.processWithThis - static step methods using this to reference the class
  • thisSerializationWorkflow - step function invoked with .call() and .apply()
  • customSerializationWorkflow - custom class serialization with WORKFLOW_SERIALIZE/WORKFLOW_DESERIALIZE
  • instanceMethodStepWorkflow - instance methods with "use step" directive
  • crossContextSerdeWorkflow - classes defined in step code are deserializable in workflow context
  • stepFunctionAsStartArgWorkflow - step function reference passed as start() argument
  • pages router addTenWorkflow via pages router
  • pages router promiseAllWorkflow via pages router
  • pages router sleepingWorkflow via pages router

starter (42 failed):

  • addTenWorkflow
  • addTenWorkflow
  • should work with react rendering in step
  • promiseAllWorkflow
  • promiseRaceWorkflow
  • promiseAnyWorkflow
  • hookWorkflow
  • webhookWorkflow
  • sleepingWorkflow
  • nullByteWorkflow
  • workflowAndStepMetadataWorkflow
  • fetchWorkflow
  • promiseRaceStressTestWorkflow
  • error handling error propagation workflow errors nested function calls preserve message and stack trace
  • error handling error propagation workflow errors cross-file imports preserve message and stack trace
  • error handling error propagation step errors basic step error preserves message and stack trace
  • error handling error propagation step errors cross-file step error preserves message and function names in stack
  • error handling retry behavior regular Error retries until success
  • error handling retry behavior FatalError fails immediately without retries
  • error handling retry behavior RetryableError respects custom retryAfter delay
  • error handling retry behavior maxRetries=0 disables retries
  • error handling catchability FatalError can be caught and detected with FatalError.is()
  • hookCleanupTestWorkflow - hook token reuse after workflow completion
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously
  • stepFunctionPassingWorkflow - step function references can be passed as arguments (without closure vars)
  • stepFunctionWithClosureWorkflow - step function with closure variables passed as argument
  • closureVariableWorkflow - nested step functions with closure variables
  • spawnWorkflowFromStepWorkflow - spawning a child workflow using start() inside a step
  • health check (queue-based) - workflow and step endpoints respond to health check messages
  • health check (CLI) - workflow health command reports healthy endpoints
  • pathsAliasWorkflow - TypeScript path aliases resolve correctly
  • Calculator.calculate - static workflow method using static step methods from another class
  • AllInOneService.processNumber - static workflow method using sibling static step methods
  • ChainableService.processWithThis - static step methods using this to reference the class
  • thisSerializationWorkflow - step function invoked with .call() and .apply()
  • customSerializationWorkflow - custom class serialization with WORKFLOW_SERIALIZE/WORKFLOW_DESERIALIZE
  • instanceMethodStepWorkflow - instance methods with "use step" directive
  • crossContextSerdeWorkflow - classes defined in step code are deserializable in workflow context
  • stepFunctionAsStartArgWorkflow - step function reference passed as start() argument
  • pages router addTenWorkflow via pages router
  • pages router promiseAllWorkflow via pages router
  • pages router sleepingWorkflow via pages router

turso (41 failed):

  • addTenWorkflow
  • addTenWorkflow
  • should work with react rendering in step
  • promiseAllWorkflow
  • promiseRaceWorkflow
  • promiseAnyWorkflow
  • hookWorkflow
  • webhookWorkflow
  • sleepingWorkflow
  • nullByteWorkflow
  • workflowAndStepMetadataWorkflow
  • fetchWorkflow
  • promiseRaceStressTestWorkflow
  • error handling error propagation workflow errors nested function calls preserve message and stack trace
  • error handling error propagation workflow errors cross-file imports preserve message and stack trace
  • error handling error propagation step errors basic step error preserves message and stack trace
  • error handling error propagation step errors cross-file step error preserves message and function names in stack
  • error handling retry behavior regular Error retries until success
  • error handling retry behavior FatalError fails immediately without retries
  • error handling retry behavior RetryableError respects custom retryAfter delay
  • error handling retry behavior maxRetries=0 disables retries
  • error handling catchability FatalError can be caught and detected with FatalError.is()
  • hookCleanupTestWorkflow - hook token reuse after workflow completion
  • concurrent hook token conflict - two workflows cannot use the same hook token simultaneously
  • stepFunctionPassingWorkflow - step function references can be passed as arguments (without closure vars)
  • stepFunctionWithClosureWorkflow - step function with closure variables passed as argument
  • closureVariableWorkflow - nested step functions with closure variables
  • spawnWorkflowFromStepWorkflow - spawning a child workflow using start() inside a step
  • health check (queue-based) - workflow and step endpoints respond to health check messages
  • pathsAliasWorkflow - TypeScript path aliases resolve correctly
  • Calculator.calculate - static workflow method using static step methods from another class
  • AllInOneService.processNumber - static workflow method using sibling static step methods
  • ChainableService.processWithThis - static step methods using this to reference the class
  • thisSerializationWorkflow - step function invoked with .call() and .apply()
  • customSerializationWorkflow - custom class serialization with WORKFLOW_SERIALIZE/WORKFLOW_DESERIALIZE
  • instanceMethodStepWorkflow - instance methods with "use step" directive
  • crossContextSerdeWorkflow - classes defined in step code are deserializable in workflow context
  • stepFunctionAsStartArgWorkflow - step function reference passed as start() argument
  • pages router addTenWorkflow via pages router
  • pages router promiseAllWorkflow via pages router
  • pages router sleepingWorkflow via pages router

Details by Category

✅ ▲ Vercel Production
App Passed Failed Skipped
✅ astro 44 0 4
✅ example 44 0 4
✅ express 44 0 4
✅ fastify 44 0 4
✅ hono 44 0 4
✅ nextjs-turbopack 47 0 1
✅ nextjs-webpack 47 0 1
✅ nitro 44 0 4
✅ nuxt 44 0 4
✅ sveltekit 44 0 4
✅ vite 44 0 4
✅ 💻 Local Development
App Passed Failed Skipped
✅ astro-stable 41 0 7
✅ express-stable 41 0 7
✅ fastify-stable 41 0 7
✅ hono-stable 41 0 7
✅ nextjs-turbopack-stable 45 0 3
✅ nextjs-webpack-stable 45 0 3
✅ nitro-stable 41 0 7
✅ nuxt-stable 41 0 7
✅ sveltekit-stable 41 0 7
✅ vite-stable 41 0 7
✅ 📦 Local Production
App Passed Failed Skipped
✅ astro-stable 41 0 7
✅ express-stable 41 0 7
✅ fastify-stable 41 0 7
✅ hono-stable 41 0 7
✅ nextjs-turbopack-stable 45 0 3
✅ nextjs-webpack-stable 45 0 3
✅ nitro-stable 41 0 7
✅ nuxt-stable 41 0 7
✅ sveltekit-stable 41 0 7
✅ vite-stable 41 0 7
✅ 🐘 Local Postgres
App Passed Failed Skipped
✅ astro-stable 41 0 7
✅ express-stable 41 0 7
✅ fastify-stable 41 0 7
✅ hono-stable 41 0 7
✅ nextjs-turbopack-stable 45 0 3
✅ nextjs-webpack-stable 45 0 3
✅ nitro-stable 41 0 7
✅ nuxt-stable 41 0 7
✅ sveltekit-stable 41 0 7
✅ vite-stable 41 0 7
✅ 🪟 Windows
App Passed Failed Skipped
✅ nextjs-turbopack 45 0 3
❌ 🌍 Community Worlds
App Passed Failed Skipped
✅ mongodb-dev 3 0 0
❌ mongodb 8 37 3
✅ redis-dev 3 0 0
❌ redis 5 40 3
✅ starter-dev 3 0 0
❌ starter 3 42 3
✅ turso-dev 3 0 0
❌ turso 4 41 3
✅ 📋 Other
App Passed Failed Skipped
✅ e2e-local-dev-nest-stable 41 0 7
✅ e2e-local-postgres-nest-stable 41 0 7
✅ e2e-local-prod-nest-stable 41 0 7

📋 View full workflow run

@vercel
Copy link
Contributor

vercel bot commented Feb 8, 2026

@changeset-bot
Copy link

changeset-bot bot commented Feb 8, 2026

🦋 Changeset detected

Latest commit: 377d3b7

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

This PR includes changesets to release 19 packages
Name Type
@workflow/core Patch
@workflow/world Patch
@workflow/cli Patch
@workflow/web Patch
@workflow/world-testing Patch
@workflow/builders Patch
@workflow/next Patch
@workflow/nitro Patch
@workflow/web-shared Patch
workflow 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

Copy link
Member Author

TooTallNate commented Feb 8, 2026

Warning

This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
Learn more

This stack of pull requests is managed by Graphite. Learn more about stacking.

Copy link
Collaborator

@pranaygp pranaygp left a comment

Choose a reason for hiding this comment

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

Review: PR #979 - Add Encryptor interface and thread through serialization layer

Summary: Adds the Encryptor, EncryptionContext, and KeyMaterial interfaces to @workflow/world, makes World extend Encryptor, and threads the encryptor parameter through all serialization functions. This is a no-op refactor -- the encryptor parameter is unused (_encryptor) throughout.

Strengths:

  • Clean interface design: Encryptor has all-optional methods, so existing World implementations don't break
  • EncryptionContext is minimal (just runId) -- good for forward compatibility
  • KeyMaterial interface for o11y tooling is a thoughtful addition
  • The getEncryptorForRun() method on World is a well-designed escape hatch for cross-deployment encryption (e.g., resumeHook() from newer deployment)
  • getHookByTokenWithEncryptor() resolves the encryptor once and reuses it -- avoids redundant key resolution

Concerns:

  1. resolveEncryptorForRun type safety: In resume-hook.ts line 29-31, getEncryptorForRun is accessed via (world as any).getEncryptorForRun. Since World already extends Encryptor and getEncryptorForRun is defined on World, you should be able to use optional chaining directly: world.getEncryptorForRun?.(runId). The 'getEncryptorForRun' in world + as any pattern bypasses type checking unnecessarily.

  2. Serialization parameter ordering: The PR reorders parameters in the dehydrate/hydrate functions. For example, dehydrateWorkflowArguments goes from (value, ops, runId, ...) to (value, runId, encryptor, ops, ...). This is a breaking change to the internal API. While these aren't public, any external code calling these directly would break. The reorder makes sense semantically (runId + encryptor are conceptually paired), but consider documenting this in the changeset.

  3. _encryptor unused parameter pattern: All 8 functions have _encryptor: Encryptor that is unused. This is expected since the actual wiring happens in #957. However, this means if #979 lands but #957 doesn't (or is delayed), there's dead parameter threading throughout the codebase. A minor code smell but acceptable for a PR stack.

  4. hydrateResourceIO now requires encryptor: In observability.ts, hydrateResourceIO now takes an Encryptor parameter, and all callers pass world. This means the observability layer now has a dependency on the World instance. Previously it was a pure data transformation. This is a reasonable tradeoff for encryption support, but worth noting the coupling increase.

Overall, well-structured interface design. The cross-deployment encryption support via getEncryptorForRun shows good foresight for production scenarios.

@TooTallNate TooTallNate marked this pull request as ready for review February 9, 2026 23:12
Copilot AI review requested due to automatic review settings February 9, 2026 23:12
Copy link
Member Author

@TooTallNate TooTallNate left a comment

Choose a reason for hiding this comment

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

Thanks for the thorough review @pranaygp! Addressing each concern:

  1. resolveEncryptorForRun type safety — Fixed. Now uses optional chaining: return (await world.getEncryptorForRun?.(runId)) ?? world;

  2. Serialization parameter ordering — Good call. Updated the changeset to document this as a breaking change to the internal API, noting the reorder and that these are not intended for external consumption.

  3. _encryptor unused parameter pattern — Agreed this is a minor smell. It's intentional for the PR stack — #957 (wire encryption) removes the underscores and actually uses the parameter. If that PR is delayed, the unused params are harmless and serve as documentation of the intended API surface.

  4. hydrateResourceIO now requires encryptor — Fair point about the coupling increase. Previously it was pure data transformation; now it depends on an Encryptor instance. In practice, the CLI and web callers already have world in scope (they need it for world.runs.get() etc.), so the additional parameter doesn't introduce a new dependency — it just makes an existing one explicit. For the common case where no encryption is configured, {} satisfies Encryptor since all methods are optional.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces a new Encryptor interface in @workflow/world and threads an encryptor + runId through the core serialization/hydration APIs and runtime plumbing, laying groundwork for future at-rest / E2E encryption (without enabling encryption yet).

Changes:

  • Add Encryptor, EncryptionContext, and KeyMaterial to @workflow/world, and extend World with optional getEncryptorForRun(runId).
  • Update core serialization/hydration function signatures (and call sites) to accept runId + encryptor.
  • Propagate the encryptor through runtime flows, including runWorkflow(), step/hook hydration, and resumeHook() (resolving per-run encryptors once).

Reviewed changes

Copilot reviewed 29 out of 29 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
workbench/nextjs-webpack/pages/api/trigger-pages.ts Update hydrateWorkflowArguments call to new (runId, encryptor, ...) signature.
workbench/nextjs-turbopack/pages/api/trigger-pages.ts Same signature update for turbopack workbench.
packages/world/src/interfaces.ts Add Encryptor/EncryptionContext/KeyMaterial; extend World and add getEncryptorForRun?.
packages/world-testing/src/null-byte.mts Update hydration calls to pass (runId, encryptor).
packages/world-testing/src/idempotency.mts Update hydration calls to pass (runId, encryptor).
packages/world-testing/src/hooks.mts Update hydration calls to pass (runId, encryptor).
packages/world-testing/src/errors.mts Update hydration calls to pass (runId, encryptor).
packages/world-testing/src/addition.mts Update hydration calls to pass (runId, encryptor).
packages/web/src/server/workflow-server-actions.ts Thread world into hydrateResourceIO for decrypt context.
packages/core/src/workflow/hook.ts Pass ctx.runId/ctx.encryptor into step return value hydration.
packages/core/src/workflow/hook.test.ts Add runId/encryptor to context + update serialization calls.
packages/core/src/workflow.ts Add encryptor param to runWorkflow and pass through to (de)hydration.
packages/core/src/workflow.test.ts Update tests for new serialization signatures (but one callsite is still incorrect).
packages/core/src/step.ts Pass ctx.runId/ctx.encryptor into step result hydration.
packages/core/src/step.test.ts Add runId/encryptor to context + update serialization calls.
packages/core/src/serialization.ts Add Encryptor parameter to all 8 dehydrate/hydrate functions and reorder parameters.
packages/core/src/serialization.test.ts Update test calls to new signatures across serialization suite.
packages/core/src/runtime/suspension-handler.ts Thread runId + world (as encryptor) into step argument dehydration.
packages/core/src/runtime/step-handler.ts Thread world (as encryptor) into step argument hydration + return dehydration.
packages/core/src/runtime/start.ts Pass (runId, world) into dehydrateWorkflowArguments.
packages/core/src/runtime/runs.ts Pass (runId, {}) into hydrateWorkflowArguments (placeholder encryptor).
packages/core/src/runtime/run.ts Pass (runId, world) into hydrateWorkflowReturnValue.
packages/core/src/runtime/resume-hook.ts Resolve per-run encryptor once and reuse for metadata hydration + payload dehydration.
packages/core/src/runtime.ts Pass world into runWorkflow as encryptor.
packages/core/src/private.ts Extend WorkflowOrchestratorContext with runId and encryptor.
packages/core/src/observability.ts Require encryptor for hydrateResourceIO and thread into hydration helpers.
packages/core/src/observability.test.ts Update hydrateResourceIO calls to provide encryptor.
packages/cli/src/lib/inspect/output.ts Pass world into hydrateResourceIO for decrypt context.
.changeset/encryptor-interface.md Changeset describing interface/signature threading for future encryption.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

workflowRun,
events,
mockEncryptor
)) as any,
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

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

hydrateWorkflowReturnValue signature now expects (value, runId, encryptor, ops?, ...), but this test still passes ops as the second argument. This will fail typechecking and call hydration with the wrong parameters; pass the workflow runId and encryptor before ops.

Suggested change
)) as any,
)) as any,
'wrun_test',
mockEncryptor,

Copilot uses AI. Check for mistakes.
Comment on lines +36 to +41
input: await dehydrateWorkflowArguments(
[],
'wrun_test',
mockEncryptor,
ops
),
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

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

These tests pass a hard-coded runId ('wrun_test') into dehydrateWorkflowArguments, even though workflowRun.runId is 'wrun_123'. Since runId is intended for per-run derivation (and is already used for stream serialization), the runId passed into (de)serialization should match the run being created to avoid future encryption/stream bugs.

Copilot uses AI. Check for mistakes.
Comment on lines +2 to +6
"@workflow/core": patch
"@workflow/world": patch
"@workflow/cli": patch
"@workflow/web": patch
"@workflow/world-testing": patch
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

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

This changeset marks @workflow/core/@workflow/cli/@workflow/web as patch, but this PR changes public exported API signatures (e.g. @workflow/core/serialization and @workflow/core/observability) by adding new required parameters. That is a breaking change for downstream consumers; either make the new parameters optional/backwards-compatible (overloads/defaults) or bump to a minor/major release accordingly.

Suggested change
"@workflow/core": patch
"@workflow/world": patch
"@workflow/cli": patch
"@workflow/web": patch
"@workflow/world-testing": patch
"@workflow/core": minor
"@workflow/world": minor
"@workflow/cli": minor
"@workflow/web": minor
"@workflow/world-testing": minor

Copilot uses AI. Check for mistakes.
Comment on lines 1297 to 1313
/**
* Called from the `start()` function to serialize the workflow arguments
* into a format that can be saved to the database and then hydrated from
* within the workflow execution environment.
*
* @param value
* @param global
* @param runId
* @returns The dehydrated value as binary data (Uint8Array) with format prefix
*/
export async function dehydrateWorkflowArguments(
value: unknown,
ops: Promise<void>[],
runId: string,
_encryptor: Encryptor,
ops: Promise<void>[] = [],
global: Record<string, any> = globalThis,
v1Compat = false
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

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

dehydrateWorkflowArguments now requires runId and Encryptor, but the JSDoc @param list above still describes the old parameter order (e.g. mentions global before runId) and does not mention the new encryptor argument. Please update the doc comment to match the new signature (or keep the old call shape via overloads/defaults).

Copilot uses AI. Check for mistakes.
Comment on lines 424 to 428
},
>(
resource: T
resource: T,
encryptor: Encryptor
): Promise<T> => {
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

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

hydrateResourceIO is exported from @workflow/core/observability, and changing it to require an encryptor argument is a breaking API change. Consider keeping backward compatibility by making encryptor optional with a safe default (e.g. {}) or by adding an overload that preserves the previous single-argument call signature.

Copilot uses AI. Check for mistakes.
Comment on lines 27 to 33
if (
'getEncryptorForRun' in world &&
typeof (world as any).getEncryptorForRun === 'function'
) {
return await (world as any).getEncryptorForRun(runId);
}
return world;
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

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

resolveEncryptorForRun is doing runtime 'getEncryptorForRun' in world checks and any casts even though World.getEncryptorForRun? is now part of the type. Prefer const encryptor = await world.getEncryptorForRun?.(runId) ?? world; to avoid any and keep the implementation type-safe.

Suggested change
if (
'getEncryptorForRun' in world &&
typeof (world as any).getEncryptorForRun === 'function'
) {
return await (world as any).getEncryptorForRun(runId);
}
return world;
const encryptor = (await world.getEncryptorForRun?.(runId)) ?? world;
return encryptor;

Copilot uses AI. Check for mistakes.
Comment on lines 96 to 94
export async function resumeHook<T = any>(
tokenOrHook: string | Hook,
payload: T
payload: T,
_encryptor?: Encryptor
): Promise<Hook> {
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

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

The parameter is named _encryptor, but it is actually used to override the resolved encryptor. The underscore convention typically indicates an intentionally-unused parameter; rename this to something like encryptor/encryptorOverride to avoid confusion.

Copilot uses AI. Check for mistakes.
@TooTallNate TooTallNate force-pushed the nate/encryptor-interface branch from 4cc267f to 64be97d Compare February 9, 2026 23:19
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.

2 participants