Bug Description
FanInStep validates only that wait_for is a non-empty list; it never checks that the ids exist. At runtime execute does context.steps.get(step_id, {}) for each id (src/specify_cli/workflows/steps/fan_in/__init__.py):
results = []
for step_id in wait_for:
step_data = context.steps.get(step_id, {})
results.append(step_data.get("output", {}))
...
return StepResult(status=StepStatus.COMPLETED, output=resolved_output)
So a wait_for that names a step which does not exist — a typo, or a step declared after the fan-in (whose results cannot exist when the fan-in runs) — contributes {} to the join, and the step reports COMPLETED. The wiring error is silent and surfaces, if at all, as a confusing empty downstream result.
Steps to Reproduce
- Author a workflow whose
fan-in waits on an id that is never declared:
workflow:
id: repro
name: fan-in unknown wait_for
version: "1.0.0"
steps:
- id: collect
type: fan-in
wait_for: [tasks] # no step with id 'tasks' exists (typo for a real id)
specify workflow run repro
Expected Behavior
The workflow fails at validation, naming the offending id — mirroring #2957 (fail loud when a fan-out items expression does not resolve to a list). A step that is declared but only conditionally executed (inside an un-taken if/switch branch) is a legitimate empty-join case and must remain valid.
Actual Behavior
Status: completed, the unknown id silently contributes an empty {} to fan_in.results, no error.
Specify CLI Version
main @ b7e67f5
AI Agent
n/a (workflow engine bug, agent-independent)
Operating System
macOS (not OS-specific)
Python Version
3.11
AI disclosure (per CONTRIBUTING.md): this issue and the accompanying PR were authored with AI assistance (Claude Code), from a fan-out/fan-in audit; all code and claims were verified by running the repo's test suite locally.
cc @mnriem — small validation-only fix; would appreciate your review when you have a moment.
Bug Description
FanInStepvalidates only thatwait_foris a non-empty list; it never checks that the ids exist. At runtimeexecutedoescontext.steps.get(step_id, {})for each id (src/specify_cli/workflows/steps/fan_in/__init__.py):So a
wait_forthat names a step which does not exist — a typo, or a step declared after the fan-in (whose results cannot exist when the fan-in runs) — contributes{}to the join, and the step reportsCOMPLETED. The wiring error is silent and surfaces, if at all, as a confusing empty downstream result.Steps to Reproduce
fan-inwaits on an id that is never declared:specify workflow run reproExpected Behavior
The workflow fails at validation, naming the offending id — mirroring #2957 (fail loud when a fan-out
itemsexpression does not resolve to a list). A step that is declared but only conditionally executed (inside an un-takenif/switchbranch) is a legitimate empty-join case and must remain valid.Actual Behavior
Status: completed, the unknown id silently contributes an empty{}tofan_in.results, no error.Specify CLI Version
main @ b7e67f5
AI Agent
n/a (workflow engine bug, agent-independent)
Operating System
macOS (not OS-specific)
Python Version
3.11
AI disclosure (per CONTRIBUTING.md): this issue and the accompanying PR were authored with AI assistance (Claude Code), from a fan-out/fan-in audit; all code and claims were verified by running the repo's test suite locally.
cc @mnriem — small validation-only fix; would appreciate your review when you have a moment.