# How the OmniRoute Auto-Combo 12-Factor Scoring Engine Evaluates Candidate Providers

> Discover how the OmniRoute Auto-Combo engine uses a 12-factor weighted scoring system to evaluate LLM provider candidates by normalizing infrastructure signals into a 0-to-1 score.

- Repository: [Diego Rodrigues de Sa e Souza/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- Tags: deep-dive
- Published: 2026-08-06

---

**The OmniRoute Auto-Combo engine uses a 12-factor weighted scoring system in [`open-sse/services/autoCombo/scoring.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/services/autoCombo/scoring.ts) that normalizes infrastructure signals—quota, health, cost, latency, task fit, and more—into a 0-to-1 score to rank LLM provider candidates.**

The **Auto-Combo** engine is OmniRoute's intelligent routing layer that dynamically selects the optimal LLM provider, model, and connection-account combination for each incoming request. Rather than relying on static rules, it computes a quantitative fitness score for every candidate using twelve normalized factors and a configurable weight vector. This article breaks down exactly how factor extraction and weighted aggregation work inside the [OmniRoute](https://github.com/diegosouzapw/OmniRoute) codebase.

---

## The Two-Stage Scoring Pipeline

Provider evaluation happens in two distinct phases:

1. **Factor extraction** — `calculateFactors()` ingests raw telemetry and metadata from each `ProviderCandidate`, producing normalized values between 0 and 1.
2. **Weighted aggregation** — `calculateScore()` multiplies each factor by its corresponding weight and sums the results, returning a final score clamped to `[0, 1]`.

The top-scoring candidate wins the request. If multiple candidates tie, secondary sort keys (latency, then randomization) break the deadlock.

---

## The 12 I²-Factors Explained

All twelve factors are normalized by `clamp01()` to prevent malformed telemetry from poisoning rankings.

| Factor | Definition | Data Source | Normalization Formula |
|--------|-----------|-------------|----------------------|
| **quota** | Remaining quota percentage | `candidate.quotaRemaining` | `quotaRemaining / 100` |
| **health** | Circuit-breaker health state | `candidate.circuitBreakerState` | 1 = CLOSED, 0.5 = HALF_OPEN, 0 = OPEN |
| **costInv** | Inverse cost (cheaper → higher) | `candidate.costPer1MTokens` vs pool max | `1 - (cost / maxCost)` |
| **latencyInv** | Inverse p95 latency (faster → higher) | `candidate.p95LatencyMs` vs pool max | `1 - (latency / maxLatency)` |
| **taskFit** | Model-task compatibility | `getTaskFitness(model, taskType)` | Static table lookup, clamped 0-1 |
| **stability** | Latency consistency (lower jitter → higher) | `candidate.latencyStdDev` vs pool max | `1 - (stdDev / maxStdDev)` |
| **tierPriority** | Account tier + reset window bonus | `accountTier`, `quotaResetIntervalSecs` | `calculateTierScore()` |
| **tierAffinity** | Alignment with minimum tier hint | `manifestHint?.recommendedMinTier` | `calculateTierAffinity()` |
| **specificityMatch** | Match to manifest specificity hint | `manifestHint?.specificity.score` | `calculateSpecificityMatch()` |
| **contextAffinity** | Session provider reuse preference | `candidate.contextAffinity` | Clamped input or default 0.5 |
| **cacheAffinity** | Prompt cache key affinity | `candidate.cacheAffinity` | Clamped input or default 0 |
| **resetWindowAffinity** | Preference for soon-resetting quotas | `candidate.resetWindowAffinity` | Clamped input or default 0.5 |
| **connectionDensity** | Inverse connection pool saturation | `candidate.connectionPoolSize` | `((size - 1) / 10)` |

The "I²" designation refers to **infrastructure-squared**: **quota** and **health** are the dominant first-order signals that together receive 35% of default weight allocation.

---

## Core Scoring Implementation

### Factor Extraction

```typescript
// open-sse/services/autoCombo/scoring.ts
export interface ScoringFactors {
  quota: number;              // [0, 1]
  health: number;             // [0, 1]
  costInv: number;            // [0, 1]
  latencyInv: number;         // [0, 1]
  taskFit: number;            // [0, 1]
  stability: number;          // [0, 1]
  tierPriority: number;       // [0, 1]
  tierAffinity: number;       // [0, 1]
  specificityMatch: number;   // [0, 1]
  contextAffinity: number;    // [0, 1]
  cacheAffinity: number;      // [0, 1]
  resetWindowAffinity: number; // [0, 1]
  connectionDensity: number;  // [0, 1]
}

```

`calculateFactors()` computes each value by comparing the candidate against pool-wide maximums (for cost, latency, stability) or direct metadata lookups (for quota, health, tier).

### Weighted Score Calculation

```typescript
// open-sse/services/autoCombo/scoring.ts
export function calculateScore(
  factors: ScoringFactors,
  weights: ScoringWeights,
): number {
  return clamp01(
    weights.quota * factors.quota +
    weights.health * factors.health +
    weights.costInv * factors.costInv +
    weights.latencyInv * factors.latencyInv +
    weights.taskFit * factors.taskFit +
    weights.stability * factors.stability +
    weights.tierPriority * factors.tierPriority +
    (weights.tierAffinity ?? 0) * factors.tierAffinity +
    (weights.specificityMatch ?? 0) * factors.specificityMatch +
    (weights.contextAffinity ?? 0) * factors.contextAffinity +
    (weights.cacheAffinity ?? 0) * (factors.cacheAffinity ?? 0) +
    (weights.resetWindowAffinity ?? 0) * factors.resetWindowAffinity +
    (weights.connectionDensity ?? 0) * factors.connectionDensity,
  );
}

```

Optional weights (marked with `?? 0`) activate only when the operator configures them or when a `RoutingHint` supplies manifest-level guidance.

---

## Default Weight Distribution

The `DEFAULT_WEIGHTS` constant in [`scoring.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/scoring.ts) establishes the following allocation:

| Weight | Value | Purpose |
|--------|-------|---------|
| `quota` | 0.15 | Prevent quota exhaustion |
| `health` | 0.20 | Avoid unhealthy providers |
| `costInv` | 0.15 | Prefer cheaper options |
| `latencyInv` | 0.12 | Prefer faster options |
| `taskFit` | 0.10 | Match model to task |
| `stability` | 0.08 | Reduce jitter |
| `tierPriority` | 0.12 | Respect account tiers |
| `tierAffinity` | 0.05 | Honor minimum tier hints |
| `specificityMatch` | 0.03 | Honor specificity hints |
| `contextAffinity` | 0.00 | Disabled by default |
| `cacheAffinity` | 0.00 | Disabled by default |
| `resetWindowAffinity` | 0.00 | Disabled by default |
| `connectionDensity` | 0.00 | Disabled by default |

Infrastructure factors (quota, health, costInv, latencyInv) collectively control **62%** of the score, giving the engine its "I²" character.

---

## Practical Code Examples

### Basic Pool Scoring

```typescript
import { scorePool, DEFAULT_WEIGHTS } from '@/open-sse/services/autoCombo/scoring';
import { getTaskFitness } from '@/open-sse/services/autoCombo/taskFitness';

// Build candidates from provider catalog
const rawCandidates = await virtualFactory.createVirtualAutoCombo();

// Score for "coding" task using defaults
const ranked = scorePool(rawCandidates, 'coding', DEFAULT_WEIGHTS, getTaskFitness);

console.log(`Top provider: ${ranked[0].provider}/${ranked[0].model}`);
console.log(`Score: ${ranked[0].score.toFixed(4)}`);

```

### Custom Weight Override (Cost-Sensitive Mode)

```typescript
import { normalizeScoringWeights } from '@/open-sse/services/autoCombo/scoring';

const costSensitiveWeights = normalizeScoringWeights({
  quota: 0.20,
  health: 0.15,
  costInv: 0.35,      // Boost cost importance
  latencyInv: 0.10,   // Deprioritize speed
  taskFit: 0.15,
  stability: 0.05,
  tierPriority: 0.10,
});

const ranked = scorePool(rawCandidates, 'coding', costSensitiveWeights, getTaskFitness);

```

### Single Candidate Evaluation (Testing)

```typescript
import { calculateFactors, calculateScore } from '@/open-sse/services/autoCombo/scoring';

const candidate: ProviderCandidate = {
  provider: 'openai',
  model: 'gpt-4-turbo',
  quotaRemaining: 78,
  circuitBreakerState: 'CLOSED',
  costPer1MTokens: 10.00,
  p95LatencyMs: 450,
  // ... other fields
};

const factors = calculateFactors(candidate, allCandidates, 'coding', getTaskFitness);
const score = calculateScore(factors, DEFAULT_WEIGHTS);

console.log(`Factors:`, factors);
console.log(`Final score: ${score.toFixed(4)}`);

```

### Manifest Hint Integration

```typescript
import type { RoutingHint } from '@/open-sse/services/autoCombo/manifestAdapter';

const hint: RoutingHint = {
  recommendedMinTier: 'ultra',      // Activates tierAffinity
  specificity: {
    score: 85,                       // Activates specificityMatch
    dimensions: ['reasoning', 'code']
  }
};

const ranked = scorePool(
  rawCandidates,
  'coding',
  DEFAULT_WEIGHTS,
  getTaskFitness,
  hint  // Optional 4th parameter
);

```

---

## Entry Point and Integration

The `scorePool()` function is invoked by `autoCombo` strategy implementation in [`open-sse/services/autoCombo/index.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/services/autoCombo/index.ts). This is the public API consumed by OmniRoute's routing layer:

```typescript
// open-sse/services/autoCombo/index.ts (simplified)
export async function autoComboRoute(
  request: LLMRequest,
  context: RoutingContext,
): Promise<ProviderSelection> {
  const candidates = await virtualFactory.createVirtualAutoCombo();
  const taskType = classifyTask(request);
  
  const scored = scorePool(
    candidates,
    taskType,
    context.weights ?? DEFAULT_WEIGHTS,
    getTaskFitness,
    context.manifestHint,
  );
  
  return {
    provider: scored[0].provider,
    model: scored[0].model,
    connectionAccount: scored[0].connectionAccount,
    score: scored[0].score,
  };
}

```

---

## Key Source Files

| File | Role |
|------|------|
| [`open-sse/services/autoCombo/scoring.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/services/autoCombo/scoring.ts) | Core factor extraction, `calculateScore()`, `scorePool()`, weight normalization |
| [`open-sse/services/autoCombo/index.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/services/autoCombo/index.ts) | Public entry point integrating with routing layer |
| [`open-sse/services/autoCombo/virtualFactory.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/services/autoCombo/virtualFactory.ts) | Candidate pool construction via `createVirtualAutoCombo()` |
| [`open-sse/services/autoCombo/taskFitness.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/services/autoCombo/taskFitness.ts) | Static model-task compatibility matrix |
| [`open-sse/services/autoCombo/manifestAdapter.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/services/autoCombo/manifestAdapter.ts) | `RoutingHint` type definitions and parsing |
| [`open-sse/handlers/autoComboCandidates.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/handlers/autoComboCandidates.ts) | Read-only API decorating candidates with reachability state |

---

## Summary

- The **OmniRoute Auto-Combo 12-factor scoring engine** evaluates every provider candidate across **quota, health, cost, latency, task fit, stability, tier priority, tier affinity, specificity match, context affinity, cache affinity, reset window affinity, and connection density**.
- Factors are **normalized to [0, 1]** and combined via **weighted summation** in `calculateScore()`.
- **Default weights prioritize infrastructure signals** (62% combined), with quota (15%) and health (20%) as the dominant "I²" factors.
- The engine supports **runtime weight customization** and **manifest-driven hints** for fine-grained routing control.
- All scoring logic lives in [`open-sse/services/autoCombo/scoring.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/open-sse/services/autoCombo/scoring.ts) and is invoked through `scorePool()` by the routing layer.

---

## Frequently Asked Questions

### What does "I²-factor" mean in OmniRoute's scoring engine?

"I²-factor" refers to the two **infrastructure-level factors** that dominate the default weight distribution: **quota availability** (15%) and **health/circuit-breaker state** (20%). Together these "infrastructure-squared" signals control 35% of the scoring decision, ensuring the engine prioritizes providers that are both well-capitalized and operationally healthy before considering cost or latency optimizations.

### How can I customize which factors matter most for my workload?

Override the `DEFAULT_WEIGHTS` by calling `normalizeScoringWeights()` with a partial weight object. Pass your custom weights as the third argument to `scorePool()`. The function automatically renormalizes so weights sum to 1.0. For UI-driven changes, store weights in your deployment configuration and inject them via the `RoutingContext`.

### Why are some factors like cacheAffinity and contextAffinity zero by default?

These factors represent **optional affinity optimizations** that make sense only in specific deployment patterns. `cacheAffinity` requires prompt-key caching infrastructure; `contextAffinity` assumes sticky session routing. Keeping them at 0.00 in `DEFAULT_WEIGHTS` ensures safe, stateless behavior out of the box while allowing operators to opt into affinity-based routing when their architecture supports it.

### How does the engine handle missing or malformed candidate telemetry?

All factor calculations pass through `clamp01()`, which bounds every intermediate result to `[0, 1]`. For pool-relative factors like `costInv` and `latencyInv`, the engine computes maximums across the candidate set, so a single outlier cannot collapse the scale. Missing optional fields (e.g., `connectionPoolSize`) receive sensible defaults that neutralize their impact on the final score.