on_complete
branch conditions with CEL. CEL is strongly typed and
non-Turing-complete. For the conceptual intro see Expressions.
Context variables
Declared entity fields are always readable at a type-valid value; an undeclared field
reference is a contract error caught at boot.
Where each variable is available
The five condition sites run at different points in the handler pipeline, soaccumulated and fan_out are not usable everywhere. Referencing one where it is not
available is a boot error.
accumulated is only readable after accumulation completes (on_complete, filter), so it is
absent in guard (runs before accumulation) and in rules (an alternative to on_complete).
fan_out.count is populated after the fan-out step and is read only in
data_accumulation.expression; in on_complete, read the entity field you wrote it to instead.
Operators
- Comparison:
==,!=,<,<=,>,>= - Logical:
&&,||,! - Arithmetic:
+,-,*,/ - Membership:
in,contains - String:
startsWith,endsWith,matches - List:
size,exists,all,filter,map
The prefix rule
Every condition carries a context prefix:payload., entity., policy., accumulated.,
or fan_out.. A bare identifier is a dialect violation. See
Dialect rules.
Examples
Cross-entity count
query_entities(<field> <op> <value>).count returns how many flow-owned entities match a single
comparison, for use inside a condition. The operator is one of ==, !=, >=, <=, >, <,
and the value is a literal or a resolved reference (payload.*, event.*):
request_id. The predicate is a single comparison, not a compound
expression, and only .count is exposed.
Presence
has(entity.field) is true for declared entity fields (redundant under universal presence,
useful for dynamic maps). Comparing against null works; timestamp and uuid fields read
null when unwritten, while most others read their non-null type default.
