Skip to content

Policy Engine — Deep Dive

The Arbitex Policy Engine is the enforcement core of the platform. Every AI request — whether routed through the cloud gateway or an on-premises Outpost — passes through the Policy Engine before the prompt reaches a model and again when the model response is returned. This document is the comprehensive technical reference for the Policy Engine. For a user-focused overview, see Policy Engine — User Guide. For admin configuration steps, see Policy Engine admin guide.

Source: backend/app/services/policy_engine.py


The Policy Engine uses a Palo Alto firewall-style rule model: rules are organized into packs, packs are organized into chains, and evaluation proceeds sequentially through the chain until a terminal action is reached (in first_applicable mode) or all rules have been evaluated (in deny_overrides mode).

Chain
└─ Pack 1
│ └─ Rule 1 (sequence: 10)
│ └─ Rule 2 (sequence: 20)
└─ Pack 2
└─ Rule 3 (sequence: 10)
└─ Rule 4 (sequence: 20)

An organization has exactly one org chain (the primary enforcement chain). Users may optionally have a user chain (personal overrides). The two chains interact in a defined evaluation order (see Chain evaluation order).

If no rule matches anywhere in the chain, the default action is ALLOW.


The combining algorithm controls how the Policy Engine responds to conflicting rule outcomes within a chain.

The engine evaluates rules in sequence order and stops at the first matching rule. The action of that rule is the final enforcement decision.

This is the default algorithm and the most commonly used. It mirrors how stateless firewalls process ACLs: rules are ordered by specificity or priority, and the most-specific matching rule wins.

Use when: You want predictable, ordered evaluation where rule order is explicit governance intent.

The engine evaluates all rules regardless of matches. If any matching rule produces a block action, that action overrides any allow actions from other matching rules. Non-blocking actions accumulate (e.g., multiple log actions all fire).

Use when: You have multiple packs that might independently match and you want a conservative posture — any block anywhere kills the request.

{
"combining_algorithm": "deny_overrides"
}

Set the algorithm on the chain object via the admin API. Org chains default to first_applicable.


The Policy Engine supports 10 condition types. All conditions are evaluated against the request context at the time of evaluation. Multiple conditions within a single rule are combined with AND logic — all must match for the rule to fire.

Matches when the request text (prompt or response, depending on direction) satisfies a regular expression.

{
"conditions": {
"content_regex": "\\b(?:sk-[a-zA-Z0-9]{48})\\b"
}
}

The value is a RE2-compatible regular expression applied via re.search(). Backtrack-unsafe patterns are rejected at rule creation time.

Matches when the DLP pipeline detects one or more entity types in the request or response. Any detected entity whose type appears in the list (with sufficient confidence) causes the condition to match.

{
"conditions": {
"entity_types": ["pii_name", "org_name", "financial_amount"],
"entity_confidence_min": 0.75
}
}

entity_confidence_min sets the minimum confidence threshold (0.0–1.0) for a detection to count. Defaults to 0.0 (all detections count). Entity type labels are the Arbitex canonical types produced by the DLP pipeline — spaCy NER produces pii_name, org_name, location, financial_amount, date. See DLP Pipeline Configuration for the full label taxonomy.

Matches when the requesting user belongs to at least one of the listed groups. Groups are SCIM-synced or directory-provisioned group names or IDs.

{
"conditions": {
"user_groups": ["compliance-officers", "legal-team"]
}
}

The user must be a member of any (not all) of the listed groups. Changes to group membership take effect immediately on the next request.

Matches when the request targets one of the listed AI provider identifiers.

{
"conditions": {
"providers": ["openai", "anthropic"]
}
}

Matches when the request targets one of the listed model identifiers.

{
"conditions": {
"models": ["gpt-4o", "gpt-4o-mini"]
}
}

Matches based on the model’s registered risk tier in the Model Registry. The condition accepts a list of tier values and checks whether the request model’s tier is a member of that list.

{
"conditions": {
"model_risk_tier": ["critical", "high"]
}
}

The tier for the (model, provider) pair is looked up from the model registry before evaluation. A model with no registry entry has its tier treated as "unclassified" — it will not match any explicit tier in the list.

Matches when the requesting user’s risk score (from CredInt/GeoIP enrichment) is at or above the specified threshold.

