Skip to content

feat!: Return Futures Instead of Coroutines - #199

Draft
natemort wants to merge 1 commit into
cadence-workflow:mainfrom
natemort:asynctask
Draft

natemort wants to merge 1 commit into
cadence-workflow:mainfrom
natemort:asynctask

Conversation

@natemort

Copy link
Copy Markdown
Member

Add WorkflowFuture, a covariant asyncio.Future subclass, to cadence.workflow. Update everything to use it rather than Awaitable or async.

Returning coroutines results in confusing behavior, especially as Cadence enforces strict determinism. Decisions are scheduled not when someone calls a method, but when they await on the returned coroutine.

What changed?

Why?

How did you test it?

Potential risks

Release notes

Documentation Changes

Comment thread tests/integration_tests/workflow/test_heartbeat.py Outdated
return res

async def execute(self, *args: P.args, **kwargs: P.kwargs) -> R:
def execute(self, *args: P.args, **kwargs: P.kwargs) -> WorkflowFuture[R]:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Cross-Repo: ai-skills TaskGroup fan-out example breaks: execute() returns a Future

Fix here and in cadence-workflow/ai-skills

Breaks in: cadence-workflow/ai-skills - skills/cadence-developer/knowledge/python/workflows.md - parallel fan-out example with asyncio.TaskGroup and tg.create_task(...execute(...))

This PR changes ActivityDefinition.execute to return a WorkflowFuture, which is an asyncio.Future subclass, where it used to return a coroutine. The change is intentional (feat!). The guidance in cadence-workflow/ai-skills, in skills/cadence-developer/knowledge/python/workflows.md, still shows parallel fan-out as tg.create_task(parallel_one.with_options(...).execute("1")) inside asyncio.TaskGroup. create_task only accepts coroutines and raises TypeError when given a Future, so workflows written from that skill will crash on first execution. This PR's own nondeterminism integration tests were migrated from TaskGroup/create_task to asyncio.gather(...) for the same reason. The consumer has to move. On this side, the breaking change should be called out in the release notes so dependent docs and skills get updated.

Here: Keep the new return type. Add a release note or changelog entry (the PR template's 'Release notes' section is empty) saying that execute(), execute_child_workflow(), sleep(), wait_condition() and the signal APIs now return WorkflowFuture. Code must use await, asyncio.gather(...), or .cancel() on the future directly, because asyncio.create_task(...)/TaskGroup.create_task(...) no longer accept these values.

There: In skills/cadence-developer/knowledge/python/workflows.md, rewrite the parallel fan-out example to await the returned futures with asyncio.gather. Do not wrap them in tg.create_task(...).

In cadence-workflow/ai-skills - skills/cadence-developer/knowledge/python/workflows.md:

results = await asyncio.gather(
    parallel_one.with_options(
        schedule_to_close_timeout=timedelta(seconds=10)
    ).execute("1"),
    parallel_two.with_options(
        schedule_to_close_timeout=timedelta(seconds=10)
    ).execute("2"),
)

Was this helpful? React with 👍 / 👎

) -> None:
self._transition(DecisionState.COMPLETED)
self._resolve(self.completed, result=event.result)
self.completed.complete_with_payload(event.result)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ [cross-pr] Merging with #196 loses typed activity results or ActivityError wrapping

Breaks when #199 and #196 both merge (in either order) and the state machine and DecisionManager hunks are combined mechanically. Any activity or child workflow that completes or fails then hits the mismatch.

