Skip to content

Validate unsupported workflow handlers before execution - #181

Merged
rmcdaniel merged 4 commits into
mainfrom
fix/177-synchronous-workflow-handlers
Oct 20, 2026
Merged

rmcdaniel merged 4 commits into
mainfrom
fix/177-synchronous-workflow-handlers

Conversation

@rmcdaniel

@rmcdaniel rmcdaniel commented Oct 20, 2026 •

Copy link
Copy Markdown
Member

Problem

Unsupported coroutine signal/update handlers and generator handlers are silently skipped or return unusable values. Defining them must fail before durable work is dispatched.

Source review also corrects #177's initial broader premise: the released Worker already awaits async queries and async update validators. Their working deadline/capacity paths remain supported; the patch does not remove them. Maintainer contract correction.

Change

  • Validate every decorated handler's callable shape, including inherited and wrapped methods, when defining, registering or replaying workflows.
  • Refuse coroutine signal/update handlers and all generator/async-generator handlers with a named InvalidWorkflowDefinition.
  • Guard handler results so synchronous wrappers cannot leak async/generator values. The Worker explicitly opts into awaiting query/validator results; local synchronous helpers refuse and close coroutines.
  • Preserve existing query deadline/authority and validator concurrency controls.
  • Add a replay corpus fixture and SDK lifecycle reference. Website #333 owns the matching explanation in all eight locales and stays held until release acceptance.

Verification

Tests-first 4e135a2 fails on the unchanged runtime. Component f5769bb passes Ruff, strict mypy on all 33 source files and the full non-integration suite: 2,976 pass, two explicit skips, 105 integration cases deselected. A separate handler/entrypoint/replay-corpus selection passes 191 with runtime warnings treated as errors.

Fresh Sonar analysis on that component passes the gate but reports four actionable findings: two oversized preparation signatures and two tests containing multiple invocations inside exception assertions. Current 106d9e01310b79247dc16897e390837549459f89 addresses all four in source. Prepared callbacks retain the Worker's existing async query and validator support; the public synchronous helpers enforce their synchronous result boundary. Codec-observer assertions now target the actual validator preparation function. Ruff, strict mypy on all 33 source files and 441 focused tests pass, with two explicit skips, including handlers, entry validation, signal/query/update behavior, Worker dispatch and query authority. Fresh whole-source CI and Sonar remain pending; the earlier full-suite result does not qualify this whole head.

An intermediate refactor run failed 59 controls because its diagnostic identifiers and test spies still targeted the old preparation function. The prospective correction preserves the codec assertions. The superseded f576 CI run was canceled after its test jobs were already canceled and its advisory job had completed; its queued aggregate is now terminal canceled. No published or real-HTTP acceptance is claimed.

The initial focused selection passed 190 tests before the compatibility correction. The first local full run was unsuccessful: it exposed the existing async-validator fixture plus missing Git and callback-reaping limitations in the tool container. Its 2,975 passes, nine failures and three errors remain a failed original. The final result uses a fresh container with Git and an init process, with source/dependencies and existing assertions preserved except the deliberate handler fix.

Fresh 106 Sonar analysis remains failed: 5.4% new duplication exceeds the unchanged 3% gate, and validator preparation has complexity 19/15. The next source c9ed469c19972e6854cf65248753310fe9c7a3b5 groups the private validator replay options into an immutable value and separates validator invocation/error conversion from replay preparation. Public synchronous signatures and existing Worker async behavior stay intact. Its Ruff, strict mypy33 and 417 focused tests / two explicit skips pass, including the actual codec-boundary spies. Fresh normal analysis and whole-source qualification remain required; no rule/profile/threshold/exclusion changed. The superseded 106 CI was canceled while all eight substantive jobs were still queued, before new c9ed qualification.

Exact c9ed Sonar 39472722164 and its GitHub app check now PASS. Independent public API readback reports 0.0% new duplication, under the unchanged 3%, and zero OPEN/CONFIRMED issues. The separate signal/update/query/replay selection passes 42 with runtime warnings treated as errors. Full normal CI 39472722100 is still queued; no exact-head whole-suite or PyPI publication acceptance is borrowed from earlier components.

Website #333 prepared 537a9af53e contains the corrected Python lifecycle page in all eight locales, verified MDX/examples/anchors/API identifiers and source hashes. It remains draft and unpublished until immutable artifacts and installed consumers pass.

This prepares the still-unpublished Python 2.6.2 patch; no earlier source pass is carried across heads. No client retry/receipt, Server, SDK wire, frozen actor or native change. #177 remains open until compatible publication, installed behavior and all-locale docs are complete.

@sonarqubecloud

Copy link
Copy Markdown

@rmcdaniel
rmcdaniel marked this pull request as ready for review October 20, 2026 19:38
@rmcdaniel
rmcdaniel merged commit 1b03ed2 into main Oct 20, 2026
15 checks passed
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