{
"conditions": {
"user_risk_score_min": 0.7
}
}

Risk scores range from 0.0 to 1.0. Higher values indicate greater risk.

Matches when the request’s computed intent complexity matches the specified value. Complexity is computed by the intake pipeline before policy evaluation.

{
"conditions": {
"intent_complexity": "complex"
}
}

Valid values: "simple", "medium", "complex". If complexity has not been computed for the request, the condition does not match.

Matches when the request channel is one of the listed values. Useful for applying different governance to browser-based interactive users versus programmatic API callers.

{
"conditions": {
"channel": ["interactive"]
}
}

Valid values: "interactive" (browser/SSE callers), "api" (programmatic API callers).

Matches when the DLP scan classifies content into one or more of the specified semantic categories. This condition operates at a higher level of abstraction than entity_types — rather than detecting individual named entity spans, it classifies the overall semantic domain and data type of the content.

{
"conditions": {
"content_categories": ["financial.credit-cards", "personal.national-ids"],
"content_category_confidence_min": 0.8
}
}

content_category_confidence_min sets the minimum classifier confidence (0.0–1.0) required for a category match to count. Defaults to 0.5. Categories are expressed as {domain}.{subcategory} dot-notation strings.

The Policy Engine recognizes 8 top-level domains with 27 subcategories:

Domain Subcategories
financial credit-cards, bank-accounts, tax-ids, financial-statements
healthcare medical-records, prescriptions, insurance-claims
legal contracts, litigation, regulatory-filings
personal addresses, phone-numbers, emails, national-ids
corporate trade-secrets, m-and-a, board-materials, earnings
technology source-code, api-keys, infrastructure-configs
data-engineering database-schemas, etl-pipelines, data-lineage
workplace-safety incident-reports, osha-filings, safety-audits

You may specify either a full domain.subcategory path (e.g., "financial.credit-cards") or just a domain root (e.g., "financial") to match any subcategory within that domain.

To block any content classified into the corporate domain regardless of subcategory:

{
"conditions": {
"content_categories": ["corporate"],
"content_category_confidence_min": 0.75
}
}

content_categories and entity_types can be combined in the same rule using AND logic. This creates a highly specific condition: the content must both be classified in a given category and contain a specific detected entity type:

{
"conditions": {
"content_categories": ["healthcare.medical-records"],
"entity_types": ["pii_name"],
"entity_confidence_min": 0.8,
"content_category_confidence_min": 0.85
},
"action": { "type": "BLOCK" }
}

This rule fires only when the content is classified as a medical record and a patient name is detected — providing more precise blocking than either condition alone.


When a rule matches, the engine applies the rule’s action. There are 7 action types. Action names are uppercase as they appear in the policy engine.

Permit the request or response to proceed. No modification is made.

{ "type": "ALLOW" }

In first_applicable mode, ALLOW is a terminal action — it stops evaluation and forwards the request. Use ALLOW rules to create explicit exemptions before more-restrictive rules in the chain.

Reject the request or response. The user receives a policy violation message.

{
"type": "BLOCK",
"message": "This request was blocked by your organization's AI use policy."
}

message is returned in the API error body. If omitted, the default block message is shown. The audit log records the matched rule, pack, and chain. BLOCK is a terminal action.

Cancel the request silently without forwarding it to the model. Unlike BLOCK, CANCEL does not return an explicit policy violation message to the caller. Used when the desired behavior is to drop the request without disclosing the blocking reason.

{ "type": "CANCEL" }

CANCEL is a terminal action. In deny_overrides mode, CANCEL is treated as a deny action alongside BLOCK.

Redact matched sensitive content before forwarding to the model (on input) or before returning to the user (on output). Requires an entity_types or content_regex condition to identify what to redact.

{
"type": "REDACT",
"redact_replacement": "[REDACTED]"
}

redact_replacement is the string substituted for each detected span. Defaults to [REDACTED].

REDACT is a non-terminal action — it accumulates redactions and evaluation continues. Multiple REDACT rules in a chain can each redact different entity types before a terminal action is reached. The original pre-redaction text is available in the audit log.

Route the request to a different model or model tier instead of the originally requested model.