How

  1. feat!: Return Futures Instead of Coroutines #199 makes ActivityStateMachine.handle_completed call self.completed.complete_with_payload(event.result) (cadence/_internal/workflow/statemachine/activity_state_machine.py:86). DecisionManager.schedule_activity(attrs, converter, result_type) passes a ConverterFn into DecisionFuture (decision_manager.py:159-172).
  2. feat!: Standardize Error Handling and Support Custom Error Reasons #196 gives ActivityStateMachine a third data_converter constructor argument. Its handle_failed/handle_timeout build errors with activity_failed_error(..., self._data_converter), and it resolves handle_completed with the raw Payload via _resolve.
  3. feat!: Standardize Error Handling and Support Custom Error Reasons #196's schedule_activity builds ActivityStateMachine(attrs, future, self._data_converter) with a plain future. feat!: Return Futures Instead of Coroutines #199 builds ActivityStateMachine(attrs, future) with a converting future.
  4. Combining the two means either handle_failed raises AttributeError on _data_converter, or await execute_activity(..., str) yields a raw Payload. The same split affects ChildWorkflowExecutionStateMachine and schedule_child_workflow.

Fix

Compared e7f8d08 with #196 at 59c684d

Was this helpful? React with 👍 / 👎

Comment on lines +971 to +985
async def _run() -> ResultType:
result_payload = await self._run_workflow_coro(
definition, child_info, input_payload, headers
)
return cast(
ResultType,
self._data_converter.from_data(result_payload, [result_type])[0],
)

