Policy configuration guide
Arbitex’s Policy Engine evaluates rules against every request and response before they are forwarded to or returned from AI providers. Policies are organized into policy packs (collections of rules), chains (ordered sequences of packs), and combining algorithms (how multiple rule matches are resolved). This guide explains how these components work together and provides practical configuration patterns for common governance scenarios.
For the full rule condition reference, see Policy rule reference. For the admin UI walkthrough, see Policy Engine admin guide.
Evaluation model
Section titled “Evaluation model”The Policy Engine follows a Palo Alto firewall model with two evaluation passes per request:
- Input pass — evaluated before the prompt is forwarded to the AI provider
- Output pass — evaluated before the response is returned to the user
For each pass, the engine evaluates chains in this order:
- User chain (
scope="user") — personal overrides assigned to the individual user - Org chain (
scope="org") — the organization’s primary policy chain
Within each chain, packs are evaluated in sequence order. Within each pack, rules are evaluated in sequence order. Evaluation stops when a terminal action is matched (in first_applicable mode) or when all packs have been processed (in deny_overrides mode).
Terminal vs non-terminal actions
Section titled “Terminal vs non-terminal actions”| Action | Terminal? | Effect |
|---|---|---|
ALLOW | Yes | Permit the request. Stop evaluation. |
BLOCK | Yes | Reject the request with a block message. Stop evaluation. |
CANCEL | Yes | Cancel the request silently. Stop evaluation. |
ROUTE_TO | Yes | Route to a specified model or tier. Stop evaluation. |
PROMPT | Yes | Present a governance challenge to the user (interactive only). Stop evaluation. |
ALLOW_WITH_OVERRIDE | Yes | Permit with an override acknowledgement. Stop evaluation. |
REDACT | No | Apply redaction and continue evaluation to the next rule. |
REDACT is the only non-terminal action. Multiple REDACT rules can match and accumulate across a single evaluation pass — each adds its replacement to the list of accumulated redactions. Terminal actions carry the accumulated redactions with them.
Default behavior: If no rule matches anywhere, the request is allowed (default ALLOW).
Policy packs
Section titled “Policy packs”A policy pack is a named, ordered collection of rules with a shared scope. Rules within a pack are evaluated in ascending sequence order. A pack can be included in multiple chains.
Pack structure
Section titled “Pack structure”Each rule in a pack has:
- Conditions (all of which must be true for the rule to match — AND logic)
- Action (what to do when the rule matches)
- Applies to (
input,output, orboth)
Example: a DLP pack with two rules
Pack: "PII Detection" Rule 1 (sequence 1): entity_types=[CREDIT_CARD, SSN], entity_confidence_min=0.85 → BLOCK Rule 2 (sequence 2): entity_types=[EMAIL_ADDRESS], entity_confidence_min=0.75 → REDACT "[EMAIL]"In this pack, a request containing a credit card number with ≥85% confidence is blocked. A request containing an email address with ≥75% confidence (but no credit card/SSN) has the email redacted and evaluation continues.
Combining algorithms
Section titled “Combining algorithms”Each chain specifies a combining algorithm that controls what happens when multiple rules match across packs in the chain.
first_applicable (default)
Section titled “first_applicable (default)”The first terminal action matched across any pack in the chain wins. Evaluation stops immediately on the first terminal match.
Chain (first_applicable): Pack 1: Rule A (ALLOW_WITH_OVERRIDE, user in "finance-team") Pack 2: Rule B (BLOCK, entity SSN detected)If Rule A matches (user is in finance-team), the decision is ALLOW_WITH_OVERRIDE and Pack 2 is never evaluated. If Rule A does not match, Pack 2 is evaluated. If Rule B matches, the decision is BLOCK.
This mirrors how firewall ACLs work: pack order matters. Place more specific allowances before general blocks.
deny_overrides
Section titled “deny_overrides”All packs are evaluated even after a terminal match, unless the match is BLOCK or CANCEL. If any pack produces a BLOCK or CANCEL, that decision wins regardless of what other packs decided. If no deny is found, the most severe non-deny decision wins.
Severity ordering (highest to lowest):
BLOCK > CANCEL > REDACT > ROUTE_TO > PROMPT > ALLOW
Chain (deny_overrides): Pack 1: Rule A (ALLOW, no conditions — catch-all) Pack 2: Rule B (BLOCK, content_regex matches "confidential")Even though Rule A fires first (and would win under first_applicable), the deny_overrides algorithm continues evaluating Pack 2. If Rule B also matches, BLOCK wins.
Use deny_overrides when you have a compliance pack that must never be bypassed by an earlier allowance — for example, a regulatory BLOCK rule that must fire even if a user-level override pack would otherwise allow the request.
ROUTE_TO — model routing
Section titled “ROUTE_TO — model routing”ROUTE_TO redirects the request to a different model or model tier when a rule matches. Use it to implement cost-based routing (downgrade complex requests to a cheaper model), capability-based routing (send code generation to a code-specialized model), or risk-based routing (send high-risk-score requests to a restricted model).
Route to a specific model
Section titled “Route to a specific model”{ "type": "ROUTE_TO", "route_to_model": "claude-haiku-4-5-20251001"}The route_to_model value is the exact model identifier as configured in your provider settings.
Route to a tier
Section titled “Route to a tier”{ "type": "ROUTE_TO", "route_to_tier": "haiku"}Valid tier values: haiku, sonnet, opus. The engine resolves the tier to the configured model for that tier at evaluation time.
ROUTE_TO example: intent-based downgrade
Section titled “ROUTE_TO example: intent-based downgrade”Route simple requests to a lower-cost model:
Pack: "Cost Optimization" Rule 1: intent_complexity=simple → ROUTE_TO tier=haiku Rule 2: intent_complexity=complex → ROUTE_TO tier=opus (no rule for medium → falls through to default model)ROUTE_TO example: provider isolation
Section titled “ROUTE_TO example: provider isolation”Route requests for specific providers to a restricted model when the user risk score is elevated:
Pack: "Risk-Based Routing" Rule: user_risk_score_min=0.7, providers=[openai] → ROUTE_TO model=gpt-4o-miniUser chain vs org chain
Section titled “User chain vs org chain”Org chain
Section titled “Org chain”The org chain (scope="org", scope_id=tenant_id) is the primary policy chain for your organization. All users in the org are subject to it. Rules in the org chain can use user_groups conditions to target specific groups without requiring separate per-user chains.
Org chain (first_applicable): Pack: "Compliance Baseline" Rule 1: entity_types=[SSN, CREDIT_CARD] → BLOCK (applies to all users) Rule 2: user_groups=["finance"], entity_types=[BANK_ACCOUNT] → ALLOW (finance team exempt) Rule 3: entity_types=[BANK_ACCOUNT] → BLOCK (all other users)The user_groups condition uses OR logic: the user must be a member of any of the listed groups for the condition to match.
User chain
Section titled “User chain”The user chain (scope="user", scope_id=user_id) contains overrides for a specific user. It is evaluated first — before the org chain. A terminal action in the user chain prevents the org chain from being evaluated at all.
Use user chains sparingly. The recommended pattern is to express group-level overrides via user_groups conditions in the org chain rather than creating individual user chains.
Practical configuration patterns
Section titled “Practical configuration patterns”Pattern 1: DLP baseline with group override
Section titled “Pattern 1: DLP baseline with group override”Block PII for all users, but allow the security-audit group to see masked output:
Org chain (first_applicable): Pack: "Security Audit Override" (sequence 1) Rule: user_groups=["security-audit"] → ALLOW_WITH_OVERRIDE Pack: "DLP Baseline" (sequence 2) Rule: entity_types=[SSN, CREDIT_CARD, PASSPORT] → BLOCKWhen a security-audit member sends a request, Pack 1 matches and returns ALLOW_WITH_OVERRIDE — the DLP Baseline is never reached. All other users fall through to the DLP Baseline.
Pattern 2: Cost-tiered routing with compliance block
Section titled “Pattern 2: Cost-tiered routing with compliance block”Implement cost optimization routing but ensure compliance blocks always fire:
Org chain (deny_overrides): Pack: "Cost Routing" (sequence 1) Rule: intent_complexity=simple → ROUTE_TO tier=haiku Rule: intent_complexity=complex → ROUTE_TO tier=opus Pack: "Compliance Block" (sequence 2) Rule: content_regex="export controlled|ITAR|EAR" → BLOCKWith deny_overrides, the compliance block in Pack 2 fires even if Pack 1 has already produced a routing decision.
Pattern 3: Channel-gated PROMPT governance
Section titled “Pattern 3: Channel-gated PROMPT governance”Present a governance challenge only for interactive users, not API callers:
Org chain (first_applicable): Pack: "Interactive Governance" Rule: channel=["interactive"], content_regex="generate.*code" → PROMPT prompt_message="Code generation requires confirmation. Proceed?"API callers (channel="api") do not match the channel condition and pass through without a challenge.
Pattern 4: Risk score escalation
Section titled “Pattern 4: Risk score escalation”Route high-risk users to a restricted model regardless of their request:
Org chain (first_applicable): Pack: "Risk Escalation" Rule: user_risk_score_min=0.8 → ROUTE_TO model=gpt-4o-mini Pack: "Default Policy" Rule: (no conditions — catch-all) → ALLOWRule condition reference summary
Section titled “Rule condition reference summary”| Condition | Type | Match logic |
|---|---|---|
applies_to | input, output, both | Must match request direction |
user_groups | list of group names/IDs | User must be in ANY listed group |
entity_types | list of entity type strings | ANY detected entity must be in the list with ≥ entity_confidence_min |
entity_confidence_min | float (0.0–1.0) | Minimum confidence for entity match |
content_regex | regex string | Pattern must match anywhere in prompt_text |
providers | list of provider names | provider must be in the list |
models | list of model identifiers | model must be in the list |
user_risk_score_min | float (0.0–1.0) | user_risk_score must be ≥ this value |
intent_complexity | simple, medium, complex | intent_complexity must equal this value |
channel | list: interactive, api | channel must be in the list |
All specified conditions must be satisfied (AND logic). A rule with no conditions is a catch-all that matches every request.
Common pitfalls
Section titled “Common pitfalls”Pack order in first_applicable determines which rules fire. If a broad allowance rule (e.g., catch-all ALLOW) is in Pack 1 and a block rule is in Pack 2, the block will never be reached. Arrange packs from most-specific to least-specific.
REDACT is non-terminal — it does not stop evaluation. If you want redaction without also allowing the request through, follow the REDACT rule with a subsequent rule that produces a terminal action.
User chains take precedence over org chains. A user with a personal ALLOW chain entry can bypass org-level blocks under first_applicable mode. Use deny_overrides on the org chain if compliance blocks must be absolute.
intent_complexity is populated by the intake pipeline after DLP scanning. Rules that reference intent_complexity will never match on the first pass if the pipeline has not yet computed the value. Check that the intake pipeline version supports Epic J5 complexity scoring.
See also
Section titled “See also”- Policy Engine overview — Architecture, evaluation model, and action types
- Policy rule reference — Complete condition and action field documentation
- Policy Engine admin guide — UI: pack editor, chain editor, rule simulator
- Policy Engine testing — Simulate rule evaluation against test inputs
- ALLOW_WITH_OVERRIDE guide — Governance challenge workflow for override scenarios
- PROMPT governance guide — Interactive challenge configuration for browser callers