{
"type": "ROUTE_TO",
"route_to_model": "gpt-4o-mini",
"route_to_tier": "sonnet"
}
Field Description
route_to_model Exact model identifier to route to (e.g., "gpt-4o-mini")
route_to_tier Tier name to route to (e.g., "haiku", "sonnet", "opus")

Either route_to_model or route_to_tier may be specified. Use route_to_tier to route to a tier without pinning an exact model. ROUTE_TO is a terminal action.

Present a governance challenge to the user before allowing the request to proceed. The user must acknowledge or respond to the challenge. Only applies to interactive (channel: "interactive") callers.

{
"type": "PROMPT",
"prompt_message": "This request may involve sensitive data. Please confirm you have authorization to share this information."
}

prompt_message is the challenge text shown to the user. PROMPT is a terminal action. Combine with a channel condition targeting ["interactive"] to avoid issuing challenges to API callers that cannot respond.

Allow the request while displaying an informational override message to the user. Used for soft governance — the request proceeds but the user is notified of the policy consideration.

{
"type": "ALLOW_WITH_OVERRIDE",
"override_message": "This request matched a sensitive data policy. It has been allowed under your elevated permissions, and this access has been logged."
}

override_message is shown to the user after the request completes. ALLOW_WITH_OVERRIDE is a terminal action.


Each request is evaluated against chains in the following order:

1. User chain (if present and enabled for the org)
2. Org chain

A user chain is a personal policy chain attached to a specific user. User chains allow personal overrides — for example, a user may have a stricter personal policy than the org default, or an admin may grant elevated permissions to a specific user.

User chains are evaluated first. In first_applicable mode (the default), if a user chain rule matches and produces a terminal action, org chain evaluation is skipped entirely.

User chains are created via POST /api/v1/admin/policy-chains with chain_type: "user" and a user_id.

The org chain is the primary enforcement chain applied to all requests in the organization. It is evaluated after the user chain (or on its own, if no user chain is configured or if the user chain did not match).

Every organization has exactly one org chain. It cannot be deleted, only modified.

Request: user "alice", model "gpt-4o", prompt contains credit card number
1. Alice's user chain (first_applicable):
- Rule 1: user_groups in [finance-power-users] → ALLOW ← alice is in this group
→ Terminal: ALLOW. Org chain skipped.
Request: user "bob", model "gpt-4o", prompt contains credit card number
1. Bob's user chain: (not configured)
2. Org chain (first_applicable):
- Rule 1: user_groups in [finance-power-users] → ALLOW ← bob is NOT in this group. No match.
- Rule 2: entity_types contains [financial_amount] → BLOCK
→ Terminal: BLOCK.

Every request that enters the Policy Engine follows a deterministic evaluation path. The flow below describes the full lifecycle from request arrival to enforcement decision and audit persistence.

┌─────────────────────────────────────────────────────────────────┐
│ Request arrives │
└──────────────────────────────┬──────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ Extract context │
│ • user identity + group memberships (SCIM/directory) │
│ • user risk score (CredInt/GeoIP enrichment) │
│ • target model ID + provider │
│ • model risk tier (model registry lookup) │
│ • request channel (interactive vs. api) │
│ • intent complexity (intake pipeline output) │
│ • DLP scan results: entity_types + content_categories │
└──────────────────────────────┬──────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ User chain present? │
│ YES ──────────────────────────────────────┐ │
│ │ │
│ Evaluate user chain rules in sequence order │ │
│ (combining algorithm: first_applicable by │ │
│ default, or deny_overrides if configured) │ │
│ ▼ │
│ Terminal action matched? │
│ YES ──────────────────────────────────────┐ │
│ NO ── fall through to org chain │ │
│ │ │
└──────────────────────────────┬──────────────────────────┼──────┘
│ (no user chain, or │
│ no user chain match) │
▼ │
┌─────────────────────────────────────────────────────────────────┐
│ Evaluate org chain rules in sequence order │
│ (combining algorithm: first_applicable by default) │
│ │
│ Non-terminal actions (e.g., REDACT) accumulate │
│ Terminal action ends evaluation │
└──────────────────────────────┬──────────────────────────────────┘
┌────────────┴────────────┐
│ │
No match Match found
│ │
▼ ▼
Default: ALLOW Apply action:
ALLOW / BLOCK / CANCEL /
REDACT / ROUTE_TO /
PROMPT / ALLOW_WITH_OVERRIDE
Audit log entry created
(rule_id, pack_id, chain_id,
action, matched conditions,
pre-redaction text if REDACT)

