Reading a policy
delta runs the compiler, so this is written for reviewing a policy rather than for building one locally. The authority for everything here is the language reference, which is synced from the compiler itself; this page is the orientation.
The shape
Section titled “The shape”A policy is a header and two blocks:
name cart_guard
parameters { max_total_usd_cents: int max_item_usd_cents: int}
requires { sum(item.price_usd_cents * item.quantity for item in evidence.cart) + evidence.shipping_usd_cents <= parameters.max_total_usd_cents;
all(item.price_usd_cents <= parameters.max_item_usd_cents for item in evidence.cart);}name <identifier>comes first.- At most one
parametersblock: the fields the user’s intent supplies values for. An emptyparameters {}is the same as omitting it. - Exactly one, non-empty
requiresblock: the constraints.
There is no evidence block. Evidence fields are referenced directly as
evidence.<field> and are typed by the evidence schema supplied at compile time,
not declared in the policy.
Two sides of every constraint
Section titled “Two sides of every constraint”This is the distinction to hold on to when reviewing:
| Reference | Where the value comes from |
|---|---|
parameters.max_total_usd_cents | the user’s intent — the limits they authorised |
evidence.shipping_usd_cents | the evidence extracted from the agent’s proposal |
A policy is reusable precisely because the limits are parameters: one policy
serves many intents at different values. When reviewing, read parameters.* as
“whatever the user chose” and evidence.* as “whatever was true of the proposal”.
Scalars are bool, int, string, date. Collections are List<T> and
Set<T> — a Set holds int, string or date; a List may also hold
Object, but only for evidence produced at runtime, never as a declared field
type. Element types cannot themselves be collections.
A parameter field may be prefixed optional:
parameters { allowed_brands: optional Set<string>}Constraints
Section titled “Constraints”Every constraint in requires must hold, and each ends with ;. A constraint
prefixed optional: is skipped when the optional parameter it reads is absent —
which is how “only check the colour if the user named colours” is expressed:
requires { optional: evidence.color in parameters.color;}Things worth recognising when you read one:
- Chained comparison —
date(2026-01-01) <= evidence.delivery <= date(2026-12-31)reads as one range check, not two. - Reducers over collections —
sum(...),all(...),count_distinct(...)with afor <var> in evidence.<collection>clause, and an optional trailingiffilter:all(item.organic for item in evidence.cart if item.category under "Food > Vegetables"). - Category paths —
under "Food > Vegetables"tests taxonomy membership rather than string equality. - Set membership —
evidence.audience in {"men", "women", "unisex"}against a literal, orin parameters.acceptable_categoriesagainst a parameter.
What a failure tells you
Section titled “What a failure tells you”A failed evaluation reports which constraint failed by index, with the
constraint re-printed and its own reason — see constraint_failures in the
Orchestrator API. The index is the constraint’s position in
requires, counting from 0, which is why the order of constraints in a policy is
worth keeping stable.
Next: worked policies for complete examples, and value encoding for how parameter values are written on the wire.