The closed, portable boolean predicate algebra carried by
deterministic_predicate evaluation assertions (base §6.6).
Grammar (closed world — every node is an object with op plus exactly the
operator's operand members):
{"op": "and" | "or", "args": [predicate, …]} # n-ary, ≥ 1
{"op": "not", "args": [predicate]}
{"op": "eq" | "ne" | "lt" | "lte" | "gt" | "gte",
"path": [segment, …], "value": json}
{"op": "in", "path": [segment, …], "values": [json, …]}
{"op": "present" | "absent", "path": [segment, …]}validate/2 checks shape against the declared port names: path[0] must
name a declared port (:predicate_path_unresolved), the node count is
ceilinged at 256 (:predicate_nodes_exceeded), unknown
operators deny :predicate_op_unknown, and operand-shape failures use the
package's class vocabulary (:unknown_member, :missing_required_field,
:invalid_type, :invalid_cardinality). Check order inside one node is
pinned so two implementations pick the same reason: op presence → op
value/known → unknown member → missing operand → operand type/cardinality →
path[0] → node ceiling (nodes are counted depth-first, on entry).
evaluate/2 validates first, then applies the predicate to a map of port
name → tagged value. Path addressing: segment 0 is the port-name map key;
later segments address object members by name and array elements by
CANONICAL decimal index string ("0", "17" — no leading zeros). For
present/absent an unresolvable path is a defined outcome (present →
false, absent → true); for every value operator it is
{:error, :predicate_path_unresolved}. eq/ne/in use Schema.equal?/2
(mathematical-value numbers, order-blind objects); lt/lte/gt/gte
require both operands numbers (mathematical value) or both strings (byte
order) — any other combination is :predicate_path_unresolved (the path
did not resolve to a value the operator can order). The n-ary and/or
folds are ERROR-DOMINANT: any errored operand makes the fold an error
regardless of the other operands' booleans, which is what makes the verdict
independent of operand order (a value short-circuit would not).
Predicates are declarative data — evaluation never authorizes anything.
Summary
Functions
Apply predicate to ports (port name → tagged value). Validates first,
so a shape-invalid predicate denies instead of raising. Returns
{:ok, boolean()} or the first error encountered under the pinned orders.
Validate a predicate's shape against port_names. Total and never-raising
on any input: malformed tagged shapes deny :invalid_type.
Types
Functions
@spec evaluate(AgentBlueprintProtocol.Json.value(), %{ optional(binary()) => AgentBlueprintProtocol.Json.value() }) :: {:ok, boolean()} | {:error, reason()}
Apply predicate to ports (port name → tagged value). Validates first,
so a shape-invalid predicate denies instead of raising. Returns
{:ok, boolean()} or the first error encountered under the pinned orders.
@spec validate(AgentBlueprintProtocol.Json.value(), [binary()] | :any_root) :: :ok | {:error, reason()}
Validate a predicate's shape against port_names. Total and never-raising
on any input: malformed tagged shapes deny :invalid_type.