The context extraction phase runs before any rule evaluation begins. All fields are resolved once and cached for the duration of the evaluation pass:

Context field Source
User identity JWT sub claim, resolved against user store
Group memberships SCIM group sync or IdP directory (cached TTL: 60s)
User risk score CredInt enrichment result (0.0–1.0)
Model ID + provider Request routing header
Model risk tier Model registry lookup by (model_id, provider)
Request channel X-Arbitex-Channel header or connection type
Intent complexity Intake pipeline classification result
Entity types DLP scan (spaCy NER) over prompt or response text
Content categories DLP classifier over prompt or response text

In first_applicable mode, non-terminal actions from earlier rules accumulate as evaluation continues:

Rule 1 (sequence: 10): REDACT entity_types=[pii_name] → matched, REDACT applied, continue
Rule 2 (sequence: 20): REDACT entity_types=[financial_amount] → matched, REDACT applied, continue
Rule 3 (sequence: 30): entity_types=[financial_amount] → BLOCK → matched, BLOCK applied, stop

The final request carries both redactions from rules 1 and 2 even though rule 3 blocked it. The audit log records all three rule matches with their respective actions.


Before deploying policy changes to production, you can test them against a simulated request.

POST /api/v1/admin/policy/simulate

Request body:

{
"prompt": "Please send me the credit card number on file for customer 12345.",
"model_id": "gpt-4o",
"user_id": "user_abc",
"direction": "input",
"chain_id": "org"
}

Response 200 OK:

{
"outcome": "BLOCK",
"matched_rule": {
"id": "rule_xyz",
"name": "Block credit card in prompts",
"pack": "PCI-DSS v4.0 Compliance Bundle",
"condition_type": "entity_types",
"action": "BLOCK"
},
"evaluation_trace": [
{
"rule_id": "rule_aaa",
"name": "Finance power user exemption",
"matched": false,
"reason": "User not in group finance-power-users"
},
{
"rule_id": "rule_xyz",
"name": "Block credit card in prompts",
"matched": true,
"reason": "DLP detected entity_type=financial_amount"
}
],
"dry_run": true
}

The evaluation_trace lists every rule evaluated in sequence order, whether it matched, and why. This is the primary debugging tool for unexpected policy behavior.

Using dry_run to test before deploying:

  1. Create or modify rules on a staging chain.
  2. Run simulate with representative test cases.
  3. Verify the outcome and evaluation_trace match your intent.
  4. Promote the chain configuration to the active org chain.

The Cloud Portal provides a full administrative interface for policy management. All operations available via the API are also available through the admin UI. This section walks through the major screens.

The Policy Dashboard is the entry point for policy administration. Navigate to Admin → Policy Engine in the Cloud Portal.

The dashboard displays:

  • Active chain summary — the org chain name, combining algorithm, pack count, and total rule count
  • Pack list — all packs attached to the org chain in sequence order, with rule counts and enabled/disabled status per pack
  • Recent evaluations chart — a 24-hour time-series chart showing evaluation outcomes (ALLOW / BLOCK / REDACT / ROUTE_TO) segmented by hour
  • Top blocked rules — the 5 rules that have triggered the most BLOCK/CANCEL actions in the past 7 days, with match counts

