In this section

Structure

A Media URN has the form:

media:<type>[;tag=value]...

Examples:

media:                          # Identity (any media)
media:document                  # A document, in any format
media:document;ext=pdf          # A PDF: a document whose format is pdf
media:image                     # An image, in any format
media:ext=png;image             # A PNG image
media:enc=utf-8                 # Bare UTF-8 text (scalar by default)
media:fmt=json;record           # JSON object (serialization format)

Top and unit types

The media URN order has two distinguished anchors. They are not interchangeable, and confusing them flips the meaning of every cap that uses them.

media:: the top type

media:

The bare prefix with no tags. Reads as “any data type.”

  • Has no tags.
  • Every other media URN conforms_to it.
  • Specificity 0.
  • The top of the media partial order.
pub const MEDIA_IDENTITY: &str = "media:";
∀m ∈ MediaUrn, m ⪯ media:     (every media URN conforms to top)
media: ⪯ media:               (reflexive)

A cap with in=media: says “I accept any input.” A cap with out=media: says “I may produce any output.” Used on both sides, these are just the fully generic top types for the directional axes. They do not by themselves mean identity.

Under the four-axis cap model:

  • cap:effect=none is the explicit identity morphism
  • cap: and cap:in=media:;out=media: are illegal bare top forms
  • cap:<y-tags> with both directional sides at media: is a generic top-to-top transform, not identity

media:void: the unit type

media:void

Reads as “no data”: the nullary value, the type with exactly one inhabitant.

  • Has the void marker tag.
  • Distinct from media:. Top means “any A flows here”; unit means “() flows here, no meaningful payload.”
pub const MEDIA_VOID: &str = "media:void";

A cap with in=media:void does not consume data; it is driven entirely by its non-directional tags and any peer state. A cap with out=media:void produces no data; it exists for the side effect. Caps with media:void on both sides are pure side-effect commands (see CapKind: Source, Sink, Effect).

Atomicity

media:void is atomic. The parser rejects any media URN that combines the void marker tag with any other tag:

media:void                ✓
media:void;text           ✗  (parse error)
media:void;pdf            ✗  (parse error)
media:void;reason=warmup  ✗  (parse error)
media:void;heartbeat      ✗  (parse error)

There is no lattice underneath the unit. Permitting refinements would manufacture a fake taxonomy of unit values (media:void;warmup vs media:void;heartbeat etc.) and dispatch semantics would silently fork: are these different units? different effects? different commands? Refusing the syntax forecloses the question.

When a cap needs to express why or how it uses void, that information goes on the cap URN’s non-directional axis (or in cap args), never as a refinement of the media URN:

✓ cap:in=media:void;out=media:void;warmup
✓ cap:in=media:void;out=media:void;heartbeat
✓ cap:in=media:void;out=media:image;generate;target=thumbnail

✗ cap:in=media:void;reason=warmup;out=media:void
✗ cap:in=media:void;enc=utf-8;out=media:enc=utf-8

Each of the first three describes a distinct morphism (different operation tags). The last two try to pack the same distinction into the unit type itself; the parser rejects them at the media-URN layer before the cap URN ever forms.

This rule is enforced at the deepest layer: every MediaUrn constructor and from_string parse path returns a parse error on violation:

Port Error
Rust MediaUrnError::VoidNotAtomic
Go MediaUrnError{Code: ErrorMediaVoidNotAtomic}
Python MediaUrnError("media:void is atomic …")
Swift/ObjC CSMediaUrnErrorVoidNotAtomic
JS MediaUrnError(VOID_NOT_ATOMIC, …)

Top vs unit at a glance

Side type Reads as Used for
media: “any A” wildcards, generic passthrough
media:void ”()” sources, sinks, effects
concrete a specific type normal data flow

media: and media:void look superficially similar (both are “unspecific” in some sense), but they sit at opposite ends of the type lattice. media: is the maximum of the order; media:void is a leaf carrying the nullary value.


Semantic markers and the three media axes

Media URNs describe data with two kinds of tag: marker tags that declare modality or numeric capability (numeric, image/visual, audio), and three orthogonal media-URN axes that describe how the bytes are typed, serialized, and encoded.

There is no coercion model. A request for media:enc=utf-8 matches only values that carry the enc=utf-8 tag; numbers, booleans, and JSON are never implicitly stringified. Adapting a value from one format to another (number → text, JSON → CSV, text → PDF) is the job of an explicit conversion capability (e.g. cap:convert-format), never an implicit property of the type. Dispatch matches types as declared; it does not coerce.

