In terms of decision logic, a fork functions as a crossroads. When deciding which decision step in the flow should come next, use logical rules.

The example below illustrates a decision flow that forks into two branches. Champion and Challenger are the branches (akin to A/B testing in logic). The value random_number from a data object is used for the split.

What happens when no branch matches

A fork picks exactly one branch. The branches are tried in the order they are shown, and the first one whose conditions all match wins.

If none of them match, the run stops at the fork. Every step after it is skipped, and the response comes back with HTTP 200 holding only what was computed before the fork. Nothing is reported as an error, so the run is easy to mistake for a normal one. The fork's output carries "__status": "no_branch_matched", and the response lists the fork under __forks_unmatched.

Two situations lead to it.

The conditions leave a gap. One branch takes scores of 0 to 30, another takes 40 and above, and a score of 35 belongs to neither.

The value is not there. A missing number is treated as zero. It therefore fails every branch that asks for a value above something, and quietly matches branches that ask for a value below something. Both are worth knowing: a request that omits an attribute can end up on your lowest branch, or on no branch at all.

Always give a fork a catch-all

End every fork with a branch whose condition is any value, pointing at whatever you want done when the case is unclear, usually a manual review or a decline. Because branches are tried in order, a catch-all placed last only receives the runs that no earlier branch claimed, and the fork can no longer run out of options.

A catch-all does not replace checking your intervals. A missing attribute that reads as zero still matches a low branch before the catch-all is reached, so where a value is genuinely required, test for it before the fork.