Shadow Mode
Rule Shadow Mode¶
Test new rules against live production traffic without affecting any decisions. Shadow rules 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 rule that blocks all trades over $100K, run it in shadow mode for 24 hours. The Rule 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 rule with "mode": "shadow". It's active but observe-only. |
| 2. Evaluate | Every /enforce/intercept call evaluates shadow rules in a separate pass after the real decision. |
| 3. Record | Shadow results are stored in shadow_results on the decision record: what the shadow rule would have decided, which rules triggered, whether the outcome would differ. |
| 4. Report | The /enforce/shadow/report endpoint and the Rule 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 Rule¶
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 rules 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 rule 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 rule 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:
- Rules tab, every rule shows a LIVE or SHADOW badge with a one-click mode toggle.
- Rule Simulation tab, impact stats (would-block, would-escalate, outcome changes), per-policy breakdown, live vs shadow comparison table, and a "Promote to Live" button.