# Resolution Algorithm Deterministic resolution pipeline that produces ordered routing directives. Input/output contracts are defined in the [OpenAPI spec](../api/openapi.yaml); persistence shape is in the [data model](data-model.md). ## Precedence ladder (per rail) When multiple sources can contribute a directive, apply this order. The first successful source wins unless overridden by tenant/contract config: 1. **Tenant override** — Tenant-specific routing artifact or endpoint override. 2. **Contract-specific config** — Contract or connectivity-group mapping. 3. **Internal curated directory** — Participants/endpoints stored in the directory (admin or connector). 4. **External authoritative directory** — SMP/SML, GTT feed, or other external source (cached). 5. **Fallback heuristics** — Optional, disabled by default (e.g. default route). Log and expose **resolution_trace** in the response so callers see which source(s) contributed (e.g. "tenant override", "internal directory", "SMP cache"). See [route-directive.md](route-directive.md). **Source-driven mappings (e.g. SS7):** Data from connectors (GTT, NP/range feeds) is only as good as the ingested sources. Expose confidence and `last_verified` in directives; tag edges with provenance. No implied authority—see [connectors.md](connectors.md). ## Pipeline (steps 1–9) 1. **Normalize input** Parse and validate all identifiers in the request. Validate formats per type (E.164, PartyId, PC/SSN, etc.). Reject invalid or unsupported types early. 2. **Expand context** Infer candidate identifier equivalences using the mapping graph (same participant: multiple identifier types pointing to the same participant). Build a set of "equivalent" identifiers for lookup. 3. **Candidate retrieval** Query the directory store for participants and endpoints matching any of the normalized/expanded identifiers, within the requested tenant and constraints. 4. **Capability filter** Retain only participants/endpoints whose capabilities match the requested service context (service, action, process, document type) and any constraints in the request. Constraints may include `requiredCapability`, `messageType` (e.g. ISO8583 MTI), and `networkBrand` for card rails. 5. **Policy filter** Apply tenant-scoped policies (ABAC). Enforce trust domain, geo, compliance, and allow/deny rules. Remove any candidate that is denied or out of scope. 6. **Score and rank** Score remaining candidates (see [Scoring](#scoring)). Sort by score descending; apply [tie-break rules](#determinism-and-tie-break) for stable ordering. 7. **Assemble directives** For each ranked candidate, build a `RouteDirective`: map endpoint + participant to `target_protocol`, `target_address`, `transport_profile`, attach security refs (from credentials), `service_context`, `qos`, `ttl_seconds`, and `evidence` (source, lastVerified, confidenceScore). 8. **Sign response (optional)** In multi-party setups, optionally sign the response for non-repudiation. Not required for MVP. 9. **Cache** Store result in positive cache (keyed by normalized request + tenant) with TTL. On cache hit, return cached directives and skip steps 2–7. Negative results (no candidates after filters) may be cached with shorter TTL and invalidation hooks. ## Determinism and tie-break - **Invariant:** Same inputs + same store state ⇒ same ordered list of directives. - **Tie-break order** when scores are equal (aligned with [data-model conflict resolution](data-model.md#conflict-resolution-deterministic)): 1. **Explicit priority** (endpoint/identifier priority from store) — higher first. 2. **Policy** (allow/deny and policy priority). 3. **Freshness** (updated_at / verified_at / valid_from). 4. **Confidence** (edge or evidence confidence score). 5. **Lexical** — stable sort by deterministic key (e.g. participant id + endpoint id). Implementation must use a fixed ordering (e.g. sort by `(score DESC, priority DESC, updated_at DESC, id ASC)`). ## Scoring Factors that contribute to the score (combined by weighted sum or ordered rules; exact weights are implementation/config): | Factor | Description | | ---------------------- | ----------------------------------------------------------------------- | | Explicit priority | From `identifiers.priority` / `endpoints.priority` in the store. | | Endpoint health/status | Prefer `active` over `draining` over `inactive`. | | Freshness/verification | Higher score when `identifiers.verified_at` or evidence is recent. | | Trust domain affinity | Match between requested trust domain and endpoint/participant metadata. | Scoring must be deterministic: same inputs and same data ⇒ same scores and thus same order after tie-break. ## Caching - **Positive cache:** Key = hash or canonical form of (normalized identifiers, serviceContext, constraints, tenant). Value = ordered list of directives + TTL. Reuse until TTL expires or explicit invalidation. - **Negative cache:** When no candidates survive filters, cache "no result" with a shorter TTL to avoid thundering herd on missing keys. Invalidation: on participant/identifier/endpoint/policy change for that tenant or key scope. - **Invalidation hooks:** Connectors or admin updates that change participants/endpoints/policies should invalidate affected cache keys (by tenant, participant id, or key prefix). Optional: publish events for external caches.