The dashboard refreshes automatically every 60 seconds. Click any pack name to navigate to the pack’s rule list.

  1. Navigate to Admin → Policy Engine → Chains.

  2. Click New Chain.

  3. Enter the chain name (e.g., "Acme Corp Org Chain") and an optional description.

  4. Select the combining algorithm: First Applicable or Deny Overrides. For most organizations, First Applicable is the correct choice.

  5. Select the chain type:

    • Org chain — applies to all users in the organization
    • User chain — applies to a specific user (select the user from the dropdown)
  6. Click Create Chain. The new chain is created in a disabled state.

  7. Add packs to the chain (see next section), then click Activate to make it the active chain for the org or user.

  1. Navigate to Admin → Policy Engine → Packs and select the target pack, or click New Pack to create one.

  2. Click Add Rule to open the rule editor.

  3. In the Conditions panel, use the condition builder to add one or more conditions:

    • Click + Add Condition and select the condition type from the dropdown (e.g., content_categories).
    • Configure the condition parameters in the form fields that appear. For content_categories, select domains and subcategories from the multi-select picker. For entity_types, select entity labels from the searchable checklist.
    • Set the confidence threshold slider if applicable.
    • Add additional conditions with + Add Condition — all conditions are AND-combined.
  4. In the Action panel, select the action type from the dropdown:

    • ALLOW, BLOCK, CANCEL, REDACT, ROUTE_TO, PROMPT, or ALLOW_WITH_OVERRIDE
    • Fill in any action-specific fields (e.g., block message text, redact replacement string, route target model).
  5. Set the Direction: Input, Output, or Both.

  6. Set the Sequence number within the pack (integer; rules evaluate in ascending order).

  7. Optionally add a human-readable Rule name and Description.

  8. Click Save Rule. The rule is added to the pack immediately. If the pack is attached to an active chain, the rule takes effect on the next request.

The Policy Simulator is the built-in UI equivalent of the POST /api/v1/admin/policy/simulate API endpoint. It provides a visual evaluation trace without writing any audit log entries.

  1. Navigate to Admin → Policy Engine → Simulator.

  2. In the User context panel:

    • Select a User from the dropdown, or enter a user ID manually. The simulator resolves the user’s group memberships and risk score automatically.
    • Optionally override Group memberships to test hypothetical group assignments without changing directory data.
  3. In the Request panel:

    • Enter a Test prompt in the text area. This is the text that will be run through the DLP pipeline and evaluated against policy rules.
    • Select the Target model from the dropdown.
    • Select the Direction: Input or Output.
    • Select the Channel: Interactive or API.
  4. Click Run Simulation.

  5. Review the results in the Evaluation trace panel:

    • The Outcome badge shows the final action (ALLOW / BLOCK / REDACT / etc.) in color-coded format.
    • The Trace table lists every rule evaluated in sequence order, with columns for Rule name, Pack, Matched (yes/no), and Reason.
    • Click any row in the trace table to expand the full condition evaluation detail, showing which specific conditions matched and which did not.
    • If DLP was invoked, the DLP results section shows all detected entity types and content categories with their confidence scores.
  6. Iterate on test prompts and user contexts to cover your intended rule coverage before deploying changes.

The Effective Policy view shows the merged policy that would be applied to a specific user, combining their user chain (if any) with the org chain into a single ordered rule list.

  1. Navigate to Admin → Policy Engine → Effective Policy.

  2. Select a User from the search dropdown.

  3. Click View Effective Policy.

  4. The read-only view displays:

    • User chain rules (if a user chain exists) — shown at the top in sequence order with a “User Chain” badge
    • Org chain rules — shown below in sequence order with an “Org Chain” badge
    • Each rule shows its sequence, name, conditions summary, action, and direction
  5. Use the Export button to download the effective policy as JSON for offline review or audit documentation.

The Effective Policy view is read-only. To modify rules, navigate to the individual pack or chain editors.


Policy bundles are versioned to enable auditable rollback and safe incremental deployment. Versioning applies at the bundle (chain snapshot) level.

Policy bundle versions follow the format v{date}-{seq}:

Component Description
v Literal prefix
{date} ISO 8601 date of bundle creation (YYYYMMDD)
{seq} Monotonically increasing sequence number (zero-padded to 3 digits)

Example: v20260314-007 — the 7th bundle created on 2026-03-14.

A policy bundle is a self-contained snapshot of a chain and all its packs and rules at a point in time. It includes:

  • Chain metadata (name, combining algorithm, chain type)
  • All packs in sequence order
  • All rules within each pack, with full condition and action payloads
  • Bundle version identifier
  • Creation timestamp and creating principal
  • HMAC-SHA256 signature computed over the bundle JSON payload using the org’s policy signing key

The HMAC signature allows the Outpost to verify that a received bundle has not been tampered with in transit or at rest. The Outpost rejects any bundle whose signature fails verification and continues enforcing the previously cached valid bundle.

The Outpost maintains a local policy bundle cache to enable enforcement even during network interruptions:

