Iterate Policy Safely
Policy Iterate is an audit-driven policy rollout loop under examples/policyIterate. Use it when a real request is denied and you want to test a candidate policy change against the exact redaction-safe audit input — and prove it does not change other decisions — before activation.
- Diagnose — a request is denied and you capture its audit
request_id. The audit explain endpoint reconstructs the deniedpolicy_inputalong with the diagnostics and determining policies. - Simulate — you edit the policy, stage a candidate policy-set version, and the example replays the denied input against it through the same OPA engine that serves live traffic.
- Regress — the example replays your expected-decision cases against the same candidate, so loosening a policy for one caller cannot silently change decisions for everyone else.
- Decide — activation is gated on evidence: the candidate allows the denied input, the rollout contract validates, simulation produced no warnings, and every regression case keeps its expected decision.
- Activate — with
ACTIVATE=trueand a clean verdict, the example activates the version and polls activation status until the STS runtime reports it loaded.
Run the iteration
Section titled “Run the iteration”cd examples/policyIterateCARACAL_API_URL=http://127.0.0.1:3000 \CARACAL_ADMIN_TOKEN=<admin-token> \CARACAL_ZONE_ID=<zone-id> \DENIED_REQUEST_ID=<denied-request-id> \POLICY_SET_ID=<policy-set-id> \CANDIDATE_VERSION_ID=<staged-version-id> \REGRESSION_FILE=./regressions.json \npm run iterateThe run is a dry run by default: it narrates each phase on stderr, prints a JSON report on stdout, and exits 0 only when the verdict is clean. Re-run with ACTIVATE=true to roll out the version and wait for propagation.
REGRESSION_FILE is optional and points to a JSON array of { name, expect, input } cases — see regressions.example.json in the example directory for the format.
Claims note
Section titled “Claims note”Actor and subject claims are not written to audit, so reconstructed input does not contain them. For a claim-dependent denial, add the relevant context.actor_claims to a regression case built from the printed policyInput and iterate with that case instead.
cd examples/policyIteratenpm testThe tests inject the Admin API transport and do not call a live Caracal stack.
Next step
Section titled “Next step”Continue to Launch Research Agent to see runtime credential injection for a plain CLI agent.

