§ DOCUMENTATION
Policy Chaining
Order policies with explicit prerequisites. Skip expensive checks when a cheaper upstream policy already decided. Escalate only when the first line of defence triggered.
Why chain policies
Every enforcement request runs every applicable policy. Chaining lets you express dependencies without changing that default:
- Run an expensive validator only if a cheap upstream check passed.
- Escalate to human approval only if a PII or injection policy already triggered.
- Guarantee ordering — e.g. always run your sanitiser before your classifier.
Fields
| Field | Type | Meaning |
|---|---|---|
prerequisites | UUID[] | Other policy IDs that must be evaluated first. Max 20. Default []. |
evaluationOrder | int 0–100000 | Stable tiebreaker when prerequisites do not fully order policies. Default 100. |
chainTrigger | enum | How the chain decides whether to evaluate this policy. See the triggers table below. |
Triggers
| Trigger | Evaluate this policy when… |
|---|---|
all_passed | Every prerequisite returned no violation. Default — use when the chain is an expensive refinement of cheap upstream checks. |
any_violated | At least one prerequisite violated. Use for escalation — e.g. create an approval request only if something already triggered. |
always | Prerequisites only influence ordering. Use when you need deterministic sequencing but the chain should always run. |
Example chain
# Policy A — cheap, fast, always runs{ "name": "pii-guard", "policyType": "pii_access", ... } # Policy B — only runs if A passed{ "name": "finance-cost-cap", "policyType": "expression", "ruleDefinition": { "expression": "cost > 1.0" }, "prerequisites": ["<policy-A-id>"], "evaluationOrder": 200, "chainTrigger": "all_passed"} # Policy C — escalates if either A or B violated{ "name": "security-review", "policyType": "custom_validator", "ruleDefinition": { "validatorId": "..." }, "prerequisites": ["<policy-A-id>", "<policy-B-id>"], "evaluationOrder": 300, "chainTrigger": "any_violated"}Cycle detection
Cycles are rejected at write time, inside the same transaction as the insert or update. A DFS walks every prerequisite chain before COMMIT. If a cycle is detected the request fails with HTTP 400 and a breadcrumb of the offending path:
HTTP/1.1 400 Bad RequestContent-Type: application/json { "error": { "code": "VALIDATION_ERROR", "message": "Policy prerequisites would introduce a cycle", "fields": { "prerequisites": "cycle: A → B → C → A" } }}Because cycles never reach the database, runtime evaluation never has to worry about them. The only failure mode at enforcement time is a missing prerequisite — e.g. the upstream policy was deleted or disabled. In that case the dependent policy is recorded as skipped (fail-closed for the chain, not for the request) and an audit event is emitted.
Observability
policy.chain.skipped— emitted when a trigger condition is not met and the policy is skipped.policy.chain.cycle_detected— emitted when a cycle attempt is rejected at write time.- Trace decisions include a
skippedByChainbreakdown so chains are reconstructible after the fact.
Inspecting a chain from the CLI
Use execlave policies chain to see the full evaluation order, or execlave policies chain --id <policy-id> to list a specific policy's prerequisites and its downstream dependents. Missing prerequisites are flagged in red so drift is caught before it shows up as a silent skip at runtime.
$ execlave policies chain# ORDER NAME TYPE TRIGGER PREREQS# 10 pii-guard pii_access all_passed —# 200 finance-cost-cap expression all_passed 1# 300 security-review custom_validator any_violated 2