Skip to content

Deciding

A decision in a workflow has three parts, each a small node that costs nothing:

  1. Predicate (utility/predicate) compares values and answers true or false: is the stock above 0?
  2. Combine Conditions (utility/boolean_combine) joins several answers: all checks pass, or someone approved it by hand.
  3. Filter (utility/filter) lets a value through when the answer is true and rejects it otherwise: the branch that needed the value then does not run.

A decision never reaches an AI model as a question. The data is read with Extract, compared with Predicates, and the AI step runs only on the branch that passed — which is how a workflow checks something cheap before spending credits on something expensive.

A Predicate compares its input Value (a) with a second value, and answers with a boolean result.

Operation True when Types
equals, not_equals the two values are (not) equal two numbers, two texts, two booleans, or null
greater_than, greater_or_equal, less_than, less_or_equal the order holds two numbers
contains, starts_with, ends_with the text contains / starts with / ends with the other two texts, compared exactly (case counts)
is_null, is_not_null the value is (not) JSON null any; no second value

The second value comes from the Compare With port (b) when something is connected to it, otherwise from the parameter of the matching type: Compare Number for the order operations, Compare Text for the text operations, and, for equals, the parameter that matches the type of the value — Compare Number for a number, Compare Text for a text, Compare Boolean for a boolean. Connect Compare With when the threshold changes from run to run (a Number Input, a field of the data); set the parameter when it is fixed. When an optional input connected to Compare With is left empty, the parameter applies.

Comparisons are strict: the text "85" is not the number 85, and equals between a number and a text is an error (PREDICATE_TYPE_MISMATCH), not false. Set Extract’s expected type so each value arrives with the type the comparison needs.

is_null asks whether a value is JSON null — a field that exists and is empty. It does not detect a field that is missing: for that, read the field with Extract set to absent or default and use its found output, which is a boolean ready to combine.

Combine Conditions takes two to sixteen booleans on conditions_0, conditions_1, … and answers:

  • All (mode: all) — true when every condition is true;
  • Any (mode: any) — true when at least one is;
  • Invert Result turns the answer around, for none of (any + invert) or not all (all + invert).

Nest them for longer logic, and keep each level readable on the canvas: (in stock AND rated well AND brand safe) OR manual override is one all node feeding one any node, not a formula. Every condition is computed — there is no short-circuit — so put an expensive check behind a Filter rather than inside a combination.

A condition that does not arrive is not guessed: when any condition is absent, the node is skipped instead of deciding with a missing input.

Predicate compares values that already exist. When the condition is about content — is this photo blurred, does this message ask for a refund, is this document an invoice — ask it with Decide with a Model: it answers with a boolean, a value or a score and a probability on ports named after the question, and the nodes of this page route on them exactly as on a Predicate’s result.

A Filter receives a condition and a value. When the condition is true it passes the value on unchanged — the same type, the same file, the same text; when it is false it emits the value as rejected. Invert makes it pass on false. Its passed output repeats the decision as a boolean.

A rejected value stops the branch it feeds: every node after it is skipped, whatever port the value enters, and costs nothing. The workflow’s outputs on that branch are reported as absent, and the run still succeeds.

Two Filters on the same condition, one inverted, make an if/else: exactly one of the two values passes, and only its branch runs. The workflow then has one output per branch — one of them present, the other absent — and the caller reads which one arrived.

The condition must be a real boolean: the text "true" is refused (INVALID_CONDITION_TYPE). Connect a Predicate, Combine Conditions, a Boolean Input, a found output or a boolean field read with Extract.

The decisions lab checks a product before publishing it. It reads the name, the stock, the rating and a brand safe flag from the product; two Predicates compare the stock with 0 and the rating with a minimum that comes from an input; one Combine Conditions requires all three checks, a second lets a manual Publish anyway switch override them; and two Filters make the if/else — a listing line when the product passes, a hold note when it does not.

The lab, top to bottom: the product, the minimum rating and the override switch; four Extracts; the In stock and Rated well enough Predicates; All checks pass and Checks pass or override; Publish and Hold (inverted) Filters; the listing line and the hold note, one present and one absent

Oak chair, stock 12, rating 4.6 Linen cushion, stock 0, rating 4.8
In stock (stock > 0) true false
Rated well enough (rating >= 4) true true
All checks pass true false
Checks pass or override true false
Listing line Now available: Oak chair absent
Hold note absent On hold for review: Linen cushion

Both runs complete in about ten seconds at no cost; in each, the branch that was not taken is skipped. Turn Publish anyway on and the cushion is published despite its stock.

Terminal window
node madoo-install-example.mjs lab-decisions --api <your Madoo API URL> --key <key.json> --run

The second product is in run-inputs-out-of-stock.json.

Code Cause Fix
PREDICATE_TYPE_MISMATCH the two values have different types, an order operation received a text, or the comparison value is missing give both sides the same type (Extract with an expected type); set the typed parameter or connect Compare With
INVALID_PREDICATE_OPERATION the operation is not one of the eleven pick one from the table
MISSING_LEFT_INPUT nothing is connected to Value connect the value to compare
INVALID_CONDITION_TYPE a Filter condition is not a boolean (for example the text "true") connect a boolean producer
INVALID_BOOLEAN_CONDITION a Combine Conditions input is not a boolean connect booleans only
MIXED_CONDITION_INPUT_FORMS a boolean array and single conditions are connected together use one form
INVALID_BOOLEAN_COMBINE_MODE Mode is neither all nor any choose all or any