mirror of
https://github.com/github/spec-kit.git
synced 2026-08-03 06:26:30 +08:00
fix(workflows): fail fan-in loudly on a non-string wait_for entry (#3579)
`FanInStep.execute` already guards a non-list `wait_for` (#3482), and the engine's load-time validation rejects non-string entries. But the engine does not auto-validate step config, so on an unvalidated run `execute` iterated the list's *elements* raw: - An unhashable entry (a list/dict from a YAML indentation slip like `wait_for: [[a, b]]`) crashed the whole run at `context.steps.get(entry, ...)` with a raw `TypeError: cannot use 'list' as a dict key`. - A hashable-but-non-string entry (`wait_for: [123]`) silently joined an empty `{}` and still reported COMPLETED — the exact "silent empty result + COMPLETED" wiring bug the whole-list guard and the engine's fan-in validation both exist to prevent. Extend the execute() guard to reject any non-string entry with the engine's "entries must be step-id strings" phrasing, mirroring the sibling non-list guard right above it. Adds regression coverage for unhashable and hashable-non-string entries. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -42,6 +42,28 @@ class FanInStep(StepBase):
|
||||
output={"results": []},
|
||||
)
|
||||
|
||||
# A non-string entry can never match a real step id. An unhashable one
|
||||
# (a list/dict from a YAML indentation slip like ``wait_for: [[a, b]]``)
|
||||
# crashes the whole run at ``context.steps.get(step_id, ...)`` below with
|
||||
# a raw TypeError; a hashable-but-non-string one (``wait_for: [123]``)
|
||||
# silently joins an empty ``{}`` and still reports COMPLETED — the exact
|
||||
# "silent empty result + COMPLETED" wiring bug the whole-list guard above
|
||||
# and the engine's fan-in validation (engine.py) both reject. The engine
|
||||
# does not auto-validate step config, so fail this step loudly on an
|
||||
# unvalidated run too, using the engine's phrasing.
|
||||
bad_entries = [w for w in wait_for if not isinstance(w, str)]
|
||||
if bad_entries:
|
||||
first = bad_entries[0]
|
||||
return StepResult(
|
||||
status=StepStatus.FAILED,
|
||||
error=(
|
||||
f"Fan-in step {config.get('id', '?')!r}: 'wait_for' entries "
|
||||
f"must be step-id strings, got {type(first).__name__} "
|
||||
f"({first!r})."
|
||||
),
|
||||
output={"results": []},
|
||||
)
|
||||
|
||||
# Collect results from referenced steps
|
||||
results = []
|
||||
for step_id in wait_for:
|
||||
|
||||
Reference in New Issue
Block a user