cap: Documentation
Browse Sign In

Matching

Tagged URN matching, CAP direction semantics, and the dispatch predicate

Tagged URN Semantics

Generic tagged URN matching supports ?, !, and * with the full wildcard truth table (see URN Syntax).

Use this model only for TaggedUrn operations — not for Cap URN routing.

Derived Predicates

Four predicates are derived from the base relation $\preceq$:

Predicate Definition Symmetric? Use Case
accepts(a,b) $b \preceq a$ No Pattern matching: “does a accept b?”
conforms_to(a,b) $a \preceq b$ No Instance checking: “does a satisfy b?”
is_comparable(a,b) $a \preceq b \lor b \preceq a$ Yes Discovery: “are these related?”
is_equivalent(a,b) $a \preceq b \land b \preceq a$ Yes Identity: “are these the same?”

Implications

$$ \texttt{is_equivalent}(a,b) \implies \texttt{is_comparable}(a,b) $$
$$ \texttt{is_equivalent}(a,b) \implies \texttt{accepts}(a,b) \land \texttt{accepts}(b,a) $$
$$ \texttt{is_comparable}(a,b) \;\not\!\!\implies \texttt{is_equivalent}(a,b) $$
$$ \texttt{accepts}(a,b) \;\not\!\!\implies \texttt{conforms_to}(a,b) $$

Usage

// Pattern matching: does this template accept this value?
if pattern.accepts(&instance) { ... }

// Instance checking: does this value satisfy this requirement?
if instance.conforms_to(&requirement) { ... }

// Discovery: are these on the same specialization chain?
if urn_a.is_comparable(&urn_b) { ... }

// Identity: exact lookup, deduplication
if urn_a.is_equivalent(&urn_b) { ... }

CAP Direction Matching

CapUrn::accepts(pattern, request) uses media semantics for direction tags:

  • in: cap_in.accepts(request_in) — pattern’s input accepts request’s input
  • out: cap_out.conforms_to(request_out) — pattern’s output conforms to request’s output

This is asymmetric by design.

CAP Non-Direction Tag Semantics

For tags other than in/out, CapUrn::accepts does not implement the full tagged-URN ?/! table. It uses a simpler rule set:

  1. Every pattern tag must exist in the request.
  2. If either side is *, the tag matches.
  3. Otherwise values must be exactly equal.
Pattern: cap:op=extract;format=*
Request: cap:op=extract;format=pdf
Result:  match

Pattern: cap:op=extract;format=pdf
Request: cap:op=extract
Result:  no match (missing required tag)

This distinction matters: generic TaggedUrn matching and Cap tag matching are not the same operation. Cap tags use the simpler rule set because ? and ! wildcards are not used in practice for cap operation tags.

The Dispatch Predicate

For routing, none of accepts, conforms_to, is_comparable, or is_equivalent alone is sufficient. The dispatch predicate uses a three-axis check with mixed variance:

$$ \text{Dispatch}(p, r) \iff (i_r \preceq i_p) \land (o_p \preceq o_r) \land (y_r \preceq y_p) $$

Where $p$ = provider, $r$ = request, $i$ = input, $o$ = output, $y$ = cap-tags.

Axis Variance Rule Plain English
Input Contravariant request_in.conforms_to(provider_in) Provider must accept what the request sends
Output Covariant provider_out.conforms_to(request_out) Provider must produce at least what the request needs
Cap-tags Invariant $\text{request_tags} \preceq \text{provider_tags}$ Provider must have all tags the request specifies

Dispatch is NOT Symmetric

is_dispatchable(p, r) does NOT imply is_dispatchable(r, p). A text-to-text provider dispatches for a PDF-to-text request (if PDF conforms to text), but the reverse is not true.

Why Simpler Predicates Fail

  • accepts alone: A generic provider accepts a specific request, but may not meet the request’s output requirements.
  • conforms_to alone: A specific provider conforms to a generic request, but the request may not provide what the provider needs as input.
  • is_comparable alone: Being on the same chain doesn’t mean the provider can handle the request — they might be comparable but in the wrong direction.

See Dispatch for the full specification with examples.

Common Mistakes

Confusing accepts with dispatch

// WRONG: may miss output type requirements
if registered.accepts(&request) { route_here(); }

// CORRECT: checks all three axes
if registered.is_dispatchable(&request) { route_here(); }

Confusing argument order

// WRONG: backwards
if pattern.conforms_to(&instance) { ... }

// CORRECT:
if instance.conforms_to(&pattern) { ... }
// OR equivalently:
if pattern.accepts(&instance) { ... }

References