The three media axes

Axis Tag Describes Single-valued? Examples
file type ext=<x> The on-disk FILE type no pdf, png, txt, csv
data format fmt=<x> The content SERIALIZATION format yes (≤ one fmt) json, yaml, ndjson, csv, xml, tsv, psv, cbor, msgpack
encoding enc=<x> The character ENCODING of text yes utf-8

These axes are independent and must not be conflated:

  • ext= is what the file is called on disk; it says nothing about how the bytes are structured.
  • fmt= is how the content is serialized once you look inside; a value has at most one fmt.
  • enc= is the character encoding, and its presence is how text is identified at all (see Type detection). Bare text is media:enc=utf-8.

So a CSV file sitting on disk is media:ext=csv;fmt=csv;..., while the CSV content flowing between caps is media:fmt=csv;list;record. A plain text file is media:ext=txt;enc=utf-8; bare text is just media:enc=utf-8.

Standard markers

Tag Meaning Examples
numeric Supports numeric operations integers, floats
image An image, to be looked at png, jpeg, webp, a video frame
audio Audio, to be heard wav, mp3, flac, raw PCM frames
video A video mp4, mov, mkv, webm
document Laid-out pages, sheets or slides pdf, docx, epub, xlsx

image, audio, video and document are the mediums. Each is a type of its own — media:image, media:audio, media:video, media:document — and every format of a medium carries its marker, so media:ext=png;image conforms to media:image and media:document;ext=pdf to media:document. A cap that takes any image declares media:image; an abstract cap over per-format caps declares the medium they share. Writing kept as text (Markdown, RTF, HTML) is a text file and carries no medium.

Markers are orthogonal to the three axes. A number is media:numeric (no enc=, because it is not delivered as text). A boolean delivered as text is media:bool;enc=utf-8. There is no binary marker: everything is binary at the byte level, so “binary” is not a category. The meaningful question is which axes a type carries.

Format adaptation is explicit

A capability requiring media:enc=utf-8 matches values that actually carry the enc=utf-8 tag. It does not match a bare media:numeric or media:fmt=json;record. To feed a number into a text-consuming cap, route it through an explicit conversion cap:

media:numeric ──[cap:convert-format → text]──▶ media:enc=utf-8
media:fmt=json;record ──[cap:convert-format → csv]──▶ media:fmt=csv;list;record

The conversion cap is a real node in the graph with its own input and output types. Nothing is adapted behind the dispatcher’s back.


Structural markers and defaults

Media URNs have no form= axis. Structure is represented by marker tags and by default absence:

Shape property Encoding Meaning
scalar no list tag Single value (default cardinality)
list list marker Ordered collection
opaque no record tag No internal key-value structure (default)
record record marker Key-value structure

So:

  • media:enc=utf-8 means scalar + opaque (text)
  • media:fmt=json;record means scalar + record
  • media:enc=utf-8;list means list + opaque
  • media:fmt=json;list;record means list + record

Examples

media:enc=utf-8                    # String
media:enc=utf-8;list               # Array of strings
media:fmt=json;record              # JSON object
media:integer;list;numeric         # Array of integers

Common media types

Primitives

Media URN Constant Description
media: MEDIA_IDENTITY Top: any data type (universal wildcard)
media:void MEDIA_VOID Unit: the nullary value (no data flows here)
media:enc=utf-8 MEDIA_STRING UTF-8 string
media:integer;numeric MEDIA_INTEGER Integer
media:numeric MEDIA_NUMBER Float
media:bool;enc=utf-8 MEDIA_BOOLEAN Boolean
media:record MEDIA_OBJECT Generic record/object
media:fmt=json;record MEDIA_JSON JSON object

Arrays

Media URN Constant Description
media:enc=utf-8;list MEDIA_STRING_LIST String array
media:integer;list;numeric MEDIA_INTEGER_LIST Integer array
media:list;numeric MEDIA_NUMBER_LIST Number array
media:bool;enc=utf-8;list MEDIA_BOOLEAN_LIST Boolean array
media:list;record MEDIA_OBJECT_LIST List of opaque records

Mediums and their formats

Media URN Constant Description
media:image MEDIA_IMAGE An image in any format
media:ext=png;image MEDIA_PNG PNG image
media:ext=jpeg;image MEDIA_JPEG JPEG image
media:audio MEDIA_AUDIO Audio in any format
media:audio;ext=wav MEDIA_WAV WAV audio
media:video MEDIA_VIDEO A video in any container
media:ext=mp4;video MEDIA_MP4 MP4 video
media:document MEDIA_DOCUMENT A document in any format
media:document;ext=pdf MEDIA_PDF PDF document