loop = get_running_loop()
execution = WorkflowFuture[WorkflowExecution](loop=loop)
execution.set_result(
WorkflowExecution(workflow_id=child_id, run_id=child_run_id)
)
return _drive_future(

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ [cross-pr] Test env child failures skip #196's ChildWorkflowError wrapping

Breaks when #199 merges after #196 (or #196 is rebased onto #199), and a child workflow run in TestWorkflowEnvironment raises.

How

  1. feat!: Return Futures Instead of Coroutines #199 replaces _start_child_workflow with _execute_child_workflow. Its _run() coroutine only awaits _run_workflow_coro and converts the result (cadence/testing/_workflow_environment.py:971-978).
  2. _drive_future copies the task's raw exception into the ChildWorkflowFutureImpl (cadence/testing/_workflow_environment.py:118-126).
  3. feat!: Standardize Error Handling and Support Custom Error Reasons #196 wraps child failures with child_workflow_error_from_exception(...) and re-raises ContinueAsNewError in _start_child_workflow. That wrapping has nowhere to go in feat!: Return Futures Instead of Coroutines #199's _run().
  4. feat!: Standardize Error Handling and Support Custom Error Reasons #196's _start_child_workflow also builds ChildWorkflowFutureImpl(workflow_id=, run_id=, result_future=, result_type=, data_converter=). feat!: Return Futures Instead of Coroutines #199 removes that constructor, so the call raises TypeError.

Fix

Compared e7f8d08 with #196 at 59c684d

Was this helpful? React with 👍 / 👎

Comment on lines +15 to +18
from cadence.error import (
ChildWorkflowExecutionFailed,
StartChildWorkflowExecutionFailed,
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ [cross-pr] New tests import error names that #196 removes, causing ImportError

Breaks when #196 lands without compatibility aliases for its removed error classes, in either merge order. Test collection then fails on import.

How

  1. feat!: Return Futures Instead of Coroutines #199's tests/cadence/_internal/workflow/test_context_child_workflow.py:15-18 imports ChildWorkflowExecutionFailed and StartChildWorkflowExecutionFailed from cadence.error.
  2. The same file asserts pytest.raises(ChildWorkflowExecutionFailed, ...) and pytest.raises(StartChildWorkflowExecutionFailed) (test_context_child_workflow.py:326,455).
  3. feat!: Standardize Error Handling and Support Custom Error Reasons #196's cadence/error.py defines only the renamed ChildWorkflowError/StartChildWorkflowExecutionError/ActivityError and has no aliases for the old names, despite what its description says.

Fix

Compared e7f8d08 with #196 at 59c684d

Was this helpful? React with 👍 / 👎

Add WorkflowFuture, a covariant asyncio.Future subclass, to cadence.workflow. Update everything to use it rather than Awaitable or async.

Returning coroutines results in confusing behavior, especially as Cadence enforces strict determinism. Decisions are scheduled not when someone calls a method, but when they await on the returned coroutine.
@codecov

codecov Bot commented Oct 16, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 90.90909% with 15 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
cadence/testing/_workflow_environment.py 84.78% 4 Missing and 3 partials ⚠️
cadence/_internal/workflow/context.py 82.35% 3 Missing ⚠️
cadence/workflow/_interceptor.py 75.00% 3 Missing ⚠️
cadence/activity.py 50.00% 0 Missing and 1 partial ⚠️
cadence/workflow/_api.py 94.44% 0 Missing and 1 partial ⚠️
Files with missing lines Coverage Δ
cadence/_internal/activity/_definition.py 86.72% <100.00%> (ø)
...adence/_internal/workflow/child_workflow_future.py 100.00% <100.00%> (ø)
...al/workflow/statemachine/activity_state_machine.py 95.52% <100.00%> (ø)
...emachine/child_workflow_execution_state_machine.py 96.84% <100.00%> (+0.03%) ⬆️
...internal/workflow/statemachine/decision_manager.py 95.08% <100.00%> (+0.16%) ⬆️
...al/workflow/statemachine/decision_state_machine.py 97.29% <100.00%> (+0.63%) ⬆️
cadence/_internal/workflow/waiter.py 100.00% <100.00%> (ø)
cadence/workflow/__init__.py 100.00% <ø> (ø)
cadence/workflow/_context.py 91.42% <ø> (ø)
cadence/workflow/_types.py 100.00% <100.00%> (+10.20%) ⬆️
... and 5 more

... and 9 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@gitar-bot

gitar-bot Bot commented Oct 16, 2026

Copy link
Copy Markdown
Code Review ⚠️ Changes requested 1 closed / 5 findings

🔴 High risk · Replacing coroutine-returning workflow APIs with immediately scheduled futures is a breaking interface change that could break existing workflows or alter deterministic decision ordering.

Converts execute_activity, execute_child_workflow, sleep, wait_condition, and signal helpers to return WorkflowFuture instead of coroutines, so decisions are scheduled on call. Changes requested: the breaking change needs a release note, and open findings remain on the ai-skills TaskGroup fan-out example (create_task rejects futures), on merge conflicts with #196 that would drop typed results, ActivityError wrapping, and child-failure wrapping, and on new tests importing error names #196 removes.

⚠️ Cross-Repo: ai-skills TaskGroup fan-out example breaks: execute() returns a Future

📄 cadence/_internal/activity/_definition.py:88 📄 cadence/workflow/_api.py:24-32

Fix here and in cadence-workflow/ai-skills

Breaks in: cadence-workflow/ai-skills - skills/cadence-developer/knowledge/python/workflows.md - parallel fan-out example with asyncio.TaskGroup and tg.create_task(...execute(...))

This PR changes ActivityDefinition.execute to return a WorkflowFuture, which is an asyncio.Future subclass, where it used to return a coroutine. The change is intentional (feat!). The guidance in cadence-workflow/ai-skills, in skills/cadence-developer/knowledge/python/workflows.md, still shows parallel fan-out as tg.create_task(parallel_one.with_options(...).execute("1")) inside asyncio.TaskGroup. create_task only accepts coroutines and raises TypeError when given a Future, so workflows written from that skill will crash on first execution. This PR's own nondeterminism integration tests were migrated from TaskGroup/create_task to asyncio.gather(...) for the same reason. The consumer has to move. On this side, the breaking change should be called out in the release notes so dependent docs and skills get updated.

Here: Keep the new return type. Add a release note or changelog entry (the PR template's 'Release notes' section is empty) saying that execute(), execute_child_workflow(), sleep(), wait_condition() and the signal APIs now return WorkflowFuture. Code must use await, asyncio.gather(...), or .cancel() on the future directly, because asyncio.create_task(...)/TaskGroup.create_task(...) no longer accept these values.

There: In skills/cadence-developer/knowledge/python/workflows.md, rewrite the parallel fan-out example to await the returned futures with asyncio.gather. Do not wrap them in tg.create_task(...).

In cadence-workflow/ai-skills - skills/cadence-developer/knowledge/python/workflows.md:

results = await asyncio.gather(
    parallel_one.with_options(
        schedule_to_close_timeout=timedelta(seconds=10)
    ).execute("1"),
    parallel_two.with_options(
        schedule_to_close_timeout=timedelta(seconds=10)
    ).execute("2"),
)
⚠️ [cross-pr] Merging with #196 loses typed activity results or ActivityError wrapping

📄 cadence/_internal/workflow/statemachine/activity_state_machine.py:86 📄 cadence/_internal/workflow/statemachine/child_workflow_execution_state_machine.py:135 📄 cadence/_internal/workflow/statemachine/decision_manager.py:159-172 📄 cadence/_internal/workflow/statemachine/decision_manager.py:193-207

Breaks when #199 and #196 both merge (in either order) and the state machine and DecisionManager hunks are combined mechanically. Any activity or child workflow that completes or fails then hits the mismatch.

How

  1. feat!: Return Futures Instead of Coroutines #199 makes ActivityStateMachine.handle_completed call self.completed.complete_with_payload(event.result) (cadence/_internal/workflow/statemachine/activity_state_machine.py:86). DecisionManager.schedule_activity(attrs, converter, result_type) passes a ConverterFn into DecisionFuture (decision_manager.py:159-172).
  2. feat!: Standardize Error Handling and Support Custom Error Reasons #196 gives ActivityStateMachine a third data_converter constructor argument. Its handle_failed/handle_timeout build errors with activity_failed_error(..., self._data_converter), and it resolves handle_completed with the raw Payload via _resolve.
  3. feat!: Standardize Error Handling and Support Custom Error Reasons #196's schedule_activity builds ActivityStateMachine(attrs, future, self._data_converter) with a plain future. feat!: Return Futures Instead of Coroutines #199 builds ActivityStateMachine(attrs, future) with a converting future.
  4. Combining the two means either handle_failed raises AttributeError on _data_converter, or await execute_activity(..., str) yields a raw Payload. The same split affects ChildWorkflowExecutionStateMachine and schedule_child_workflow.

Fix

Compared e7f8d08 with #196 at 59c684d

⚠️ [cross-pr] Test env child failures skip #196's ChildWorkflowError wrapping

📄 cadence/testing/_workflow_environment.py:971-985

Breaks when #199 merges after #196 (or #196 is rebased onto #199), and a child workflow run in TestWorkflowEnvironment raises.

How

  1. feat!: Return Futures Instead of Coroutines #199 replaces _start_child_workflow with _execute_child_workflow. Its _run() coroutine only awaits _run_workflow_coro and converts the result (cadence/testing/_workflow_environment.py:971-978).
  2. _drive_future copies the task's raw exception into the ChildWorkflowFutureImpl (cadence/testing/_workflow_environment.py:118-126).
  3. feat!: Standardize Error Handling and Support Custom Error Reasons #196 wraps child failures with child_workflow_error_from_exception(...) and re-raises ContinueAsNewError in _start_child_workflow. That wrapping has nowhere to go in feat!: Return Futures Instead of Coroutines #199's _run().
  4. feat!: Standardize Error Handling and Support Custom Error Reasons #196's _start_child_workflow also builds ChildWorkflowFutureImpl(workflow_id=, run_id=, result_future=, result_type=, data_converter=). feat!: Return Futures Instead of Coroutines #199 removes that constructor, so the call raises TypeError.

Fix

Compared e7f8d08 with #196 at 59c684d

⚠️ [cross-pr] New tests import error names that #196 removes, causing ImportError

📄 tests/cadence/_internal/workflow/test_context_child_workflow.py:15-18 📄 tests/cadence/_internal/workflow/test_context_child_workflow.py:327 📄 tests/cadence/_internal/workflow/test_context_child_workflow.py:455

Breaks when #196 lands without compatibility aliases for its removed error classes, in either merge order. Test collection then fails on import.

How

  1. feat!: Return Futures Instead of Coroutines #199's tests/cadence/_internal/workflow/test_context_child_workflow.py:15-18 imports ChildWorkflowExecutionFailed and StartChildWorkflowExecutionFailed from cadence.error.
  2. The same file asserts pytest.raises(ChildWorkflowExecutionFailed, ...) and pytest.raises(StartChildWorkflowExecutionFailed) (test_context_child_workflow.py:326,455).
  3. feat!: Standardize Error Handling and Support Custom Error Reasons #196's cadence/error.py defines only the renamed ChildWorkflowError/StartChildWorkflowExecutionError/ActivityError and has no aliases for the old names, despite what its description says.

Fix

Compared e7f8d08 with #196 at 59c684d

✅ 1 closed
✅ Bug: Find/replace renamed proto field names, so heartbeat tests will crash

📄 tests/integration_tests/workflow/test_heartbeat.py:178 📄 tests/integration_tests/workflow/test_heartbeat.py:182 📄 tests/integration_tests/workflow/test_heartbeat.py:225 📄 tests/integration_tests/workflow/test_heartbeat.py:232 📄 tests/integration_tests/workflow/test_heartbeat.py:274
The activity_task → activity_future rename was meant for the workflow's local variable, but it also changed protobuf field names in the history assertions: activity_future_timed_out_event_attributes, activity_future_canceled_event_attributes and activity_future_cancel_requested_event_attributes. None of these fields exist. Only history_pb2 defines the activity_task_* names, and a grep for activity_future finds matches only in this test file. Protobuf HasField raises ValueError when given an unknown field name, so test_activity_without_heartbeat_times_out, test_activity_cancellation_is_delivered_by_heartbeat and test_sync_wait_for_cancelled will fail once they reach these checks. The fix is to restore the activity_task_* field names in the HasField calls and the attribute accesses.

🤖 Prompt for agents
Code Review: Converts `execute_activity`, `execute_child_workflow`, `sleep`, `wait_condition`, and signal helpers to return `WorkflowFuture` instead of coroutines, so decisions are scheduled on call. Changes requested: the breaking change needs a release note, and open findings remain on the `ai-skills` TaskGroup fan-out example (`create_task` rejects futures), on merge conflicts with #196 that would drop typed results, `ActivityError` wrapping, and child-failure wrapping, and on new tests importing error names #196 removes.

1. ⚠️ Cross-Repo: ai-skills TaskGroup fan-out example breaks: execute() returns a Future
   Files: cadence/_internal/activity/_definition.py:88, cadence/workflow/_api.py:24-32

   **Fix here and in [`cadence-workflow/ai-skills`](https://github.com/cadence-workflow/ai-skills)**
   
   **Breaks in:** [`cadence-workflow/ai-skills`](https://github.com/cadence-workflow/ai-skills) - [`skills/cadence-developer/knowledge/python/workflows.md`](https://github.com/cadence-workflow/ai-skills/blob/HEAD/skills/cadence-developer/knowledge/python/workflows.md) - `parallel fan-out example with asyncio.TaskGroup and tg.create_task(...execute(...))`
   
   This PR changes `ActivityDefinition.execute` to return a `WorkflowFuture`, which is an `asyncio.Future` subclass, where it used to return a coroutine. The change is intentional (`feat!`). The guidance in `cadence-workflow/ai-skills`, in `skills/cadence-developer/knowledge/python/workflows.md`, still shows parallel fan-out as `tg.create_task(parallel_one.with_options(...).execute("1"))` inside `asyncio.TaskGroup`. `create_task` only accepts coroutines and raises `TypeError` when given a Future, so workflows written from that skill will crash on first execution. This PR's own nondeterminism integration tests were migrated from `TaskGroup`/`create_task` to `asyncio.gather(...)` for the same reason. The consumer has to move. On this side, the breaking change should be called out in the release notes so dependent docs and skills get updated.
   
   **Here:** Keep the new return type. Add a release note or changelog entry (the PR template's 'Release notes' section is empty) saying that `execute()`, `execute_child_workflow()`, `sleep()`, `wait_condition()` and the signal APIs now return `WorkflowFuture`. Code must use `await`, `asyncio.gather(...)`, or `.cancel()` on the future directly, because `asyncio.create_task(...)`/`TaskGroup.create_task(...)` no longer accept these values.
   
   **There:** In `skills/cadence-developer/knowledge/python/workflows.md`, rewrite the parallel fan-out example to await the returned futures with `asyncio.gather`. Do not wrap them in `tg.create_task(...)`.
   
   In cadence-workflow/ai-skills - `skills/cadence-developer/knowledge/python/workflows.md`:
   
   ````
   results = await asyncio.gather(
       parallel_one.with_options(
           schedule_to_close_timeout=timedelta(seconds=10)
       ).execute("1"),
       parallel_two.with_options(
           schedule_to_close_timeout=timedelta(seconds=10)
       ).execute("2"),
   )
   ````

2. ⚠️ [cross-pr] Merging with [#196](<https://github.com/cadence-workflow/cadence-python-client/pull/196>) loses typed activity results or ActivityError wrapping
   Files: cadence/_internal/workflow/statemachine/activity_state_machine.py:86, cadence/_internal/workflow/statemachine/child_workflow_execution_state_machine.py:135, cadence/_internal/workflow/statemachine/decision_manager.py:159-172, cadence/_internal/workflow/statemachine/decision_manager.py:193-207

   **Breaks when** #199 and #196 both merge (in either order) and the state machine and DecisionManager hunks are combined mechanically. Any activity or child workflow that completes or fails then hits the mismatch.
   
   **How**
   
   1. #199 makes `ActivityStateMachine.handle_completed` call `self.completed.complete_with_payload(event.result)` (`cadence/_internal/workflow/statemachine/activity_state_machine.py:86`). `DecisionManager.schedule_activity(attrs, converter, result_type)` passes a `ConverterFn` into `DecisionFuture` (`decision_manager.py:159-172`).
   2. #196 gives `ActivityStateMachine` a third `data_converter` constructor argument. Its `handle_failed`/`handle_timeout` build errors with `activity_failed_error(..., self._data_converter)`, and it resolves `handle_completed` with the raw `Payload` via `_resolve`.
   3. #196's `schedule_activity` builds `ActivityStateMachine(attrs, future, self._data_converter)` with a plain future. #199 builds `ActivityStateMachine(attrs, future)` with a converting future.
   4. Combining the two means either `handle_failed` raises `AttributeError` on `_data_converter`, or `await execute_activity(..., str)` yields a raw `Payload`. The same split affects `ChildWorkflowExecutionStateMachine` and `schedule_child_workflow`.
   
   **Fix**
   
   - **This PR:** When rebasing onto #196, keep `complete_with_payload`/`ConverterFn` for results. Also pass `data_converter` into `ActivityStateMachine` and `ChildWorkflowExecutionStateMachine` so #196's error builders still work.
   - **#196:** If it lands second, call `complete_with_payload` in `handle_completed` instead of `_resolve(..., result=event.result)`, and adopt #199's `schedule_activity`/`schedule_child_workflow` signatures.
   
   _Compared `e7f8d08` with #196 at `59c684d`_

3. ⚠️ [cross-pr] Test env child failures skip [#196](<https://github.com/cadence-workflow/cadence-python-client/pull/196>)'s ChildWorkflowError wrapping
   Files: cadence/testing/_workflow_environment.py:971-985

   **Breaks when** #199 merges after #196 (or #196 is rebased onto #199), and a child workflow run in `TestWorkflowEnvironment` raises.
   
   **How**
   
   1. #199 replaces `_start_child_workflow` with `_execute_child_workflow`. Its `_run()` coroutine only awaits `_run_workflow_coro` and converts the result (`cadence/testing/_workflow_environment.py:971-978`).
   2. `_drive_future` copies the task's raw exception into the `ChildWorkflowFutureImpl` (`cadence/testing/_workflow_environment.py:118-126`).
   3. #196 wraps child failures with `child_workflow_error_from_exception(...)` and re-raises `ContinueAsNewError` in `_start_child_workflow`. That wrapping has nowhere to go in #199's `_run()`.
   4. #196's `_start_child_workflow` also builds `ChildWorkflowFutureImpl(workflow_id=, run_id=, result_future=, result_type=, data_converter=)`. #199 removes that constructor, so the call raises `TypeError`.
   
   **Fix**
   
   - **This PR:** On rebase, wrap the `_run_workflow_coro` call inside `_run()` in #196's try/except, which raises `child_workflow_error_from_exception(...)` and re-raises `ContinueAsNewError`.
   - **#196:** If it merges second, move the wrapping into #199's `_run()` coroutine and drop the old `ChildWorkflowFutureImpl(...)` construction.
   
   _Compared `e7f8d08` with #196 at `59c684d`_

4. ⚠️ [cross-pr] New tests import error names that [#196](<https://github.com/cadence-workflow/cadence-python-client/pull/196>) removes, causing ImportError
   Files: tests/cadence/_internal/workflow/test_context_child_workflow.py:15-18, tests/cadence/_internal/workflow/test_context_child_workflow.py:327, tests/cadence/_internal/workflow/test_context_child_workflow.py:455

   **Breaks when** #196 lands without compatibility aliases for its removed error classes, in either merge order. Test collection then fails on import.
   
   **How**
   
   1. #199's `tests/cadence/_internal/workflow/test_context_child_workflow.py:15-18` imports `ChildWorkflowExecutionFailed` and `StartChildWorkflowExecutionFailed` from `cadence.error`.
   2. The same file asserts `pytest.raises(ChildWorkflowExecutionFailed, ...)` and `pytest.raises(StartChildWorkflowExecutionFailed)` (`test_context_child_workflow.py:326,455`).
   3. #196's `cadence/error.py` defines only the renamed `ChildWorkflowError`/`StartChildWorkflowExecutionError`/`ActivityError` and has no aliases for the old names, despite what its description says.
   
   **Fix**
   
   - **This PR:** After #196 lands, switch the new tests (and any state machine imports) to `ChildWorkflowError`/`StartChildWorkflowExecutionError`/`ActivityError`.
   - **#196:** Ship the aliases its description promises (`ChildWorkflowExecutionFailed`, `StartChildWorkflowExecutionFailed`, `ActivityFailure`) in `cadence/error.py`.
   
   _Compared `e7f8d08` with #196 at `59c684d`_

Verification Repos 3 inspected · PRs 2 inspected

Functional validation No results

Rules No rules evaluated

Broader impact Repos 3 inspected PRs 2 inspected
Cross-repo 3 repositories inspected 1 open impact

cadence-workflow/ai-skills Inspected
cadence-workflow/cadence-samples Inspected
cadence-workflow/Cadence-Docs Inspected

Cross-PR 2 PRs inspected 3 open impacts

PR #196: feat!: Standardize Error Handling and Support Custom Error Reasons Inspected
PR #182: feat(observability): replayable logger and metrics Inspected

For more verification details, comment gitar display:verbose.

Options

Auto-apply is off → Gitar will not commit updates to this branch.
Display: compact → Showing compact verification results.

Comment with these commands to change the behavior for this request:

Auto-apply Compact
gitar auto-apply:on         
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Gitar

This branch has not been deployed

No deployments
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.

1 participant