Behavior Detail
Initial sync Outpost downloads the current active bundle on startup
Sync interval Configurable; default 60 seconds. The Outpost polls GET /api/outpost/policy-bundle
Cache persistence Bundle is persisted to local disk (policy_bundle_cache.json) and loaded on restart
Integrity check HMAC verified on every load (startup, sync, and disk read)
Stale bundle behavior If sync fails, the Outpost continues enforcing the last valid cached bundle
Maximum stale age Configurable; default 24 hours. After this threshold, the Outpost enters degraded mode and logs a warning

Bundle versions are created automatically when:

  1. A chain is activated (promoted to active) in the Cloud Portal
  2. Any rule, pack, or chain attribute is modified on an active chain via the API or admin UI
  3. A pack is added to or removed from an active chain

To manually snapshot the current chain state without activating it:

POST /api/v1/admin/policy-chains/{chain_id}/bundles
{
"note": "Pre-release snapshot before Q1 compliance review"
}

Response 201 Created:

{
"bundle_id": "bundle_abc123",
"version": "v20260314-007",
"chain_id": "chain_xyz",
"created_at": "2026-03-14T10:22:00Z",
"hmac_signature": "sha256:4f3a9b...",
"rule_count": 42,
"pack_count": 5
}

To revert to a previous bundle version:

POST /api/v1/admin/policy-chains/{chain_id}/activate
{
"bundle_id": "bundle_prev_abc"
}

This activates the specified bundle as the current active policy for the chain. Outposts will pick up the rollback on their next sync interval.


Arbitex ships pre-configured policy packs (bundles) for common compliance standards. Bundles are read-only and updated by Arbitex when standards change.

Bundle Standard Default rule count
pci-dss-v4 PCI-DSS v4.0 14
hipaa HIPAA Privacy + Security Rules 11
gdpr GDPR Article 5 data minimization 9
glba Gramm–Leach–Bliley Act 7
sox Sarbanes-Oxley Act 6
ccpa California Consumer Privacy Act 8
sec_reg_fd SEC Regulation FD (material non-public information) 6
occ-sr-11-7 OCC SR 11-7 model risk management 8

To add a bundle to your org chain:

POST /api/v1/admin/policy-chains/{chain_id}/packs
{
"pack_id": "pci-dss-v4",
"sequence": 100
}

Create a custom pack to group org-specific rules:

POST /api/v1/admin/policy-packs
{
"name": "Internal Data Classification Policy",
"description": "Enforces Acme Corp data classification rules for AI interactions",
"pack_type": "custom"
}

Add rules to the pack via POST /api/v1/admin/policy-packs/{pack_id}/rules.

Packs within a chain are evaluated in ascending sequence order. Convention:

Sequence range Purpose
1–99 High-priority user exemptions or overrides
100–299 Compliance bundles (PCI-DSS, HIPAA, etc.)
300–499 Custom org rules
500–699 Model governance rules (model_risk_tier, model_id)
700–899 Content policy rules
900–999 Default catch-all rules

This ordering ensures compliance bundles fire before custom rules, which fire before model governance rules. Adjust to suit your org’s risk posture.


All conditions and actions support a direction field that specifies when the rule is evaluated:

Direction Evaluated when
input Before the prompt is sent to the model
output Before the model response is returned to the user
both On both prompt and response

Most blocking rules target input to prevent sensitive content from reaching the model. Redaction and DLP detection rules often target both.


Condition Type AND-combinable Requires DLP
content_regex string (RE2 pattern) Yes No
entity_types string[] Yes Yes
user_groups string[] Yes No
providers string[] Yes No
models string[] Yes No
model_risk_tier string[] Yes No
user_risk_score_min float (0.0–1.0) Yes No
intent_complexity enum Yes No
channel string[] Yes No
content_categories string[] (domain.subcategory) Yes Yes
Action Terminal Interactive only Notes
ALLOW Yes No Explicit permit; stops evaluation
BLOCK Yes No Rejects request with message
CANCEL Yes No Silent drop; no policy message
REDACT No No Accumulates; evaluation continues
ROUTE_TO Yes No Redirects to different model/tier
PROMPT Yes Yes Challenge dialog; combine with channel condition
ALLOW_WITH_OVERRIDE Yes No Permits with informational notice

