Conditions and invariants
Conditions are structured XML rather than executable scripts. Wrap exactly one condition in when or assert. A step's when controls whether that stage participates; a field's when controls that field. Conditions are evaluated against current inputs and state.
<journey id="conditions" title="Conditional process">
<input key="name" label="Name" kind="text" required="true"/>
<form id="details" title="Details">
<field key="count" label="Count" kind="number" required="true" defaultValue="1">
<validation min="1" max="10"/>
</field>
</form>
<info id="bulk" title="Bulk order">
<when><all><gt path="$.state.count" type="number" value="5"/><not><eq path="$.state.count" type="number" value="0"/></not></all></when>
<body>{{ $.inputs.name }}, please check capacity.</body>
<hint canSuggest="true">Help review this order.</hint>
</info>
<done id="done" title="Ready"><body>Ready for {{ $.inputs.name }}.</body></done>
<invariant id="positive" description="Count must be positive">
<when><exists path="$.state.count"/></when>
<assert><gte path="$.state.count" type="number" value="1"/></assert>
</invariant>
</journey>Comparisons are eq, neq, lt, lte, gt and gte. Set type="number" or type="boolean" when comparing typed answers. The number 5 does not equal the string "5". Every comparison needs a value, except type="null". Ordering (lt, lte, gt, gte) compares numbers with numbers or strings with strings, so it accepts only type="number" or type="string". exists means present and non-null; an empty string still exists. Use value="false" on exists to test absence.
Use all for conjunction, any for alternatives and not with exactly one child. Avoid empty all/any groups even if the compiler accepts them: explicit conditions are easier to review. Conditions select from an ordered stage sequence; there are no authored jump targets or loops.
An invariant has an id, optional description, optional when and required assert. A conditional invariant means "if when holds, assert must hold", which is logical implication. Invariants document the obligations a process must meet. Do not assume they are a server authorization boundary or that they replace visible field validation and mutation preconditions: the CoCoCo app does not enforce arbitrary invariants while a Journey runs.
Use unconditional terminal completion and test both sides of each conditional path. Retained answers can change which stages are active when the user goes back. Do not depend on the displayed step number as a stable identifier.
Published platform manual · revision c760cde8b223