IBEX Harness
DocsBenchmarksBlogChangelogRoadmap
GitHub
IBEX Harness

Documentation

Architecture Decision RecordsADR-0002: Repository foundation bootstrapADR-0003: Branch protection and merge policyADR-0004: Protobuf and code generation policyADR-0005: Postgres migration strategyADR-0006: Auth protobuf contract (`ibex.auth.v1`)ADR-0007: Auth token validation implementationADR-0008: Security scanning and CI quality gatesADR-0009: Permission bitmap layoutADR-0010: Cryptography policyADR-0011: Proxy auth gRPC client and middlewareADR-0012: Proxy request normalization (OpenAI chat)ADR-0013: Proxy input validation and stable error envelopeADR-0014: Core domain migration sequencingADR-0015: Proxy rate limit skeleton (Phase 1)ADR-0016: Proxy agent identity verification (Phase 1)ADR-0017: Request ID and trace context strategy (Phase 1)ADR-0018: Graceful shutdown contract (Phase 1)ADR-0019: OpenTelemetry provider configuration (Phase 1)ADR-0020: Shared package boundaries — `packages/config` and `packages/apierror`ADR-0021: Prometheus Metric Catalog (Phase 1)ADR-0022: Health check contract (Phase 1)ADR-0023: Docs site architecture (Phase 1.5)ADR-0024: Benchmark data publishing modelADR-0025: LLM provider abstractionADR-0026: OpenAI client designADR-0027: Streaming dual-write strategyADR-0028: Auth cache designADR-0029: Token revocation propagation via Redis pub/subADR-0030: Directive versioning strategyADR-0031: System prompt injection strategyADR-0032: Session data model and retentionADR-0033: ClickHouse llm_traces schema and retentionADR-0034: Proxy overhead performance measurement methodologyADR-0035: Chat Idempotency-Key Redis dedupeADR-0038: Context assembly service design and gRPC contractADR-0039: Proxy Postgres ownership for session and directive storesADR-0040: Anthropic provider adapterADR-0041: Model capability registryADR-0042: Self-hosted OpenAI-compatible LLM adapterADR-0043: Tokenizer registry architectureADR-0044: Non-streaming response pipelineADR-0045: Streaming response transformationADR-0046: Embedder interface and profile registryADR-0047: Memory temporal validity foundationADR-0048: Memory multi-label categoriesADR-0049: Memory relationship graph readinessADR-0050: MCP server skeleton (transport, auth, audit)ADR-0051: Local LGTM observability stack (Phase 2.5 exit pull-forward)ADR-0052: Memory schema v2 expand (HNSW, quality columns)ADR-0053: Vector store abstraction and composite scoring v2ADR-0054: In-process Presidio PII detection in memoryADR-0055: Memory write-path exact and near-duplicate dedupADR-0056: Temporal-interval-aware conflict detectionADR-0057: Memory write-path persistence and orchestrationADR-0058: Semantic search FTS fallback triggerADR-0059: Hot cache read pathADR-0060: Memory service tenant isolation architectureADR-0061: Retrieval-quality benchmark methodologyADR-0062: Worker task observability and dead-letter handlingADR-0063: Extraction output schema v2ADR-0064: Extraction provider registry and batch executionADR-0065: Extraction batch idempotency and turn pointer orderingADR-0066: Extraction quality evaluation harnessADR-0067: Context capability catalog generate-and-diff for token budgetsADR-0068: Composite scoring-time relevance gateADR-0069: Context packer bounded DP knapsackADR-0070: Context formatting locked ordering and session nonceADR-0071: Context assembly gRPC degradation ladder and retrieval deadlineADR-0072: Extraction enqueue via worker HTTP (not Celery Redis wire format)ADR-0073: Organization Lifecycle and Cascading SuspensionADR-0074 Provider Credential StorageADR-0075 Per-Org Model Routing PolicyADR-0076: Circuit Breaker per ProviderADR-0077: Provider Fallback RoutingADR-0078: Operator runtime topology & environment contract (4.P.0)ADR-0079: Operator session RS256 dual-verify and TOTP step-upIBEX Console service rename and boundaryADR-0081: Fail-closed Proxy runtime controlsD2 metadata-only trace read contractD2 publication, identity, query, and lifecycle contract
ADRs›ADR-0077: Provider Fallback Routing
ADRs

ADR-0077: Provider Fallback Routing

Error-driven opt-in model fallback on circuit_open/5xx/timeout with per-replica breakers and pre-stream cutoff

ADR-0077: Provider Fallback Routing

  • Status: Accepted
  • Date: 2026-09-12
  • Authors: IBEX Harness team
  • Milestone: 4.C.4 Fallback routing
  • Related: ADR-0075, ADR-0076, ADR-0033

Context

Circuit breakers (4.C.3) fail fast when a provider is unhealthy but do not recover the request. Org model policies (4.C.2) gate allow/deny but deferred fallback_chain until a consumer existed. Milestone 4.C.4 adds transparent substitution to a configured next model when the primary Complete fails for breaker-open, 5xx (after adapter retries), or timeout — never for 4xx (including 429).

Decision

  1. Error-driven breaker observation only. Detect open via errors.As → *provider.ProviderError with Reason == ErrorReasonCircuitOpen on the failed primary Complete. No preflight State() peek and no widening of provider.CircuitBreaker.
  2. Per-replica breaker state is accepted. Breakers remain in-process gobreaker instances. Fallback decisions based on locally observed Complete failures may differ across proxy replicas. Shared Redis breaker state is explicitly out of scope.
  3. Trigger matrix: eligible = circuit_open OR HTTP 5xx OR timeout. Never 4xx, including 429. BYO requests (APIKeyOverride / BaseURLOverride) never fallback.
  4. Opt-in: org_model_policies.fallback_chain TEXT[] NOT NULL DEFAULT '{}' with cardinality <= 8 (API + DB). Empty = disabled. Non-empty on the first-match allow policy for the original model = opt-in. Runtime hop depth capped by IBEX_PROVIDER_FALLBACK_MAX_DEPTH (default 1) as min(len(chain), max_depth).
  5. Every hop must pass ForOrg. Deny or unknown model → skip hop. Policy infrastructure failure → abort fallback and surface the original primary error (fail closed).
  6. Streaming hard cutoff: fallback only when primary Complete fails before forwardSSEStream (before any client bytes). After SSE headers flush, never fallback (double-billing / duplicate client events).
  7. Headers X-IBEX-Provider-Fallback / X-IBEX-Provider-Used only on successful substitution (after response acceptance, immediately before WriteHeader). Chain exhausted → the original mapped primary error; no fallback headers.
  8. ClickHouse: additive original_model, fallback_model, fallback_reason on ibex.llm_traces. Usage attributes to the fallback model; audit fields record original + reason. Non-fallback rows leave new fields null/empty.

Consequences

  • Operators configure chains on allow policies; depth is a process env knob.
  • Multi-replica open detection is best-effort and LB-dependent; document for operators.
  • Streaming clients still get fail-fast 503 on mid-stream upstream death without model swap.

Was this page helpful?

Edit on GitHub

Last updated on

PreviousADR-0076: Circuit Breaker per ProviderNextADR-0078: Operator runtime topology & environment contract (4.P.0)

On this page

  • Context
  • Decision
  • Consequences
0%