feat!: v8 review remediation — client split, parse-once wire format, and full-surface hardening - #354
Merged
Merged
Conversation
Records the investigation and decision from millenium!56319 note 2210871: add a synchronous, memoized TypedClient#for(contract) rather than moving the contract to the call site or re-introducing a NestJS integration package. Spec lives in .agents/specs/ rather than docs/ because the VitePress config sets no srcExclude, so any .md under docs/ becomes a published page. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Review feedback: the client should not depend on a contract at all, so the
privileged bootstrap contract in the previous draft is gone.
TypedClient becomes connection-scoped with no type parameter; the contract-bound
surface moves to ContractClient<TContract>, reached via TypedClient#for(contract).
The >= 1.16 schedule check moves to create, where it is a property of the
connection rather than of any contract, which keeps for() infallible.
create({ contract, client }) is dropped rather than deprecated — retaining it
would preserve the coupling being removed — and createOrThrow goes with it.
Records the resulting breaking changes, the ~6 type annotations to retype, and
the migration section owed to upgrade-to-v8.md.
Also adopts the repo's fluent `await create({...}).get()` idiom and fixes an
ungrammatical sentence flagged in review.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…nt spec Adds a Non-goals entry explaining the client/worker asymmetry: the client's contract coupling was accidental (connection vs schema) while the worker's is essential (a Worker instance polls exactly one task queue and the contract is its job description), with the NativeConnection-sharing story already covered by createWorker's option spread. Also records the deliberate choice to keep the TypedClient name, the memoization trade-off and its constraint on a future for(contract, options) overload, adds a type-level migration assertion (TypedClient takes no type argument), and reflows one inline code span that was broken across lines. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Wave 1 meta/docs items from the v8 review remediation spec: - Item 7: add a beta-install warning and @beta-tagged install commands to the root README, docs/how-to/install.md, and tutorial step 1 — npm's latest dist-tag is 7.0.0 while the docs teach the v8 API. - Item 8: correct AGENTS.md rule 2 and handlers.md — unthrown 5 does export OkAsync/ErrAsync (only lowercase okAsync/errAsync are absent); switch handlers.md's cancellation example from free-function isErr(result) to the method style the codebase uses. - Item 9: add the missing @temporalio/testing ^1 peer to dependencies.md's testing row and key-dependencies table. - Item 10: examples/README.md — drop stale "Promise-based worker" and "Result/Future" wording, list all three example packages; fix the matching one-line comment in order-processing-contract's contract.ts. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… signals/queries/updates Wave 1 of the v8 review remediation (spec items 1-6): - Activity-collision check now allows the same activity definition object to be referenced from several scopes (reference equality — the flat namespace stays unambiguous); real collisions (different objects, same name) recommend hoisting the shared activity to the contract's global "activities" block. - defineContract rejects a global activity whose name equals a workflow name (they share the root of the worker implementations map). - Replaced the zod-based contract meta-validation with a hand-rolled structural validator over unknown; zod moved from dependencies to devDependencies (tests still use it as a Standard Schema). The contract root is now strict: unknown top-level keys are rejected, matching the strict defaultOptions behavior. - defineSignal/defineQuery/defineUpdate accept an omitted input: they materialize an UndefinedInputSchema (Standard Schema whose validated value is always undefined), so handler inputs infer as undefined without z.void() ceremony. Definition types keep a required input slot so the worker and client compile unchanged (their optional-payload surfaces land in Wave 3). - Deleted the trivial InferContractWorkflows alias; fixed the stale "unthrown 4" comment in errors.ts to describe unthrown 5 semantics. - Dropped the CJS build: ESM-only exports with types conditions (aligned with packages/testing), removed main/module/types top-level fields. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…iginal) Implements D1 from the v8 review remediation spec. Previously both sides of every payload boundary ran the same Standard Schema and the sender transmitted the PARSED value; the receiver parsed again, so a transforming schema (z.coerce.*, .transform(...)) was applied twice — silent data corruption. Now each boundary parses exactly once, on the receiving side: the sender still validates (failing early with the existing typed error) but transmits the caller's ORIGINAL value, discarding the parsed result. Send-side sites reclassified (validate, transmit original): - client startWorkflow / executeWorkflow / signalWithStart workflow args (resolveDefinitionAndValidateInput no longer returns a parsed value) - client signalWithStart signal args - client handle signal/query/update proxy inputs (buildValidatedProxy) - client schedule.create args - worker workflow-side activity proxy inputs (both throwing and Result-shaped wrappers in activities-proxy.ts) - worker child-workflow args (startChildWorkflow / executeChildWorkflow) - worker continueAsNew args - worker workflow output (declareWorkflow returns the implementation's original value after validating it) - worker activity handler output (declareActivitiesHandler) - worker query/update handler outputs (bindQueryHandler/bindUpdateHandler) - worker contract-error data (contractErrorToApplicationFailure details[0]) Receive-side sites confirmed as the single boundary parse (unchanged): - worker workflow/signal/query/update input handlers, activity handler input, middleware-substituted inputs (a patched input is raw from the pipeline's perspective and parsed once) - client executeWorkflow / handle.result() / query / update result parsing - worker parent-side child-workflow result parsing, activity-result parsing in the workflow proxy, contract-error rehydration Adds transform-schema tests pinning the new wire format at unit level in both packages plus an end-to-end integration case in the client suite, and rewrites the old "intentional double-validation" rationale comments. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…er surface fixes
- D2: invalid signal payloads are dropped and logged via @temporalio/workflow's
log.warn instead of throwing; SignalInputValidationError is deleted
- D3: new ContractMisuseError (non-retryable ApplicationFailure) replaces every
plain Error thrown from workflow-sandbox code (handler binding guards,
sync-schema guards, buildRawActivitiesProxy options-coverage errors)
- item 20: declareActivitiesHandler iterates contract definitions (fail fast on
declared-but-missing implementations), rejects workflow-name/global-activity
collisions (defense-in-depth, message aligned with defineContract), and
errors on stray root-level keys whether or not contract.activities exists
- item 21: TypedChildWorkflowHandle gains a typed signals map (validate on
send, transmit original per D1) and firstExecutionRunId
- item 22: declareWorkflow throws ContractMisuseError for unknown workflow
names, listing the available ones
- item 23: activities is optional on createWorker (workflow-only workers, key
omitted from Worker.create when absent); key remapping drops empty
"workflowName: {}" placeholder entries from the implementations map (NoInfer
keeps lambda contextual typing intact); extractHandlerInput maps zero args
to undefined, pairing with input-less signal/query/update definitions
- item 24: rename exported qualify -> qualifyFailure (no alias; unshipped beta)
- item 25: ValidationError name property non-enumerable; new SignalDefOf /
QueryDefOf / UpdateDefOf type helpers replace the triple-repeated
conditionals; deduped the update sync-validation message
- item 26: README quick start rewritten around createWorker +
workflowsPathFromURL (ESM, .js imports, named contract export, conditional
cause spread); TSDoc fixes (child-workflow contract-required bullets,
.getOrThrow -> .get, declareActivitiesHandler example uses createWorker,
cause idiom); worker integration tests migrated to the new
TypedClient.create({ client }).for(contract) client surface
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…nt surface
Wave 3 of the v8 review remediation (items 11-18):
- 11: TypedClient is now connection-scoped (no type parameter):
static create({ client, interceptors }) holds the schedule-presence
check + eager ensureConnected; for(contract) hands out memoized,
identity-stable ContractClient<TContract> bindings (the renamed old
class, constructor @internal). createOrThrow and the create options'
contract field are removed; ContractClient is exported.
- 12: handle.result() output-validation errors now carry the real
workflow NAME (the workflowId was passed as workflowName);
WorkflowValidationError gains a workflowId field, populated on
start/execute/signalWithStart/result paths.
- 13: schedule parity — tagged ScheduleAlreadyExistsError /
ScheduleNotFoundError classified from Temporal's ScheduleAlreadyRunning /
ScheduleNotFoundError; create returns Err(ScheduleAlreadyExistsError);
handle methods return AsyncResult<void, ScheduleNotFoundError>;
new update + backfill on the typed handle and list on the typed
schedule client; TypedScheduleClient constructor is @internal.
- 14: readonly raw escape hatch on the TypedClient root; typed workflow
handles carry runId + firstExecutionRunId (signaledRunId stays on
signalWithStart's); getHandle is now SYNCHRONOUS returning
Result<handle, WorkflowNotInContractError> and accepts runId +
GetWorkflowHandleOptions (firstExecutionRunId interlock); typed
startUpdate beside executeUpdate with a parsed-on-receive result().
- 15: WorkflowNotFoundError renamed WorkflowNotInContractError (it
squatted on the SDK's execution-not-found name);
WorkflowExecutionNotFoundError unchanged.
- 16: deleted the six unused ClientInfer* type exports; fixed the
inverted direction comment in types.ts; {} fallbacks are now
Record<never, never>.
- 17: executeWorkflow composes classifyStartError + the new shared
classifyExecutionResultError (rehydrate-then-classify) helper, also
used by handle.result().
- 18: TSDoc/doc polish (orphaned TypedSearchAttributeMap doc, "Thrown
when" -> "Surfaced on the Err channel when", module docs above
imports, readonly handle/error fields, typeof-per-kind runtime checks
for search-attribute VALUES, fixed interceptors.ts combinator names,
README rewritten to the TypedClient.create({ client }).for(contract)
two-step with .get()); payload arguments are omittable when the
schema accepts undefined (input-less signals/queries/updates send
empty args); expanded type-level and unit/integration suites incl.
second-contract fixtures proving one root drives two task queues.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…eries, errors, and schedules
Port the order-processing example to the TypedClient/ContractClient split
(TypedClient.create({ client }).get() + .for(contract), synchronous
getHandle, qualifyFailure) and extend it across the advertised surface:
an approval signal + payload-less defineSignal() cancellation, an
argument-less defineQuery({ output }) status query, a PaymentDeclined
typed contract error travelling activity -> workflow -> client (matched
with P.tag), and a schedule-driven activity-less cleanupExpiredOrders
workflow with the ScheduleAlreadyExistsError create-if-absent idiom.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Documents the v8 review-remediation changes (D1-D3 plus the client split)
across the hand-written docs, root README, and agent rules:
- upgrade-to-v8: new migration sections for the TypedClient/ContractClient
split (create({client}).for(contract), ContractClient annotations, no
createOrThrow), the WorkflowNotInContractError rename, sync getHandle,
deleted ClientInfer* aliases, the validate-on-send/parse-on-receive wire
format (D1) and its behavioral notes, signal drop-and-log semantics (D2),
qualify -> qualifyFailure, ContractMisuseError (D3), workflow-only
workers, fail-fast declareActivitiesHandler, contract-package changes
(strict root validation without zod, collision recalibration, input-less
builders, InferContractWorkflows removal, ESM-only), and the typed
schedule surface (ScheduleAlreadyExistsError/ScheduleNotFoundError,
update/backfill/list) with an expanded checklist
- validation-boundaries: rewritten around validate-on-send/parse-on-receive
with the exactly-once transform rationale, signal-drop row, and the
hand-rolled strict contract validation
- reference: client-surface rewritten for the two-class surface (for(),
raw, startUpdate, runId fields, sync getHandle, schedule additions);
contract-surface (UndefinedInputSchema, input-less builders, strict root
keys); worker-surface (ContractMisuseError, qualifyFailure, optional
activities, child-handle signals, signal-drop policy); errors (renames,
schedule errors, workflowId, channel tables)
- how-to/tutorials: construction sweep to the two-step client form,
input-less signal/query/update forms and omittable payloads, child
signals map, workflow-only workers, schedule typed errors and
create-if-absent idiom, sync getHandle call sites
- agent rules: qualifyFailure rename, client-split guidance, hand-rolled
contract validation wording
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- item 27: createContractTest(contract, { workflowsPath, activities?,
workerOptions? }) — new ./contract entry; vitest fixtures exposing
{ client, typedClient, worker } wired against the testcontainers server,
reusing the ./extension connection fixtures
- item 27: runActivity(definition, implementation, input, { env? }) — new
vitest-free ./activity entry executing a single AsyncResult activity
implementation inside MockActivityEnvironment, with heartbeat and
cancellation support via a caller-provided environment
- item 28: createTimeSkippingEnvironment forwards
TimeSkippingTestWorkflowEnvironmentOptions; new createTimeSkippingTest
fixture factory so suites can pin the test-server version
- item 28: extension throws a descriptive error naming
@temporal-contract/testing/global-setup when inject values are missing;
workerConnection is now closed in teardown inside try/catch (the known
NativeConnection shutdown race is swallowed)
- item 28: createGlobalSetup({ postgresImage, temporalImage, temporalEnv,
quiet }) factory; the default export becomes createGlobalSetup() with the
previous defaults; add the ./package.json export
- item 29: time-skipping TSDoc examples use .get() and the new
TypedClient.create({ client }) + for(contract) construction; README covers
./contract, ./activity, ./time-skipping and fixes the Client import
- deps: @temporal-contract/client|contract|worker and unthrown become peer
dependencies (they appear in the new public types); the workspace siblings
are resolved via tsconfig paths / vitest aliases locally because declaring
them as dev deps would create a cycle in the package graph (client and
worker already devDepend on this package)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… for the v8 review remediation - Adopt publint --strict + attw --pack as a per-package check:package turbo task (contract/testing: esm-only profile; worker: node16 — subpath-only exports can't resolve under node10; client: full). - Fix a real release blocker check:package caught: the testing package's workspace:^ sibling peers broke pnpm pack/publish (ERR_PNPM_CANNOT_RESOLVE_WORKSPACE_PROTOCOL, the peers are deliberately not installed to avoid a turbo package-graph cycle) — they now use concrete ^8.0.0-beta.3 ranges that changesets keeps bumped. - One major changeset for all four packages summarizing the v8 review remediation breaks. - Docs reconciliation: testing API guide sections (createContractTest, runActivity, createTimeSkippingTest, createGlobalSetup), example package descriptions, testing peer requirements in install docs and README, stale zod-internal claims, dependencies.md testing peers + no-devDep cycle exception, getHandle TSDoc example narrows with isOk() (unthrown 5). - Register second.workflows.ts as a knip entry (loaded by path string). - Mark both v8 specs implemented; D4 scope cuts recorded as still deferred. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Completes the no-deprecated-aliases policy applied to the client's createOrThrow: createWorker returns AsyncResult<Worker, never>, so .get() provides the same throw-on-defect behavior with the original cause. Migration guide, checklist, changeset, and handlers.md updated. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- rename CreateTypedClientOptions -> CreateClientOptions (the family-shared name for the Typed*.create() options shape, matching amqp-contract; its own JSDoc already claimed the shared role) - add a package-check CI job running publint + are-the-types-wrong on every publishable package (mirrors amqp-contract's job) - root package.json gains the engines field the packages already declare - changeset $schema points at the versioned unpkg URL instead of a local node_modules path - changeset entries for the declare* middleware rename, the client options rename, and the time-skipping testEnv fixture typing fix
Contributor
There was a problem hiding this comment.
Pull request overview
This PR is a broad v8 (8.0 beta) remediation sweep across the contract/client/worker/testing packages and documentation, centered on hardening runtime behavior and fixing validation/wire-format semantics so schema transforms apply exactly once (validate on send, parse on receive). It also introduces a connection-scoped TypedClient with synchronous contract binding (for(contract)), strengthens worker failure semantics in the workflow sandbox, and expands testing helpers and packaging checks.
Changes:
- Enforces the “parse-once wire format” across boundaries (senders validate but transmit originals; receivers parse) and updates docs/tests accordingly.
- Splits the client surface into
TypedClient(connection-scoped) andContractClient(contract-scoped), with expanded typed schedule and handle/update APIs. - Hardens worker/runtime behavior (notably
ContractMisuseError, dropping invalid signals) and adds/updates testing utilities and package verification (publint/attwviacheck:packages).
Reviewed changes
Copilot reviewed 128 out of 129 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| turbo.json | Adds a check:package Turbo pipeline task. |
| README.md | Updates v8 API docs and adds @beta install guidance. |
| pnpm-workspace.yaml | Adds catalog entries for publint and @arethetypeswrong/cli. |
| packages/worker/src/workflow.spec.ts | Adds unit coverage for declaration-time misuse errors. |
| packages/worker/src/workflow-proxy.spec.ts | Tightens expectations around misuse errors and uncovered options. |
| packages/worker/src/worker.ts | Makes activities optional and conditionally spreads it. |
| packages/worker/src/worker.spec.ts | Replaces createWorkerOrThrow tests with workflow-only worker coverage. |
| packages/worker/src/types.ts | Adds helper types to resolve signal/query/update definitions. |
| packages/worker/src/internal.ts | Adjusts wire-boundary behavior and adds signal to child error classification. |
| packages/worker/src/errors.ts | Removes signal validation error type; adds ContractMisuseError; tweaks name enumerability. |
| packages/worker/src/errors.spec.ts | Updates error suite for new semantics and ContractMisuseError. |
| packages/worker/src/contract-errors.ts | Sends original error payload over the wire (parse on receive). |
| packages/worker/src/continue-as-new.spec.ts | Adds D1 coverage ensuring original args are transmitted. |
| packages/worker/src/child-workflow.spec.ts | Adds test coverage for signal-specific phrasing. |
| packages/worker/src/activity-contract-errors.spec.ts | Adds D1 coverage for original error payload; renames middleware helper. |
| packages/worker/src/activities-proxy.ts | Implements validate-on-send/parse-on-receive semantics for activities. |
| packages/worker/src/activities-proxy.spec.ts | Adds tests covering wire-format behavior in throwing and Result-shaped paths. |
| packages/worker/src/tests/worker.spec.ts | Updates integration tests to new client split and worker behavior. |
| packages/worker/src/tests/time-skipping.inprocess.spec.ts | Updates in-process integration commentary and client binding usage. |
| packages/worker/README.md | Updates worker usage examples (ESM, createWorker, workflow-only workers). |
| packages/worker/package.json | Adds check:package script and related dev deps. |
| packages/testing/vitest.config.ts | Splits unit/integration projects and adds workspace source aliases. |
| packages/testing/typedoc.json | Expands typedoc entry points for new testing utilities. |
| packages/testing/tsconfig.json | Broadens rootDir and adds paths for peer sibling source resolution. |
| packages/testing/src/time-skipping.ts | Adds configurable environment options and fixture factory. |
| packages/testing/src/time-skipping.spec.ts | Adds unit coverage for time-skipping helper forwarding/teardown. |
| packages/testing/src/global-setup.spec.ts | Expands coverage for createGlobalSetup options and behavior. |
| packages/testing/src/extension.ts | Closes worker connection with race-safe swallow; adds address resolution helper. |
| packages/testing/src/extension.spec.ts | Updates unit tests to cover new close behavior and address resolution errors. |
| packages/testing/src/contract.ts | Adds createContractTest contract-aware integration fixture builder. |
| packages/testing/src/activity.ts | Adds runActivity for Docker-free unit testing in MockActivityEnvironment. |
| packages/testing/src/activity.spec.ts | Adds unit coverage for runActivity Ok/Err/defect/cancel/heartbeat behavior. |
| packages/testing/src/tests/test.workflows.ts | Adds minimal workflow module for fixture integration coverage. |
| packages/testing/src/tests/test.contract.ts | Adds minimal contract definition for fixture integration coverage. |
| packages/testing/src/tests/contract-test.spec.ts | Adds end-to-end integration coverage for createContractTest. |
| packages/testing/README.md | Documents new fixtures and clarifies Docker/time-skipping usage. |
| packages/testing/package.json | Exposes new entrypoints, adds check:package, and adjusts deps/peers. |
| packages/contract/src/types.ts | Adds UndefinedInputSchema and removes a trivial alias export. |
| packages/contract/src/types.spec.ts | Updates tests to reflect removed alias type. |
| packages/contract/src/types-inference.spec.ts | Adds inference tests for input-less signal/query/update helpers. |
| packages/contract/src/index.ts | Exposes UndefinedInputSchema and removes deleted export. |
| packages/contract/src/helpers.spec.ts | Adds tests asserting undefined-input schema materialization. |
| packages/contract/src/errors.ts | Updates comments for unthrown v5 reserved payload fields. |
| packages/contract/src/builder.spec.ts | Expands collision/root strictness tests and improves collision messages. |
| packages/contract/package.json | Switches to ESM-only exports/build and adds package checks tooling. |
| packages/client/src/types.ts | Updates client-side inference helpers for parse-once and payload-less calls. |
| packages/client/src/internal.ts | Adds runtime validation for typed search attribute values; adds schedule error classification helpers. |
| packages/client/src/interceptors.ts | Updates docs/types to reflect renamed errors and defect-based retry guidance. |
| packages/client/src/index.ts | Re-exports new types/surfaces and updates error exports for renamed/schedule errors. |
| packages/client/src/errors.ts | Renames contract lookup error; adds schedule errors; threads optional workflowId into validation error. |
| packages/client/src/tests/test.workflows.ts | Adds D1-oriented workflow implementation helper for integration testing. |
| packages/client/src/tests/test.contract.ts | Adds a transforming workflow definition for D1 testing. |
| packages/client/src/tests/second.workflows.ts | Adds workflows for multi-contract integration coverage. |
| packages/client/src/tests/second.contract.ts | Adds second contract definition for multi-contract integration coverage. |
| packages/client/README.md | Updates usage to the root+binding client split. |
| packages/client/package.json | Adds check:package script and related dev deps. |
| package.json | Adds root check:packages script. |
| knip.json | Updates entry list to include additional test workflow module. |
| examples/README.md | Updates example descriptions to match v8 capabilities and new APIs. |
| examples/order-processing-worker/src/infrastructure/adapters/payment.adapter.ts | Adjusts domain naming and models declines as outcomes. |
| examples/order-processing-worker/src/infrastructure/adapters/order-repository.adapter.ts | Adds a mock order repository adapter. |
| examples/order-processing-worker/src/domain/usecases/purge-expired-orders.usecase.ts | Adds cleanup use-case logic for scheduled workflow. |
| examples/order-processing-worker/src/domain/usecases/process-payment.usecase.ts | Updates naming to PaymentOutcome. |
| examples/order-processing-worker/src/domain/ports/payment.port.ts | Updates port docs and return type to reflect modeled declines. |
| examples/order-processing-worker/src/domain/ports/order-repository.port.ts | Adds repository port for cleanup use-case. |
| examples/order-processing-worker/src/domain/entities/order.schema.ts | Adds PaymentOutcome domain type. |
| examples/order-processing-worker/src/dependencies.ts | Wires new cleanup dependencies/use case. |
| examples/order-processing-worker/src/application/activities.ts | Updates activity handler to v8 semantics and typed contract errors. |
| examples/order-processing-worker/README.md | Updates narrative for unthrown AsyncResult, signals/queries, and schedules. |
| examples/order-processing-contract/src/schemas.ts | Refactors schemas and adds signal/query/status/schedule workflow schemas. |
| examples/order-processing-contract/README.md | Updates overview and client usage to new binding model. |
| examples/order-processing-client/README.md | Updates client example narrative to new split, signals/queries, schedule errors. |
| docs/tutorial/your-first-workflow.md | Updates tutorial install/API usage for v8 beta and qualifyFailure. |
| docs/tutorial/adding-signals-and-queries.md | Updates tutorial for input-less query and parse-once semantics. |
| docs/reference/worker-surface.md | Updates worker reference for D1 semantics, signal dropping, workflow-only workers, and new handles. |
| docs/reference/glossary.md | Updates terminology to qualifyFailure. |
| docs/reference/errors.md | Updates error docs for renamed workflow error and typed schedule errors; adds ContractMisuseError. |
| docs/reference/contract-surface.md | Updates contract reference for strict validation and input-less signal/query/update helpers. |
| docs/index.md | Updates homepage messaging and examples for v8 API changes. |
| docs/how-to/use-signals-queries-and-updates.md | Updates guidance for contract binding, payload-less ops, startUpdate, and sync getHandle. |
| docs/how-to/tune-activity-options.md | Renames qualify references to qualifyFailure. |
| docs/how-to/troubleshoot.md | Renames qualify references to qualifyFailure. |
| docs/how-to/test-workflows.md | Documents runActivity, time-skipping options, and createContractTest. |
| docs/how-to/schedule-workflows.md | Updates schedule API guidance and adds typed create-if-absent flow. |
| docs/how-to/run-child-workflows.md | Documents child handle signals and firstExecutionRunId. |
| docs/how-to/model-domain-errors.md | Updates examples for qualifyFailure and renamed workflow error tag. |
| docs/how-to/migrate-from-neverthrow.md | Updates migration guide for renamed workflow error and qualifyFailure. |
| docs/how-to/intercept-client-calls.md | Updates interceptor usage for root client + .for(contract). |
| docs/how-to/install.md | Adds prerelease guidance and clarifies schema-library-agnostic design. |
| docs/how-to/index-workflows-with-search-attributes.md | Updates getHandle usage to sync Result. |
| docs/how-to/implement-activities.md | Updates examples and warnings for qualifyFailure. |
| docs/how-to/handle-cancellation.md | Updates getHandle usage to sync Result. |
| docs/how-to/define-a-contract.md | Updates guidance for input-less signal/query/update and boundary semantics. |
| docs/how-to/configure-a-worker.md | Adds workflow-only worker guidance; removes deprecated helper mention. |
| docs/how-to/add-activity-middleware.md | Renames defineActivityMiddleware to declareActivityMiddleware and updates examples. |
| docs/explanation/validation-boundaries.md | Rewrites explanation around validate-on-send/parse-on-receive and signal dropping behavior. |
| docs/explanation/the-result-model.md | Updates examples for new client creation/binding surface. |
| docs/explanation/nexus.md | Renames qualify references to qualifyFailure. |
| docs/examples/index.md | Updates examples page to reflect v8 features and naming. |
| AGENTS.md | Updates repo guidance to match unthrown v5 and current APIs. |
| .changeset/v8-review-remediation.md | Adds a major changeset summarizing the breaking v8 remediation. |
| .agents/rules/project-overview.md | Updates client overview to reflect root/binding split. |
| .agents/rules/handlers.md | Updates handler guidance for qualifyFailure and current worker/client shapes. |
| .agents/rules/dependencies.md | Updates dependency guidance for ESM-only and testing peer dependency strategy. |
| .agents/rules/contract-patterns.md | Updates contract guidance for strict validation and input-less handler helpers. |
Files not reviewed (1)
- pnpm-lock.yaml: Generated file
Copilot review on #354: typeof reports "object" for arrays, Dates, and null; a describeRuntimeType helper now spells those out. Also stops labeling zod a peer dependency in the README and tutorial — the packages require any Standard Schema validator. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This was referenced Jul 30, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements every finding from the six-track review of 2026-07-29/30 (client, worker, contract+testing, unthrown audit, amqp-contract consistency, DX/docs). Decisions and work breakdown are recorded in .agents/specs/2026-07-30-v8-review-remediation.md; the
TypedClient/ContractClientsplit follows the companion spec from #353 (whose commits this branch contains — #353 can be closed or merged first, either works).All breaking changes land inside the unshipped 8.0 beta. One changeset marks all four packages
major(folds into the next8.0.0-beta.N).Headline changes
Criticals fixed
z.coerce.*,.transform(...)) apply exactly once instead of twice — previously silent data corruption. Proven end-to-end against a live server.log.warn'd;SignalInputValidationErroris deleted.@betainstall commands + warnings on README/install/tutorial (npmlatestis still v7).Client —
TypedClient(connection-scoped root) +for(contract)→ContractClient; syncgetHandlereturningResultwithrunId/firstExecutionRunIdoptions;rawescape hatch;startUpdate; schedule parity (typedScheduleAlreadyExistsError/ScheduleNotFoundError,update/backfill/list);WorkflowNotFoundError→WorkflowNotInContractError; deadClientInfer*exports deleted.Worker —
ContractMisuseError(non-retryable) replaces plainErrors that hung executions in task retries; workflow-name/global-activity collisions rejected (contract + handler); fail-fast on missing implementations; child handles gain typedsignals+firstExecutionRunId; workflow-only workers (activitiesoptional, no{}ceremony);qualify→qualifyFailure;createWorkerOrThrowremoved.Contract — zod removed from runtime deps (hand-rolled strict validation, unknown root keys rejected); same-object activity reuse allowed across workflows; input-less
defineSignal()/defineQuery({output})/defineUpdate({output}); ESM-only build.Testing —
createContractTest(ready{ client, typedClient, worker }per test), vitest-freerunActivityoverMockActivityEnvironment, configurable time-skipping env +createGlobalSetup(options), inject/connection-lifecycle fixes.Examples & docs — examples ported and extended (signals, query, typed contract error via
P.tag, create-if-absent schedule; smoke-run live); migration guide covers every break; validation-boundaries explanation rewritten for D1; full construction sweep;publint --strict+attw --pack(check:packages) adopted from amqp-contract.Verification
pnpm install/build(incl. docs) /turbo typecheck/lint/turbo test/test:integration(Docker: client 19, worker 16+1 skip, testing 3, examples 8) /check:packages/knip/changeset status— all green. Examples additionally smoke-run against a live Temporal dev server (worker + client processes, all demo flows incl. schedule trigger).Deferred (recorded in the spec, D4)
Typed local activities; client
list/count(covered byraw); amqp-contract/async-contract convergence (separate repos); configurable invalid-signal policy.🤖 Generated with Claude Code