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
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 inputout: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:
- Every pattern tag must exist in the request.
- If either side is
*, the tag matches. - 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:
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
acceptsalone: A generic provider accepts a specific request, but may not meet the request’s output requirements.conforms_toalone: A specific provider conforms to a generic request, but the request may not provide what the provider needs as input.is_comparablealone: 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
tagged-urn-rs/src/tagged_urn.rs—accepts,conforms_to,values_matchcapdag/src/urn/cap_urn.rs—accepts,is_dispatchable,cap_tags_dispatchable