Policy Governance
Production policy changes never go straight to live. Adjudon's Policy Engine enforces a multi-stakeholder workflow that mirrors the role-separation auditors expect under EU AI Act Art. 14, BaFin MaRisk AT 4.3.1, and DORA Art. 8(4).
The 3-role separation
Every promotion to live (or to a canary % above 0) requires three distinct humans on Governance and Enterprise tiers:
| Role | What they do | Gate |
|---|---|---|
| Author | Drafts the policy, runs dry-runs, attaches regression tests | Submits the approval request |
| Reviewer | Inspects the proposed change against business intent + risk register | Approves or rejects |
| Enforcer | Confirms operational readiness and authorizes the production cutover | Promotes to live |
Backend enforcement: policyApprovalService rejects the action with one of two error codes — AUTHOR_REVIEWER_SAME_PERSON (when submittedBy === reviewedBy) or AUTHOR_ENFORCER_SAME_PERSON (when submittedBy === enforcedBy). Both return HTTP 403.
Workflow states
draft
↓ submit
pending_review
↓ reviewer-approve ↓ reviewer-reject
pending_enforce rejected
↓ enforcer-promote ↓ enforcer-reject
approved (live) rejected
The author can also withdraw a request before either reviewer or enforcer acts.
Break-glass
When the situation requires immediate enforcement and a normal approval flow is not feasible, an admin or owner can invoke break-glass on a pending request. The action:
- Bypasses the 3-role separation (single human authorizes the cutover).
- Requires a typed-confirm phrase (
BREAK GLASS) plus a justification of at least 50 characters (enforced bypolicyApprovalService.breakGlassPromotewith error codeBREAK_GLASS_JUSTIFICATION_REQUIRED). - Records
viaBreakGlass: true,breakGlassJustification: <text>, the actor's identity, and the timestamp on the immutable hash chain. - Surfaces the action in the Auditor View with a critical-severity badge.
- Is gated by
requireRole('owner', 'admin')— never available toviewerorauditor.
Audit reviewers (PwC, BaFin examiners, EU notified bodies) can filter the auditor view to viaBreakGlass: true to inspect every break-glass override and its accompanying justification.
Canary deployment
Each policy version may be promoted to a fractional rollout instead of going straight to 100%. The canary cohort is selected deterministically by SHA-256 bucketing (shouldRouteToCanary({ traceId, policyId, canaryPercentage })). Once BOTH the canary AND the production-baseline cohort have each accumulated ≥30 samples in the current window, the SPRT decision banner (Wald 1947 sequential probability ratio test) makes one of three calls (below the threshold the decision is inconclusive):
| Decision | Meaning | Action |
|---|---|---|
accept | Canary fire-rate is statistically equivalent to production within tolerance | Promote to 100% |
reject | Canary fire-rate is statistically worse than production | Auto-revert recommended |
continue | Insufficient evidence | Wait for more samples |
The dashboard's <CanaryPercentageSlider> component refreshes the SPRT result every 30 seconds. Operators can adjust the rollout % at any time; the decision gets recomputed against the new sample window.
The auditor role
The auditor role is read-only by design. An auditor can:
- View every live policy and its history (
GET /api/policies/audit/auditor-view) - Inspect recent transcripts (last 50 policy fires) including break-glass flags
- Inspect recent approvals (last 20) including state transitions, reviewer/enforcer identities, and timestamps
- Inspect recent effectiveness snapshots (precision/recall/F1/FPR)
- Pull the immutable PolicyVersion chain count
An auditor cannot:
- Create, edit, approve, reject, or delete policies
- Initiate break-glass
- Change canary rollout percentages
- Generate or download the insurance attestation feed
- Modify SSO, billing, or any organization-level setting
This separation ensures that an external auditor on-site can verify enforcement without holding any production-changing capability.
Customer-controlled audit-trail export
For court-admissible evidence (per eIDAS Art. 41(2) + §371a Abs. 3 ZPO), the customer-portable bundle export wraps the relevant transcripts, the policy version chain, and the qualified electronic timestamp. Download via Policy Engine → Export bundle. The bundle is dual-signed with Sigstore Cosign (transparency log) and D-Trust QTSP (qualified electronic signature). See Policy Portability for the full schema.