Only tool, loopback and agent-result cycles are legal
Rejecting every other cycle is what makes the forward graph acyclic. Loop membership is defined by reachability sweeps over that acyclic graph, so loosening this rule would make loop extent ill-defined rather than merely permissive.
The rule
- Cycle detection ignores tool-availability, loopback and agent-result edges.
- A cycle formed only from those edge types is legal.
- Any other cycle refuses compilation.
- The graph that remains once the ignored edge types are removed is therefore acyclic, and rules that depend on that acyclicity may assume it.
What it means
Cycle detection does not walk the graph as stored — it first removes every tool-availability, loopback and agent-result edge, then checks what is left for a cycle. A cycle is legal exactly when it disappears once those edge types are taken out, whatever mix of edge types formed it. The one case a mix does not save: a cycle built entirely from ordinary connections has nothing for the removal to take out, so it always refuses compilation.
Example
The same two-node shape, back and forth, once with both edges ordinary and once with the return edge a loopback:
[
{ "source": "node_a", "target": "node_b" },
{ "source": "node_b", "target": "node_a" }
][
{ "source": "iterator_1", "target": "node_b", "sourceHandle": "iterator_1-output-item" },
{ "source": "node_b", "target": "iterator_1", "targetHandle": "iterator_1-input-loop_back" }
]The first refuses compilation with Circular dependency detected in workflow; the second compiles, because removing the loopback edge before
checking leaves nothing but a single forward connection.