# How the Domain Policy Engine in OmniRoute Governs Routing Decisions Independently

> Discover how OmniRoute's domain policy engine autonomously controls routing decisions by evaluating API requests against lockout budget and fallback policies before provider routing.

- Repository: [Diego Rodrigues de Sa e Souza/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- Tags: internals
- Published: 2026-07-25

---

**The domain policy engine in OmniRoute operates as a centralized, declarative decision-making component that evaluates API requests against lockout, budget, and fallback policies before any provider routing occurs, ensuring complete separation from the routing-combo and executor logic.**

The **domain policy engine** in the [OmniRoute](https://github.com/diegosouzapw/OmniRoute) repository provides self-contained governance over how AI model requests are processed and routed. Unlike traditional systems that scatter policy logic across transport layers, this engine sits entirely within the domain layer at [`src/domain/policyEngine.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/domain/policyEngine.ts), deterministically evaluating whether requests may proceed, which providers are preferred, and what constraints apply—all before network I/O begins.

## Core Architecture of the Domain Policy Engine

The engine follows a strict evaluation pipeline that processes requests through normalization, validation, and policy resolution stages.

### Request Normalization and PolicyRequest Construction

Every incoming API call is first normalized into a **PolicyRequest** object containing the model name, API-key ID, client IP, and optional provider preference. According to the OmniRoute source code at [`src/domain/policyEngine.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/domain/policyEngine.ts) (lines 15‑21), this normalization ensures all subsequent evaluations operate on a consistent data structure regardless of the entry point.

### Pre-Routing Validation Checks

Before policy evaluation begins, the engine executes mandatory lockout and budget validations. The **checkLockout** function inspects the client IP or identifier for active lockout states at lines 50‑61, immediately returning a denial verdict if the client is locked, as implemented in [`src/domain/lockoutPolicy.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/domain/lockoutPolicy.ts) (lines 73‑94). Similarly, **checkBudget** verifies API-key quota limits at lines 63‑73, referencing budget constraints defined in [`src/domain/costRules.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/domain/costRules.ts).

### Fallback Chain Resolution

When primary models are unavailable, **resolveFallbackChain** builds a prioritized list of alternative models. As defined at lines 76‑86 in [`src/domain/policyEngine.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/domain/policyEngine.ts), this function attaches the fallback chain to the verdict metadata, enabling downstream components to execute graceful degradation without re-evaluating policies.

### Class-Based Policy Evaluation

The **PolicyEngine** class maintains an in-memory registry of `Policy` objects. When `evaluate()` is called (lines 101‑195), it:

- Sorts enabled policies by **priority** value
- Filters policies using glob matchers against model patterns
- Executes actions based on policy type (`routing`, `access`, or `budget`)
- Accumulates preferred providers, applied policies, and token limits into a comprehensive result

The final **PolicyVerdict** returned at lines 47‑88 and 133‑191 indicates whether the request is allowed, the denial reason if applicable, and any adjustments such as preferred provider lists or max-token overrides.

## Architectural Independence from Routing Logic

The domain policy engine guarantees independence from the routing-combo and executor layers through several architectural constraints.

### Pure Function Design for Side-Effect-Free Evaluation

All validation checks—including **checkLockout**, **checkBudget**, and **resolveFallbackChain**—are implemented as pure functions that do not trigger provider calls or external side effects. This functional isolation ensures that policy evaluation remains deterministic and testable without requiring network infrastructure.

### Deterministic Verdicts Before Network I/O

The engine produces a definitive **allowed** boolean flag and structured reason codes before any routing logic executes or HTTP requests leave the system. This pre-network governance prevents wasted resources on requests that violate budget or lockout constraints.

### Composable Policies Without Router Modification

New policies integrate via `PolicyEngine.addPolicy()` without touching the combo router. The engine automatically merges policies based on priority values, keeping routing logic untouched while allowing complex rule composition. This extensibility point at lines 101‑195 demonstrates how the engine accommodates custom business rules independently of transport concerns.

### Separation of Concerns Across Domain Modules

Policy logic is modularized into dedicated domain files: lockout tracking lives in [`src/domain/lockoutPolicy.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/domain/lockoutPolicy.ts), budget enforcement in [`src/domain/costRules.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/domain/costRules.ts), and fallback resolution in [`src/domain/fallbackPolicy.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/domain/fallbackPolicy.ts). This compartmentalization prevents policy-related bugs from leaking into the combo or executor layers, as each module handles a specific governance concern.

## Implementing Policy Checks in Code

Developers interact with the policy engine through both functional and class-based APIs.

### Evaluating a Single Request

Use the **evaluateRequest** function to check individual API calls against active policies:

```ts
import { evaluateRequest } from '@/domain/policyEngine';

const verdict = evaluateRequest({
  model: 'gpt-4o',
  apiKeyId: 'key_123',
  clientIp: '203.0.113.42',
});

if (!verdict.allowed) {
  console.log(`Denied (${verdict.policyPhase}): ${verdict.reason}`);
} else {
  console.log('Allowed – fallback chain:', verdict.adjustments.fallbackChain);
}

```

This function returns either a denial message indicating the failing phase (lockout or budget) or an allowed verdict with the computed fallback chain metadata.

### Configuring Custom Policies with the PolicyEngine Class

For advanced scenarios, instantiate the **PolicyEngine** class to register custom routing policies:

```ts
import { PolicyEngine, Policy } from '@/domain/policyEngine';

const preferClaude: Policy = {
  id: 'p1',
  name: 'Prefer Claude for Claude‑compatible models',
  type: 'routing',
  enabled: true,
  priority: 10,
  conditions: { model_pattern: 'claude-*' },
  actions: { prefer_provider: ['anthropic'] },
};

const engine = new PolicyEngine();
engine.loadPolicies([preferClaude]);

const result = engine.evaluate({ model: 'claude-2.1' });

console.log(result.preferredProviders); // → ['anthropic']

```

The engine sorts policies by priority and applies glob matching to model patterns, returning preferred providers without executing network calls.

### Bulk Evaluation for Model Selection

When multiple model alternatives exist, use **evaluateFirstAllowed** to find the first permissible option:

```ts
import { evaluateFirstAllowed } from '@/domain/policyEngine';

const models = ['gpt-4o', 'gpt-3.5-turbo', 'claude-2'];
const base = { apiKeyId: 'key_123', clientIp: '203.0.113.42' };

const { model, verdict } = evaluateFirstAllowed(models, base);
if (model) {
  console.log(`First allowed model: ${model}`);
} else {
  console.log(`All denied – reason: ${verdict.reason}`);
}

```

This utility evaluates models sequentially until finding one that passes all policy checks, optimizing for the first available valid option.

## Summary

The domain policy engine in OmniRoute provides independent governance over routing decisions through these key characteristics:

- **Centralized evaluation** at [`src/domain/policyEngine.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/domain/policyEngine.ts) processes all requests before they reach routing layers
- **Pure function architecture** ensures deterministic, side-effect-free policy validation without network dependencies
- **Declarative policy composition** allows new rules to be added via `PolicyEngine.addPolicy()` without modifying routing code
- **Modular domain structure** separates lockout, budget, and fallback concerns into distinct modules
- **Pre-routing verdicts** return definitive allow/deny decisions with reasons and metadata before any provider calls occur

## Frequently Asked Questions

### Why is the domain policy engine considered independent from the routing combo?

The engine operates entirely within the domain layer using pure functions that produce deterministic verdicts before any network I/O or routing logic executes. By residing in [`src/domain/policyEngine.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/domain/policyEngine.ts) and interacting with separate modules like [`src/domain/lockoutPolicy.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/domain/lockoutPolicy.ts) and [`src/domain/costRules.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/domain/costRules.ts), it maintains zero dependencies on the combo router or executor implementations, ensuring routing decisions respect policies without entangling the transport layer with business rules.

### How does the engine handle budget and lockout checks?

The engine executes **checkLockout** (lines 50‑61) to inspect client IPs for active lockouts and **checkBudget** (lines 63‑73) to verify API-key quotas against definitions in [`src/domain/costRules.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/domain/costRules.ts). Both checks occur immediately after request normalization and return denial verdicts with specific phase identifiers (`lockout` or `budget`) if constraints are violated, preventing the request from ever reaching provider selection logic.

### Can custom policies be added without modifying the router?

Yes. The **PolicyEngine** class exposes `loadPolicies()` and `addPolicy()` methods that accept `Policy` objects defining conditions, actions, and priorities. These policies are evaluated at lines 101‑195 in [`src/domain/policyEngine.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/domain/policyEngine.ts) through a priority-sorted execution loop that requires no changes to the combo router or executor code, enabling business-specific routing rules to be injected purely through domain configuration.

### What happens during fallback chain resolution?

When a requested model might be unavailable, **resolveFallbackChain** (lines 76‑86) constructs a prioritized list of alternative models based on domain rules in [`src/domain/fallbackPolicy.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/domain/fallbackPolicy.ts). This chain attaches to the **PolicyVerdict** as metadata, allowing downstream components to attempt subsequent models if the primary fails, all while maintaining the original policy constraints and without requiring re-evaluation of lockout or budget rules for each fallback attempt.