Conditions
A step with when runs only when its condition holds for the request payload; otherwise it is
skipped and the skip is recorded. Conditions are plain JSON, so a flow can be stored, compared and
shown to people, and no code from a flow ever runs.
// Plain JSON, evaluated against the payload; no code runs.const bigOrForeign: Condition = { any: [ { field: "amount", op: "gt", value: 10_000 }, { field: "vendor.country", op: "nin", value: ["NL", "BE", "DE"] }, ],};const notInternal: Condition = { not: { field: "internal", op: "eq", value: true } };Runs in CI:examples/docs-snippets/src/concepts/conditions.ts
| Operator | Compares |
|---|---|
eq, neq |
Any JSON value, strictly (1 is not "1") |
gt, gte, lt, lte |
Numbers with numbers, strings with strings (ISO timestamps compare correctly) |
in, nin |
A value against a list |
all, any, not |
Other conditions |
field is a dot path into the payload (vendor.country, lines.0.amount).
Conditions fail closed
Section titled “Conditions fail closed”A comparison that does not make sense, such as a number against a string or a missing field, never quietly counts as false. Rungs evaluates every condition at submit, so the requester gets the error, not an approver weeks later:
try { await rungs.submit({ flow: "purchase", requesterId: "u_req", subject: { type: "purchase", id: "PO-9" }, payload: { amount: "12000", vendor: { country: "US" }, internal: false }, // amount is a string });} catch (error) { if (error instanceof ConditionError) { // Refused at submit, so an approver never meets a broken condition later (EC-40, EC-41). console.log(error.field, error.expected, error.received); // "amount" "number" "string" refused = error; }}Runs in CI:examples/docs-snippets/src/concepts/conditions.ts
Conditions read the payload as it was at submit (EC-36). When the data changes, resubmit the request with the new payload.