Matching semantics

Media URN matching follows Tagged URN semantics from Tagged URN domain.

Pattern matching

Pattern:  media:document
Instance: media:document;ext=pdf

Does instance have all tags pattern requires?
- Pattern requires: document=*
- Instance has: document=*, ext=pdf
- document present? Yes → MATCH ✓

Specificity

More tags = more specific:

spec(media:) = 0
spec(media:document) = 2             # document=* is must-have-any
spec(media:document;ext=pdf) = 6     # must-have-any (2) + exact value (4)
spec(media:document;ext=pdf;list) = 8

Conformance

media:document;ext=pdf ⪯ media:document   (a pdf is a document)
media:document ⪯ media:                   (a document conforms to identity)
media:document;ext=pdf ⪯ media:image      ✗ (not on the same chain)

Direction specs in cap URNs

When used as in or out values in Cap URNs:

Quoting

Media URNs containing ; must be quoted:

cap:in="media:document;ext=pdf";extract;out="media:record"

Identity expansion

in=* and out=* expand to media::

cap:in=*;convert;out=*
→ cap:in=media:;convert;out=media:

Dispatch

For dispatch (see Dispatch):

  • Input: Request input must conform to candidate input (contravariant)
  • Output: Candidate output must conform to request output (covariant)

Type detection

Helper methods

let urn = MediaUrn::from_string("media:fmt=json;record")?;

urn.is_json()    // true iff get_tag("fmt") == Some("json")
urn.is_yaml()    // true iff get_tag("fmt") == Some("yaml")
urn.is_csv()     // true iff get_tag("fmt") == Some("csv")
urn.is_void()    // true iff the `void` marker tag is present (unit type)
urn.is_top()     // true iff the URN has no tags at all (top type)

The format predicates (is_json / is_yaml / is_csv) read the fmt= axis: each is just get_tag("fmt") == Some(<format>). There is no is_text() and no is_binary(). Everything is binary at the byte level, so “text vs binary” is not a real distinction. Text is identified by the presence of the enc= tag:

urn.has_tag("enc")          // true → this value is text
urn.get_tag("enc")          // Some("utf-8") → the encoding, if any

There is no is_utf8 method; callers inspect get_tag("enc") directly.

is_void and is_top are the predicates the CapKind classifier consults. Together they let any caller reason about whether a media URN is a concrete type, the wildcard, or the unit without parsing strings.

Tag queries

urn.has_tag("enc")          // true (text)
urn.has_tag("fmt")          // true (serialized)
urn.has_tag("list")         // false
urn.has_tag("record")       // true

Adding new types

When defining a new media type:

  1. Determine the content format (fmt=) and/or encoding (enc=): how is this value serialized, and is it text?
  2. Determine structure/cardinality: default scalar vs list, default opaque vs record
  3. Add constant if frequently used
  4. Document in media catalog

Example: custom type

// A new type for structured logs (serialized as JSON)
const MEDIA_LOG_ENTRY: &str = "media:log-entry;fmt=json;record";

// Serialized as JSON, structured as record

Partial order position

Media URNs form a partial order (specialization order). media: is the unique top; media:void is a leaf, distinct from every concrete type:

                    media:                          (top — any A)
                  /        \
          media:enc=utf-8   media:void               (leaf — unit ())
            /         \
  media:integer;numeric  media:fmt=json;record
                                      |
                         media:fmt=json;list;record

More tags = lower in the order = more specific. media:void carries exactly one tag (void) and so sits at specificity 2 (one must-have-any tag, plus the prefix); it is not a refinement of any concrete type.


Summary

Concept Definition
Structure media:<type>[;tag=value]...
Top media:: universal wildcard, max of the partial order, “any A”
Unit media:void: nullary value, leaf of the partial order, “()”
Media axes ext= (file type), fmt= (serialization), enc= (encoding)
Semantic markers numeric, visual/image, audio, video
Structural markers list and record; scalar and opaque are defaults by absence
Matching Tagged URN semantics (truth table)
Specificity Sum of per-tag scores

Media URNs describe data types. They are used:

  • In Cap URN in/out specs (where the choice between media:, media:void, and a concrete type determines the cap’s kind)
  • As argument identifiers
  • For type matching in dispatch