| Field | Value |
|---|---|
| RFC | 0134 |
| Title | Edge conditions — truthy / falsy operators |
| Status | Accepted |
| Author(s) | openwop-app maintainers |
| Created | 2026-07-23 |
| Updated | 2026-07-23 (Draft → Active: wire schema + spec + conformance landed; Active → Accepted 2026-07-23: openwop-app tier-1 reference host mapped the operators + witnessed edge-condition-truthy-falsy §B non-vacuously under OPENWOP_REQUIRE_BEHAVIOR=true — rev c8854cb5, PR openwop-app#2438) |
| Affects | schemas/workflow-definition.schema.json (§EdgeCondition), schemas/workflow-chain-pack-manifest.schema.json (§EdgeCondition, inlined), spec/v1/workflow-definition.md, conformance scenarios |
| Compatibility | additive per COMPATIBILITY.md |
| Supersedes | — |
| Superseded by | — |
Summary
A WorkflowEdge.condition (EdgeCondition) routes a target node only when the condition holds against a source node's output. The wire EdgeCondition.type enum is ["expression", "equals", "notEquals", "contains", "regex"] — every operator except expression/regex compares the left path against a right operand. There is no way, over the wire, to express the most common branch shape of all: "take this edge iff left is truthy" (an approval gate's approved output, a boolean flag, a present-or-absent field) — or its negation. Hosts that evaluate edges already implement truthy/falsy operators internally (they are the natural predicate for a boolean gate output), but a conformant client cannot emit them and a portable workflow-chain pack cannot carry them. This RFC adds truthy and falsy to the EdgeCondition.type enum. Additive — no existing condition changes meaning.
Motivation
Two concrete, current gaps:
1. The wire cannot express a boolean branch. The canonical approval pattern is core.chat.approvalGate → two conditioned edges: one fires when approved is truthy (proceed), one when approved is falsy (reject). Modelling this over the wire today forces { type: "equals", left: "approved", right: true } / { type: "notEquals", left: "approved", right: true }. That is a semantic mismatch on the two paths that matter: equals true is false for a skipped upstream (output undefined), whereas falsy is true — and reject-safe barrier wiring (a none_failed fan-in over a core.fail that runs only on the falsy edge) depends on the skipped-source path evaluating the way truthy/falsy do, not the way equals/notEquals do. Authors that need the correct skip semantics have no wire operator for it.
2. Portable chains can't carry it, so real workflows can't convert. RFC 0013 workflow-chain packs use the SAME EdgeCondition shape (inlined in workflow-chain-pack-manifest.schema.json). A host expanding a chain maps the wire condition to its executor's native condition. The openwop-app reference host's mapper supports exactly the wire operators — so a chain cannot express a truthy/falsy branch, and workflows built on the approval-gate + reject-safe-barrier pattern (a challenge-authoring "factory", a multi-channel campaign orchestration) are blocked from converting to editable chain packs. This RFC unblocks them.
The operators are not new behavior — hosts that route on a boolean gate output already compute truthiness. RFC 0134 makes the wire able to say it, closing a gap between what hosts do and what the protocol can express.
Proposal
Wire shape change (schemas/workflow-definition.schema.json §EdgeCondition)
Add two members to the type enum. truthy/falsy take a left path and no right operand (they test the resolved value of left for JS-style truthiness).
"EdgeCondition": {
"type": "object",
"properties": {
"type": {
"type": "string",
- "enum": ["expression", "equals", "notEquals", "contains", "regex"]
+ "enum": ["expression", "equals", "notEquals", "contains", "regex", "truthy", "falsy"]
},
"left": { "type": "string", "description": "Left operand path (e.g., 'status', 'output.approved')." },
"right": { "description": "Right operand value (any JSON value)." },
"expression": { "type": "string", "description": "Used when type='expression'." }
},
"additionalProperties": false
}
The same two-member addition applies to the inlined EdgeCondition $def in schemas/workflow-chain-pack-manifest.schema.json (RFC 0013 keeps the manifest self-contained for pack-loader validators), so a chain fragment edge can carry the operators.
Behavior (RFC 2119)
- A host that evaluates
EdgeConditionMUST treattype: "truthy"as: the edge
contributes to the target iff the value at left (resolved against the source node's output, same resolution as the other operators) is truthy — i.e. not one of false, null, undefined, 0, NaN, "", or absent. type: "falsy" is its exact complement (the edge contributes iff left resolves to one of those values, or is absent).
truthy/falsyMUST NOT requireright; a host MUST ignorerightif
present on a truthy/falsy condition (it is meaningless, not an error — forward-compat).
leftis REQUIRED fortruthy/falsy(as forequals/notEquals/contains);
a truthy/falsy condition missing a non-empty left is a malformed edge and the host MUST reject it at ingest/expansion (the existing chain_edge_condition_invalid / definition-validation path), never silently drop the edge.
- A host that does not implement these operators (a pre-0134 host) will reject an
unknown type at schema validation — the additive enum is opt-in per host, and the capability is discoverable by the conformance scenario below (no new capability flag; the operator set is part of the always-advertised workflow-definition contract, so a host claiming v1 workflow support that rejects a truthy edge is simply not yet on 0134).
Examples
Positive — an approval-gate branch (both edges from the gate node):
{ "from": "approve", "to": "apply", "condition": { "type": "truthy", "left": "approved" } }
{ "from": "approve", "to": "reject", "condition": { "type": "falsy", "left": "approved" } }
Negative — fails validation (missing left):
{ "from": "approve", "to": "apply", "condition": { "type": "truthy" } }
Compatibility
Additive. New optional enum members on an existing field. No existing EdgeCondition (which uses one of the five prior operators) changes meaning or validity. A workflow/chain that does not use truthy/falsy is byte-identical and replays identically. Lands in v1.x. A host adopts it by extending its condition mapper; until it does, a truthy edge fails that host's schema validation (honest — the host does not yet honor the operator, so it must not accept it).
Conformance
A new scenario edge-condition-truthy-falsy:
- §A (always-on, corpus):
workflow-definition.schema.json§EdgeConditiontype
enum contains truthy and falsy; the manifest schema's inlined EdgeCondition matches; the spec (workflow-definition.md) documents the no-right semantics + the required-left rule.
- §B (capability-gated on the host actually expanding/evaluating conditions): a
workflow-chain pack whose fragment carries a truthy and a falsy edge off one approval-gate node instantiates through from-chain and the expanded WorkflowDefinition's edges carry the mapped host-native truthy/falsy conditions (the reference host's edgeConditionMapping maps truthy → truthy, falsy → falsy); a truthy edge missing left is refused chain_edge_condition_invalid.
Reference-impl-tier witness (the RFC 0132/0133 precedent): the openwop-app tier-1 reference host is the witness. The RFC moves Draft → Active on the schema/spec/ conformance landing, and Active → Accepted once the reference host maps the operators and the §B scenario passes non-vacuously under OPENWOP_REQUIRE_BEHAVIOR=true.
Security
None. Edge conditions carry no credentials and route control flow only; truthy/falsy add no evaluation power beyond the existing operators (they are a strict subset of what expression could already express on hosts that implement it). No SSRF/egress/secret surface. The required-left fail-closed rule preserves the existing "never a silently dead edge" invariant.
Unresolved questions
1. right on truthy/falsy — ignore vs reject? Resolved: ignore (forward-compat; a future operator variant could give right meaning). A host MAY warn. 2. A dedicated capability flag? Resolved: no. The operator set is part of the always-present workflow-definition contract (not an optional family); adoption is discoverable by the conformance scenario, matching how the other five operators are handled (no per-operator flag).