cap: Documentation
Browse Sign In

Ranking

Selection policy, specificity distance, preference order, and tie-breaking

Separation of Concerns

The system distinguishes two phases:

  1. Dispatch Validity — Is this provider legal for this request? (see Dispatch)
  2. Ranking — Among valid providers, which should be selected?

Ranking applies ONLY to dispatch-valid providers. Never rank before validating.

The Valid Set

Given a request $r$, define the valid set:

$$ \text{Valid}(r) = \{ p \in C \mid \text{Dispatch}(p, r) \} $$

Ranking is a total order over $\text{Valid}(r)$.

Specificity Distance

Definition

For a provider $p$ and request $r$:

$$ \text{dist}(p, r) = \text{spec}_C(p) - \text{spec}_C(r) $$

Where $\text{spec}_C$ is Cap URN specificity (see Specificity).

Interpretation

Distance Meaning Provider Relationship
dist = 0 Equivalent Provider matches request exactly
dist > 0 Refinement Provider is more specific
dist < 0 Fallback Provider is more generic

Preference Order

Standard Policy

The default ranking policy prefers:

  1. Exact match (dist = 0) — most preferred
  2. Refinement (dist > 0) — provider specializes request
  3. Fallback (dist < 0) — provider is generic, last resort

Within each category, prefer smaller absolute distance.

Formal Ordering

For providers $a$ and $b$ in $\text{Valid}(r)$:

$$ a \prec b \;\text{(a preferred over b)} \;\text{iff:} $$
  • $\text{dist}(a,r) \geq 0$ and $\text{dist}(b,r) < 0$ — a is refinement, b is fallback
  • Both refinements, a closer: $\text{dist}(a,r) \geq 0 \land \text{dist}(b,r) \geq 0 \land \text{dist}(a,r) < \text{dist}(b,r)$
  • Both fallbacks, a closer: $$\text{dist}(a,r) < 0 \land \text{dist}(b,r) < 0 \land \text{dist}(a,r) < \text{dist}(b,r) $$

Simplified Rule

preferred = min(valid_providers, key=ranking_key)

def ranking_key(p, r):
    d = dist(p, r)
    if d >= 0:
        return (0, d)      # refinement tier, prefer smaller positive
    else:
        return (1, -d)     # fallback tier, prefer smaller negative

Tie-Breaking

When multiple providers have the same distance:

Default Policy

First registered wins — the provider that was registered first is selected.

Subsystem Policies

Subsystem Policy
UrnMatcher First by specificity, then by registration order
CapMatrix Strict > comparison (no ties possible)
CapBlock Strict > comparison (no ties possible)
RelaySwitch First registered wins

Avoiding Ties

Design caps to avoid ties by ensuring distinct specificities:

  • Add distinguishing tags
  • Use consistent naming conventions
  • Register more specific caps before generic ones

Examples

Exact Match Preferred

Request: cap:in=media:pdf;op=extract;out=media:object
         spec = 3

Valid providers:
  A: cap:in=media:pdf;op=extract;out=media:object     spec=3, dist=0
  B: cap:in=media:pdf;op=extract;out=media:object;v=2 spec=4, dist=+1
  C: cap:op=extract                                    spec=1, dist=-2

Ranking: A (dist=0) ≺ B (dist=+1) ≺ C (dist=-2)
Selected: A

Refinement When No Exact Match

Request: cap:op=convert
         spec = 1

Valid providers:
  A: cap:in=media:pdf;op=convert;out=media:html   spec=3, dist=+2
  B: cap:in=media:image;op=convert;out=media:png  spec=3, dist=+2
  C: cap:op=convert                                spec=1, dist=0

Ranking: C (dist=0) ≺ {A, B} (dist=+2, tie)
Selected: C

If C not available:
  {A, B} tied at dist=+2
  Selected: First registered of A or B

Fallback Only

Request: cap:in=media:pdf;v=2.0;op=extract;out=media:object;format=json
         spec = 5

Valid providers:
  A: cap:in=media:pdf;op=extract;out=media:object  spec=3, dist=-2
  B: cap:op=extract                                 spec=1, dist=-4

Ranking: A (dist=-2) ≺ B (dist=-4)
Selected: A (closer to request despite being less specific)

Preferred Cap Hints

User Preference

The system supports an optional preferred cap hint:

RelaySwitch::route_request(request, preferred_cap: Option<&CapUrn>)

When preferred_cap is provided:

  1. Find valid providers via is_dispatchable
  2. Among valid providers, check if any is is_equivalent to preferred
  3. If found, select it regardless of specificity ranking
  4. Otherwise, fall back to normal ranking

Use Cases

  • User explicitly requests a specific capability version
  • Configuration specifies a particular provider
  • Testing with known handler

Properties

Determinism

Given the same request, set of registered providers, and registration order — the selected provider is deterministic.

Stability

Adding a new provider P:

  • If P is not in Valid(r), selection unchanged
  • If P is in Valid(r), P may be selected only if it ranks higher

Monotonicity

If provider $p$ is selected for request $r$, then $p$ remains selected for any request $r'$ where $r' \preceq r$ and $\text{Dispatch}(p, r')$ still holds.

Implementation Notes

For small provider sets, linear scan is sufficient:

fn select_best(providers: &[CapUrn], request: &CapUrn) -> Option<&CapUrn> {
    let request_spec = request.specificity();

    providers.iter()
        .filter(|p| p.is_dispatchable(request))
        .min_by_key(|p| {
            let dist = p.specificity() as isize - request_spec as isize;
            if dist >= 0 {
                (0, dist)
            } else {
                (1, -dist)
            }
        })
}

For frequently queried requests, cache:

  • The valid set Valid(r)
  • The sorted ranking
  • The selected provider

Invalidate on provider registration/unregistration.

Relationship to is_comparable

The is_comparable predicate from Predicates is sometimes used for discovery but NOT for ranking:

$$ \text{is_comparable}(p, r) \;\not\!\!\implies \text{Dispatch}(p, r) $$

Comparable providers may not be dispatchable. Always check is_dispatchable first.

Summary

Concept Definition
Valid set $\{ p \mid \text{Dispatch}(p, r) \}$
Distance $\text{spec}_C(p) - \text{spec}_C(r)$
Preference Exact (0) > Refinement (+) > Fallback (-)
Tie-break First registered (default)

Ranking is policy, not semantics. The dispatch predicate defines validity; ranking determines selection among valid options.