Station v0.71 can silently execute a different provider action when a workflow node specifies an explicit but unregistered action_id.
Confirmed with a harmless stub execution.
Reproduction:
Use a workflow effect node with:
action_id = "slack_not_registered"
provider = "slack"
The explicit action_id does not exist in the integration registry.
Expected:
Because the workflow explicitly requested a specific action_id, resolution should fail closed when that action is not registered.
The node should be rejected rather than substituted with another action.
Actual:
integration_registry.resolve_node() fails to find the explicit action_id, then falls back to the provider-level registry entry.
In the reproduction, the node resolved to:
slack_message_post
and that fallback action was actually executed.
The workflow therefore performed a different action than the explicit action_id requested.
Root cause:
integration_registry.py attempts explicit action_id resolution first, but if it is not found it still falls back to REGISTRY[provider].
This fallback occurs even when the workflow explicitly supplied an action_id.
Validation does not reject the mismatch before execution.
Expected behavior:
If action_id is explicitly present:
- resolve exactly that action;
- if it is not registered, fail closed.
Provider fallback should only be used for legacy/provider-only nodes that do not specify an action_id.
Suggested fix:
If action_id is present but not found, return None / fail validation.
Only use provider fallback when action_id is absent.
Add regression coverage for:
- valid explicit action_id resolves exactly;
- invalid explicit action_id is rejected;
- provider-only legacy node may still use documented fallback behavior.
Impact:
An invalid or stale action_id can cause Station to execute a different action than the workflow requested.
This can also change the action class, approval/policy surface, and receipt semantics associated with the execution.
Confirmed against Station v0.71 source and runtime behavior with a harmless stub.