Support multi-target conditional switch cases - #3328
Conversation
Greptile SummaryThis PR adds multi-target conditional switch cases to the flow graph and native runtime while explicitly preventing unsupported Argo execution.
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains; the previously reported Argo target-dropping path is prevented before workflow compilation and backed by a runtime rejection guard.
|
| Filename | Overview |
|---|---|
| metaflow/flowspec.py | Accepts and validates scalar or non-empty list/tuple targets, preserving the selected case as the runtime transition. |
| metaflow/graph.py | Parses list-valued switch cases, exposes flattened graph edges, and tracks case-local split ancestry. |
| metaflow/lint.py | Validates case-local split/join balance and rejects overlapping targets involving multi-target cases. |
| metaflow/runtime.py | Queues every selected case target and derives join cardinality from the selected switch branch roots. |
| metaflow/task.py | Resolves the selected switch case from actual join inputs and validates its expected input count. |
| metaflow/plugins/argo/argo_workflows.py | Rejects multi-target switch cases before workflow-template compilation, fixing the previously reported target-dropping path. |
| metaflow/plugins/argo/argo_workflows_decorator.py | Adds a runtime fallback that refuses to serialize a multi-target transition as Argo's scalar switch output. |
| metaflow/plugins/cards/ui/src/types.ts | Extends the DAG UI contract to represent scalar and list-valued switch targets. |
| test/unit/test_switch_fanout_cases.py | Covers graph parsing, validation constraints, selected-case resolution, and native runtime fanout behavior. |
| test/unit/test_argo_conditional_input_paths.py | Verifies both deploy-time and runtime rejection of unsupported Argo switch fanout. |
Reviews (10): Last reviewed commit: "Clean up switch lint handling" | Re-trigger Greptile
saikonen
left a comment
There was a problem hiding this comment.
Changes look good. The argo-workflows implementation still needs modifications to support this though, or a raise as unsupported if its going to be a follow-up PR.
|
@saikonen done — added the raise in 12e43cb. Two guards:
Will open a follow-up to implement Argo support and move the tests to OSS. |
|
Follow-up PR for Argo support: #3331 |
talsperre
left a comment
There was a problem hiding this comment.
Requesting changes based on two reproduced correctness problems:
- A fanout case containing a nested split or foreach passes validation but fails during local execution. The scheduler loses the outer switch-case identity, and the task-side join cardinality check has the same assumption.
- Two fanout cases cannot share one join because lint compares each individual case against the union of predecessors from every case.
The current unit tests only call FlowSpec.next() directly, so they do not exercise either failing runtime path.
Full review, reproductions, locations, and suggested fix direction:
https://gist.github.com/talsperre/1a44dee761af17e7f9d47b454b6bf393
Reviewed at 12e43cb5b230395a2fa0c8265b6fa8d338a1958f.
|
Addressed the review findings in
Validation:
|
|
triggered internal tests |
|
Re-reviewed at I found one remaining blocking correctness issue: if two fanout cases share a target but have different cardinalities, local join scheduling depends on task completion order. With
The runtime reconstructs the selected case from the finishing branch and chooses the first matching case; Updated review with the complete runnable flow, exact commands, observed output, and code locations: |
|
Addressed the overlapping-target blocker in Multi-target switch cases are now required to have disjoint target sets. Lint rejects the reproduced Added the exact overlap shape as a regression test. Focused graph, fanout-runtime, and Argo suite: |
753cc95 to
c1dde7e
Compare
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
64889dd to
91f39e6
Compare
Summary
Allows a conditional
self.next(..., condition=...)case to target either one step or a non-empty list or tuple of steps. A selected multi-target case fans out only after the condition is evaluated; existing single-target switch behavior is unchanged.This removes boilerplate steps whose only purpose is to fan out after a switch case.
Behavior and constraints
end.Implementation
FlowSpec.nextvalidation to accept non-empty list and tuple case values.Validation
python -m pytest -q test/unit/test_switch_fanout_cases.py test/unit/test_argo_conditional_input_paths.py test/unit/test_graph_structure.py— 75 passed.black --checkandgit diff --checkpass.