Problem/Motivation
When a token reaches a node that has outgoing flows but none of them evaluate true, the token is consumed, no successor is spawned, and once the last live token is gone the instance completes. Nothing is recorded: no incident, no status, no log entry. The run reads exactly like a successful one.
WorkflowExecutor::advanceNode() already draws the distinction, in a comment on the status write: a node that still has outgoing flows (a branch dead-ending on false conditions) is left untouched, since the instance is not resting there. That is correct for the status, but the dead end itself then passes unreported.
This is not hypothetical. After the outcome and payload split in #3613729: Split the overloaded result vocabulary into the outcome and the completion payload, a definition still comparing validation.result met a task that writes its payload keyed outcome. Every run ended immediately after the operator validation step, state completed, zero incidents, and the person who submitted the form saw a normal confirmation page. Diagnosing it meant reading the instance, its tokens, its variables, the live definition and the pinned snapshot side by side, when a single incident naming the condition and the value it saw would have told the whole story.
The same shape occurs without any rename: a typo in a condition, a variable a provider failed to write, an outcome value no flow matches, or a gateway whose branches are all guarded.
Proposed resolution
When a token is about to be consumed at a node that has outgoing flows and the evaluator returns no live successors, raise an incident through the existing incident machinery rather than consuming quietly. The message should name the node and the conditions that were evaluated with the values they saw, since that is what makes the cause obvious at a glance.
A node with no outgoing flows at all stays untouched: that is a legitimate end, and the engine already keys its status write on exactly that test.
If silent completion is wanted anywhere, it should be a deliberate choice, so an optional policy in orchestra.settings alongside on_unrecoverable_failure would fit: incident (the default) or complete.
Remaining tasks
- Raise the incident in the executor at the dead-end branch.
- Message carrying the node id, the evaluated conditions and the observed values.
- Optional setting, if the policy is wanted.
- Kernel coverage: all-false conditions raise an incident rather than completing; a node with no outgoing flows still completes normally; a split with at least one live flow is unaffected.
- Documentation.
User interface changes
An incident now appears where a run previously ended quietly.
API changes
None, unless the policy setting is added.
Issue fork orchestra-3613800
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #4
mably commented