chore: adopt @unthrown/oxlint recommended rules - #356
Merged
Conversation
Register the @unthrown/oxlint plugin (catalog 5.0.0, root devDep,
minimumReleaseAgeExclude entry) with the 4 recommended rules and fix
the 29 violations it surfaced:
- no-ambiguous-error-type (client/src/types.ts): genuine findings — the
ClientInferSignal/Query/Update aliases claimed AsyncResult<..., Error>
while the handle proxies actually produce the precise
{Signal,Query,Update}ValidationError | WorkflowExecutionNotFoundError
unions; the aliases now carry those unions, and TypedWorkflowHandle's
queries/signals/updates use them directly instead of pattern-matching
the bare Error away (which also removes the three
`AsyncResult<infer R, Error>` conditionals in client.ts).
- no-ambiguous-error-type (worker/src/activities-proxy.spec.ts): the
test fixtures now use the concrete
AnyContractError | ActivityError | ActivityCancelledError union the
Result-shaped proxy really returns.
- prefer-async-result (work thunks feeding makeAsyncResult in client.ts,
schedule.ts, cancellation.ts, child-workflow.ts, testing/activity.ts):
dropped the Promise<Result<...>> return annotations; where TS cannot
collapse the thunk's per-return Result union on its own, the T/E pair
is pinned as explicit type arguments on the makeAsyncResult call.
- prefer-async-result (async validation helpers
resolveDefinitionAndValidateInput / getAndValidateChildWorkflow /
validateChildWorkflowOutput): converted to non-async functions
returning AsyncResult via makeAsyncResult — behavior is unchanged
because callers already assertNoDefect (re-throwing a captured defect
into the enclosing throw→defect net).
- prefer-async-result (contract/src/result-async.ts and its
client-internal re-export wrapper): kept with targeted
oxlint-disable-next-line — these ARE the Promise→AsyncResult
conversion seam whose thunk rejection becomes the defect, and an async
implementer cannot be annotated AsyncResult.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Adopts the @unthrown/oxlint plugin and enables its recommended rules to enforce more precise AsyncResult/Result usage and error unions across the Temporal contract client/worker/testing packages.
Changes:
- Register
@unthrown/oxlintin.oxlintrc.jsonand add the dependency via the workspace catalog (including supply-chain gate exclusion). - Tighten the client public type surface by replacing
AsyncResult<..., Error>with concrete validation/not-found error unions, and simplifyTypedWorkflowHandlemapped types accordingly. - Refactor several internal helpers from
Promise<Result<...>>toAsyncResult<...>(and remove now-redundantPromise<Result>annotations), plus align test fixtures with the real proxy error union.
Reviewed changes
Copilot reviewed 12 out of 13 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| pnpm-workspace.yaml | Adds @unthrown/oxlint to the catalog and supply-chain exclusion list. |
| pnpm-lock.yaml | Locks @unthrown/oxlint (and its transitive deps) into the workspace. |
| package.json | Adds @unthrown/oxlint as a root devDependency via the catalog. |
| .oxlintrc.json | Registers the unthrown plugin and enables the recommended rules. |
| packages/contract/src/result-async.ts | Documents and disables prefer-async-result at the intentional Promise→AsyncResult seam. |
| packages/client/src/internal.ts | Documents and disables prefer-async-result at the client’s Promise→AsyncResult seam wrapper. |
| packages/client/src/types.ts | Replaces ambiguous Error error types with concrete validation/not-found unions for signals/queries/updates. |
| packages/client/src/client.ts | Simplifies TypedWorkflowHandle query/signal/update types now that aliases carry correct unions; converts resolver helper to AsyncResult. |
| packages/client/src/schedule.ts | Removes explicit Promise<Result<...>> annotations and pins makeAsyncResult generics at call sites. |
| packages/worker/src/child-workflow.ts | Converts validation helpers to AsyncResult and pins makeAsyncResult generics where inference can’t collapse unions. |
| packages/worker/src/cancellation.ts | Removes explicit Promise<Result<...>> annotations and pins makeAsyncResult generics. |
| packages/worker/src/activities-proxy.spec.ts | Replaces AsyncResult<unknown, unknown> with a concrete proxy error union in fixtures. |
| packages/testing/src/activity.ts | Removes explicit Promise<Result<...>> annotation in the internal run wrapper while preserving behavior. |
Files not reviewed (1)
- pnpm-lock.yaml: Generated file
Docs build (root cause of the Package / ci Build / Bundle Size failures):
the TSDoc on TypedWorkflowHandle's queries/signals/updates properties held
inline code spans containing a raw `|` (e.g.
AsyncResult<T, QueryValidationError | WorkflowExecutionNotFoundError>).
typedoc renders member docs into markdown table cells without escaping
pipes inside code spans, so markdown-it split the row at the pipe, the
broken span left `Promise<T>` as a raw HTML-looking `<T>` element, and
VitePress's Vue compiler failed with "Element is missing end tag" at
api/client/index.md. Fixed at the source by rewording the three doc
comments so no code span carries a pipe; generated files untouched.
Lint: turn on unthrown/no-throw and unthrown/prefer-ensure, so all six
rules are now at "error". prefer-ensure surfaced 0 violations. no-throw
surfaced 148:
- 76 in test files, handled by a config override turning only no-throw
off for **/*.spec.ts and **/__tests__/** (tests throw to simulate
defects and assert rejections; the other five rules stay on).
- 72 in source, each carrying a targeted oxlint-disable naming its
category — none could be restructured to Err(...) without changing
semantics:
- 33 sanctioned ValidationError / ContractMisuseError /
ApplicationFailure sites (CLAUDE.md rule 2 exception — Temporal's
terminal-failure semantics require the throw)
- 12 client-side technical faults thrown inside makeAsyncResult work
thunks (RuntimeClientError/TechnicalError — the throw IS the
defect-channel routing)
- 6 defect-cause / workflow-sandbox rethrows (unmodeled failures kept
on the defect channel)
- 1 cancellation rethrow (CancelledFailure must propagate)
- 7 declaration-time fail-fast config errors (worker startup /
contract definition / test setup)
- 13 example-domain throws in plain Promise helpers wrapped once at
the activity boundary via fromPromise(..., qualifyFailure(...))
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 30 out of 31 changed files in this pull request and generated no new comments.
Files not reviewed (1)
- pnpm-lock.yaml: Generated file
Comments suppressed due to low confidence (1)
.oxlintrc.json:20
- PR description says the opt-in rules
unthrown/no-throwandunthrown/prefer-ensureshould stay off, but.oxlintrc.jsonenables both aserror(and even adds an override to partially relaxno-throw). This makes the lint config disagree with the stated intent and is why so manyoxlint-disable-next-line unthrown/no-throwdirectives were introduced.
"rules": {
"unthrown/no-ambiguous-error-type": "error",
"unthrown/no-catch-all-pattern": "error",
"unthrown/no-throw": "error",
"unthrown/no-unhandled-result": "error",
"unthrown/prefer-async-result": "error",
"unthrown/prefer-ensure": "error"
},
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
Registers the
@unthrown/oxlintplugin with the four recommended rules (no-ambiguous-error-type,no-catch-all-pattern,no-unhandled-result,prefer-async-result; the opt-insno-throw/prefer-ensurestay off — the worker's sanctionedValidationErrorthrows would fightno-throw).@unthrown/oxlintjoins the first-partyminimumReleaseAgeExcludelist (published inside the 7-day supply-chain gate; same treatment asunthrownand@unthrown/vitest).The rules found 29 violations; 24 real fixes, 2 targeted disables:
no-ambiguous-error-type: the exportedClientInferSignal/Query/Updatealiases claimedAsyncResult<..., Error>while the proxies actually produce{Signal,Query,Update}ValidationError | WorkflowExecutionNotFoundError. The aliases now carry the concrete unions, and the mapped conditionals inclient.tsthat papered over the lie collapsed to identity —TypedWorkflowHandlenow references the aliases directly.prefer-async-result: 16 internal work-thunkPromise<Result>annotations dropped (with explicit type arguments pinned atmakeAsyncResultcall sites where TS can't collapse per-returnResultunions); 3 named async helpers converted to non-asyncAsyncResult-returning functions (behavior proven unchanged — callers'assertNoDefectalready re-threw into the enclosing throw→defect net)._internal_makeAsyncResultand its client re-export), each with the reason inline.AsyncResult<unknown, unknown>replaced with the concreteProxyErrorunion the code actually produces.Cherry-picked from the post-#354 branch onto main. Mirror adoption in amqp-contract: btravstack/amqp-contract#613.
Verification
pnpm lintclean;pnpm turbo run typecheck test16/16 tasks; per-package: client 140, worker 182, contract 120, testing 19 tests passing.🤖 Generated with Claude Code