Policy Shadow Mode
Policy Shadow Mode¶
Test new policies against live production traffic without affecting any decisions. Shadow policies are evaluated on every incoming action but their verdicts are logged separately, the actual authorisation decision is never changed.
Info
Use case: Before deploying a policy that blocks all trades over $100K, run it in shadow mode for 24 hours. The Policy Simulation dashboard shows exactly which actions would have been blocked, which agents would be affected, and whether any outcomes would change, all with zero production risk.
How It Works¶
| Step | What Happens |
|---|---|
| 1. Create | Create a policy with "mode": "shadow". It's active but observe-only. |
| 2. Evaluate | Every /enforce/intercept call evaluates shadow policies in a separate pass after the real decision. |
| 3. Record | Shadow results are stored in shadow_results on the decision record: what the shadow policy would have decided, which policies triggered, whether the outcome would differ. |
| 4. Report | The /enforce/shadow/report endpoint and the Policy Simulation dashboard aggregate the impact. |
| 5. Promote | When satisfied, promote to live with a single API call or one click in the dashboard. |
Create a Shadow Policy¶
resp = requests.post(f"{BASE}/enforce/policies", headers=HEADERS, json={
"name": "Block Trades Over 500K",
"policy_type": "threshold",
"action_types": ["execute_trade"],
"decision": "block",
"priority": 200,
"trust_threshold": 95,
"mode": "shadow" # ← observe-only
})
# resp.json()["policy"]["mode"] → "shadow"
Shadow Results on Decisions¶
After sending traffic, each decision record includes a shadow_results field:
{
"decision": "allow",
"shadow_results": {
"shadow_decision": "block",
"would_have_changed": true,
"live_decision": "allow",
"triggered": [
{
"policy_id": "abc123",
"name": "Block Trades Over 500K",
"decision": "block",
"reason": "Agent trust 50.2 < threshold 95"
}
],
"reasoning": "Agent trust 50.2 < threshold 95"
}
}
GET /v1/enforce/shadow/report¶
Aggregate impact report for all active shadow policies over a time window.
{
"shadow_policies": 2,
"hours": 24,
"report": {
"total_evaluated": 847,
"would_block": 23,
"would_escalate": 8,
"would_change_outcome": 15,
"affected_agents": ["agent_abc", "agent_def"],
"per_policy": [
{
"policy_id": "abc123",
"name": "Block Trades Over 500K",
"would_block": 23,
"would_escalate": 0,
"total_triggered": 23
}
]
}
}
POST /v1/enforce/shadow/{policy_id}/promote¶
Promote a shadow policy to live mode, it will start enforcing immediately.
resp = requests.post(
f"{BASE}/enforce/shadow/{policy_id}/promote",
headers=HEADERS
)
# resp.json()["policy"]["mode"] → "live"
Toggle Mode via Update¶
You can also switch any policy between live and shadow using the standard update endpoint:
requests.put(f"{BASE}/enforce/policies/{policy_id}",
headers=HEADERS,
json={"mode": "shadow"} # or "live"
)
Dashboard¶
The Authorisation Layer dashboard includes:
- Policies tab, every policy shows a LIVE or SHADOW badge with a one-click mode toggle.
- Policy Simulation tab, impact stats (would-block, would-escalate, outcome changes), per-policy breakdown, live vs shadow comparison table, and a "Promote to Live" button.