The Policy Engine never silently resolves conflicts between rules. If two rules could apply to the same request, the rule that appears earlier in the sequence wins (under first_applicable) — full stop. Your organization owns the sequence, and therefore owns the outcome.

Example: You have a Compliance Bundle at sequence=100 and a Custom Pack at sequence=200. Both contain rules that would match a specific request. The bundle rule at sequence=100 fires first; the custom pack rule at sequence=200 is never evaluated for that request.

If you want your Custom Pack rule to take precedence over the bundle rule for specific cases, move the Custom Pack to a lower sequence number. This is deliberate — compliance teams understand priority ordering, and making it explicit and auditable is preferable to a conflict-resolution algorithm that would itself introduce surprises.

The audit log records exactly which pack and rule matched, at which sequence position, and why. There is no ambiguity in the audit trace.


When a PROMPT rule fires on a live interactive request:

  1. Arbitex returns HTTP 449 Retry With to the frontend, which triggers the GovernancePromptDialog.
  2. The user enters a justification and clicks Submit.
  3. The original request re-submits with an X-Governance-Justification header containing the justification text and a X-Governance-Challenge-Id linking the re-submission to the original audit entry.
  4. The re-submitted request passes through the full policy chain again. The PROMPT rule is bypassed on re-submission — if all other rules pass, the request proceeds.
  5. If the user clicks Cancel in the dialog, the request is silently dropped with no error shown.

For API callers (channel: "api"), PROMPT rules should be excluded using the channel condition. If a PROMPT rule fires on an API caller, the caller receives HTTP 449 with a machine-readable body explaining the governance requirement.


The Pattern Browser under Admin → Policy → Patterns shows all active DLP detection patterns and allows you to create org-specific regex-based patterns.

Patterns are organized by category:

  • secret — API keys, tokens, credentials
  • pii — names, emails, phone numbers, government IDs
  • financial — card numbers, bank accounts, routing numbers
  • medical — diagnoses, drug names, patient identifiers
  • infrastructure — IP addresses, hostnames, internal URLs

Use the category filter chips and search box to locate patterns. Each PatternCard shows the pattern name, entity type, confidence threshold, and action tier badge.

Tier Behavior
log_only Log the detection event; allow the request to proceed unmodified
redact Replace the matched content with a redaction marker
block Block the request
prompt Surface a challenge to the user before proceeding
  1. Navigate to Admin → Policy → Patterns.

  2. Click New Pattern.

  3. Fill in the fields:

    Field Description
    Detector name Human-readable identifier for this pattern
    Entity type The semantic category this pattern detects (e.g., internal_project_code)
    Action tier What happens when the pattern matches (log_only / redact / block / prompt)
    Confidence threshold Minimum match confidence (0–1, step 0.05) required to trigger the action
    Regex pattern A valid Python-compatible regular expression
  4. Click Save Pattern.

Terminal window
# Create a custom regex DLP pattern
POST /api/v1/admin/dlp-rules/
{
"detector_name": "Project codename detector",
"detector_type": "regex",
"entity_type": "internal_project_code",
"action_tier": "redact",
"enabled": true,
"confidence_threshold": 0.9,
"config_json": {
"pattern": "\\bPROJ-[A-Z]{2,6}-\\d{3,6}\\b"
}
}

In the PolicyChainEditor (Admin → Policy Engine → Policy Chain), use the Group filter dropdown to preview how the chain applies to a specific group. When a group is selected:

  • Packs containing rules that match the group are highlighted with a Has rules for this group badge.
  • Non-matching packs are dimmed.
  • A posture summary shows the count of ALLOW, DENY (BLOCK/CANCEL), and REDACT rules from matching packs.

The selected group is saved to sessionStorage and used to pre-fill the group field in the Policy Simulator.


Terminal window
PUT /api/v1/admin/policy-chains/org
{
"packs": [
{ "id": "<pack-uuid>", "sequence": 1 },
{ "id": "<pack-uuid>", "sequence": 2 }
],
"combining_algorithm": "first_applicable"
}
Terminal window
POST /api/v1/admin/dlp-rules/test
{ "pattern": "\\b\\d{9}\\b", "sample": "My SSN is 123456789" }