fix(workflows): command/prompt steps fail cleanly on a non-string integration (#3626)

_try_dispatch guarded only 'if not integration_key', then called
get_integration(integration_key). A non-string integration (a list/dict, or an
expression like integration: "{{ steps.pick.output.agents }}" that resolves to a
list) reached the registry dict lookup and raised 'TypeError: unhashable type:
list', aborting the entire workflow run. Widen the guard to also require a str,
so a non-string integration is treated as not-dispatchable and execute() falls
through to its existing FAILED StepResult (unconfigured integration=None still
returns None as before). Applied to both command and prompt steps.

Tests: a list integration now yields a FAILED result (fail before: TypeError).

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ali jawwad
2026-07-22 17:35:39 +05:00
committed by GitHub
parent 4f4d19ba93
commit aee9df00d4
3 changed files with 38 additions and 2 deletions

View File

@@ -1162,6 +1162,21 @@ class TestCommandStep:
result = step.execute(config, ctx)
assert result.output["integration"] == "gemini"
def test_execute_non_string_integration_fails_cleanly(self):
"""A non-string integration (e.g. a list from an expression that resolved
to one) must FAIL the step cleanly, not crash the run with
'TypeError: unhashable type: list' from get_integration's dict lookup."""
from specify_cli.workflows.steps.command import CommandStep
from specify_cli.workflows.base import StepContext, StepStatus
step = CommandStep()
config = {
"id": "s", "command": "speckit.plan",
"integration": ["claude"], "input": {},
}
result = step.execute(config, StepContext())
assert result.status == StepStatus.FAILED
def test_step_override_model(self):
from unittest.mock import patch
from specify_cli.workflows.steps.command import CommandStep
@@ -1359,6 +1374,20 @@ class TestPromptStep:
assert result.output["integration"] == "claude"
assert result.output["dispatched"] is False
def test_execute_non_string_integration_fails_cleanly(self):
"""A non-string integration must FAIL the step cleanly, not crash with
'TypeError: unhashable type: list' from get_integration's dict lookup."""
from specify_cli.workflows.steps.prompt import PromptStep
from specify_cli.workflows.base import StepContext, StepStatus
step = PromptStep()
config = {
"id": "p", "type": "prompt", "prompt": "do it",
"integration": ["claude"],
}
result = step.execute(config, StepContext())
assert result.status == StepStatus.FAILED
def test_execute_with_step_integration(self):
from unittest.mock import patch
from specify_cli.workflows.steps.prompt import PromptStep