Struttura prodotto
Un cap URN è una quadrupla sul dominio dei tagged URN:
C = U × U × U × E
Per un cap URN c ∈ C:
c = (i, o, y, e)
Dove:
i ∈ U: dimensione di input (il valore del tagin, un media URN)o ∈ U: dimensione di output (il valore del tagout, un media URN)y ∈ U: cap-tag non direzionali (op, ext, model, language, ecc.)e ∈ E: effetto sull’identità del media/tipo a runtime
Definizione di una cap: alias e abstract
Il cap URN è l’identità strutturale della cap. Oltre all’URN, una definizione di cap porta due campi che non fanno parte dell’URN:
aliases: una lista non vuota di nomi globalmente univoci, in minuscolo ([a-z0-9._-]+, senza due punti). Gli alias sono il livello DNS della cap: sono l’unica fonte dei nomi di una cap rivolti alle persone, usati sia dalla CLIcapdagdell’intera fabric sia dalla CLI diretta della cartuccia.aliasesè obbligatorio e non vuoto.abstract: un booleano facoltativo (predefinitofalse). Una cap astratta è un ombrello di dispatch con input generico: non è mai supportata da una cartuccia e non compare mai come arco eseguibile di un grafo. Il suo meccanismo resolve → detect → narrow → dispatch è specificato in Dispatch §”Cap astratte”.
Entrambi i campi sono governati da invarianti verificati alla pubblicazione (univocità globale degli alias e copertura delle cap astratte) specificati in Regole di validazione.
Rappresentazione come stringa
Forma canonica
Un cap URN si serializza come:
cap:in="<media-urn>";out="<media-urn>";effect=<effect>;<cap-tags>
Esempi:
cap:effect=none
cap:extract;in="media:document;ext=pdf";out="media:record"
cap:in="media:enc=utf-8";out="media:fmt=json;record";prompt
Tag direzionali
Le coordinate in, out ed effect sono strutturali:
| Tag | Scopo | Predefinito |
|---|---|---|
in |
Tipo di media in input | media: (qualsiasi) |
out |
Tipo di media in output | media: (qualsiasi) |
effect |
Regola di inferenza del media/tipo a runtime | declared |
Tag non direzionali
Tutti gli altri tag formano la dimensione y. Nessun tag in y ha un significato
funzionale per il protocollo. Soltanto in, out ed effect partecipano al
dispatch, alla conformità e all’inferenza dell’output a runtime. I cap-tag sono metadati
descrittivi arbitrari: raffinano la definizione della cap (quindi due cap con
y diverso sono cap diverse), ma nessuna chiave di tag è privilegiata. Tag
descrittivi comuni includono nomi di operazioni (extract, generate),
codici di lingua, identificatori di modello e suggerimenti. Tutti sono uguali per il
protocollo.
Parsing e normalizzazione
L’elaborazione dei cap URN distingue tre forme:
| Forma | Descrizione |
|---|---|
| Sintassi di superficie | Ciò che gli utenti possono scrivere (può omettere in/out/effect) |
| Forma canonica | Rappresentazione normalizzata (valori predefiniti strutturali applicati, effetto predefinito omesso) |
| Oggetto della validazione | Struttura dopo la normalizzazione, su cui le regole verificano |
Sintassi di superficie (input accettato)
Gli utenti possono omettere i tag direzionali o scrivere esplicitamente il wildcard banale. Queste sono tutte sintassi di superficie valide:
cap:test
cap:in=media:;out=media:;test
cap:in=*;test;out=*
cap:effect=none
Normalizzazione nella forma canonica
Il parsing produce un unico rappresentante canonico per ogni cap. Due regole governano gli assi direzionali:
- I tag direzionali mancanti o wildcard si risolvono internamente in
media:. - Quando
insi risolve nel media URN top (media:), il segmento viene omesso nella forma canonica. Lo stesso vale perout. Il valore interno restamedia:; la forma resa semplicemente non lo mostra. - Un
effectmancante si risolve internamente indeclarede viene omesso nella forma canonica. Gli effetti non predefiniti vengono conservati.
| Sintassi di superficie | Forma canonica |
|---|---|
cap:test |
cap:test |
cap:in=media:;test;out=media: |
cap:test |
cap:in=*;test;out=* |
cap:test |
cap:in=media:pdf;extract;out=media:record |
cap:extract;in=media:pdf;out=media:record |
cap:in=media:;out=media:;effect=none |
cap:effect=none |
Il valore * nei tag direzionali si espande in media::
in=* → in=media:
out=* → out=media:
Questo garantisce che media: sia l’unico top dell’ordine direzionale, e che
la forma canonica sia identica byte per byte in ogni modo di scriverla.
Oggetto della validazione
Le regole di validazione (CU1, CU2 in Regole di validazione) si applicano alla forma canonica, non alla sintassi di superficie. Dopo la normalizzazione:
ineoutsono sempre presenti- i loro valori sono media URN validi
Virgolette
I valori direzionali che contengono ; devono essere racchiusi tra virgolette:
cap:in="media:bytes;document;ext=pdf";extract;out="media:record"
Senza virgolette, media:bytes;document;ext=pdf verrebbe analizzato in modo errato.
Tipi di cap
La struttura (i, o, y, e) ammette una classificazione in cinque tipi ottenuta esaminando
gli assi direzionali. La classificazione è soltanto logica: il
protocollo di dispatch non si dirama in base al tipo. Strumenti, interfacce utente, planner e
lettori umani la usano per parlare di ciò che una cap fa senza
ricavare di nuovo le regole ogni volta.
Due tipi di ancoraggio fanno emergere la tassonomia:
media:è il tipo top, il wildcard universale sull’ordine dei media URN. Ogni altro media URN èconforms_torispetto a questo. Un lato tipizzato comemedia:si legge come “un A qualsiasi”: non c’è alcun vincolo su quali dati vi scorrono.media:voidè il tipo unità, il valore nullario. Un lato tipizzato comemedia:voidsi legge come “()”: nessun dato significativo vi scorre. Non significa “non valido” o “assente”; è il tipo con esattamente un valore.
I cinque tipi
| Tipo | i |
o |
e |
y |
Si legge come |
|---|---|---|---|---|---|
Identity |
media: |
media: |
none |
vuoto | A → A |
Source |
media:void |
non void |
qualsiasi | qualsiasi | () → B |
Sink |
non void |
media:void |
qualsiasi | qualsiasi | A → () |
Effect |
media:void |
media:void |
qualsiasi | qualsiasi | () → () |
Transform |
qualsiasi altro | qualsiasi altro | qualsiasi valore ammesso | qualsiasi | A → B |
Ogni implementazione espone questa classificazione tramite un metodo kind()
su CapUrn (o il suo equivalente nel port del linguaggio), che restituisce un valore
dell’enum CapKind.
L’identità è esplicita
L’identità non è la stessa cosa della cap completamente generica da top a top.
cap:effect=noneindica la vera identità categoriale
Quindi:
| URN | Tipo | Lettura |
|---|---|---|
cap:effect=none |
Identity | A → A per qualsiasi A |
cap:passthrough |
Transform | trasformazione generica da top a top con raffinamento sull’asse y |
La forma top dichiarata con tutti i valori predefiniti non è ammessa:
| URN | Stato |
|---|---|
cap: |
inammissibile / non ammessa |
cap:in=media:;out=media: |
inammissibile / non ammessa |
La cap identità è:
pub const CAP_IDENTITY: &str = "cap:effect=none";
Ogni capset deve includere la cap identità (vedi CU1 in Regole di validazione).
Ammissibilità dell’effetto
Un effetto non predefinito è una promessa strutturale sulla relazione fra
in= e out= dichiarati, e una promessa incoerente viene rifiutata alla
costruzione (validate_admissible, applicata da ogni parser di CapUrn in
ogni linguaggio, quindi anche il publisher della fabric la rifiuta, poiché
la pubblicazione analizza ogni cap URN):
| Effetto | Condizione di ammissibilità |
|---|---|
none |
l’in= dichiarato deve essere conform_to rispetto all’out= dichiarato, perché l’output ha il tipo dell’input e la dichiarazione deve essere coerente con questo |
patch |
il delta di coordinate out − in deve essere derivabile, e riapplicarlo a in= deve produrre un tipo conforme a out= (la verifica del testimone) |
declared |
sempre ammissibile (fatta salva la regola sulla forma top nuda vista sopra) |
cap:in="media:document;ext=pdf";out="media:enc=utf-8";effect=none non è quindi
ammessa: promette che il tipo di output è il tipo di input mentre dichiara un
output contraddittorio.
Il contratto dell’effetto a runtime
L’effetto non è un’indicazione facoltativa. Due meccanismi vi vincolano ogni esecuzione:
- Etichette di risposta derivate. Il runtime di una cartuccia ricava il media URN
dello STREAM_START di risposta di una cap dall’effetto dichiarato
(
derive_response_media):declared→ l’out=dichiarato;none→ l’in=dichiarato;patch→ l’in=modificato dalla patch. Le operazioni non scelgono le etichette di output. - La verifica dell’engine. Alla ricezione dello STREAM_START di output di una cap (prima
di inoltrare, rendere persistente o raccogliere), l’engine verifica il
media URN emesso con
CapUrn::is_conformant_runtime_output, l’unico predicato di conformità all’effetto:none/patchrichiedono l’equivalenza dei tag con l’output inferito (l’effetto determina interamente il tipo, quindi un’emissione più specifica viola comunque la dichiarazione);declaredrichiede la conformità all’out=dichiarato (più specifico è ammesso, più generico fallisce). Una violazione è un fallimentointernalbloccante che indica la cap, l’effetto e il valore atteso rispetto a quello effettivo.
Il raffinamento del tipo a valle operato dal planner
(CapUrn::infer_runtime_output_media, vedi
Planner) si basa esattamente su questo contratto; la
verifica è ciò che rende fondato questo affidamento. Vedi
Input e output per i meccanismi a runtime.
Source, sink, effect: void come unità
media:void permette alla struttura (i, o, y, e) di esprimere cap che non sono
trasformatori di dati nel senso convenzionale.
- Una Source ha
i = media:voideo ≠ media:void. Produce un valore senza un input significativo. Esempi: preriscaldare un modello (cap:in=media:void;out=media:model-artifact;warm), search-models, list-compatible-models, generatori guidati dalla sola configurazione. - Un Sink ha
i ≠ media:voideo = media:void. Assorbe un valore senza un output significativo. Esempi: cap di scarto, log verso la telemetria, aggiunta a un indice. - Un Effect ha entrambi i lati
media:void. Si legge come() → (). Una cap nullaria a effetto collaterale: warm-cache, ping, health-check, initialize-index, sync-registry, log-heartbeat. Valida nella teoria dei tipi; utile in pratica per operazioni in stile comando il cui unico scopo è l’effetto collaterale.
In tutti e tre i casi la dimensione y può portare qualsiasi tag. media:void
su un lato è una scelta direzionale; y continua a raffinare la
definizione della cap.
Transform: il caso predefinito
Transform è il caso generale: almeno un lato è un media URN non void,
e la cap non è né l’identità esplicita né la cap generica
da top a top. Transform copre la maggior parte
delle cap nella pratica: gli elaboratori
di dati (extract, render, generate-text, embed, convert).
Perché la distinzione è soltanto logica
Il dispatch (i predicati accepts / conforms_to) opera sulla
struttura di cap (i, o, y, effect) in modo uniforme. Non consulta CapKind. Una
Source e una Transform il cui in specializza per caso il
media:void di un pattern corrispondono secondo le stesse regole; il tipo è una
descrizione del risultato, non una dimensione di instradamento.
Questa separazione è importante perché:
- Il protocollo resta semplice (una sola regola di corrispondenza su quattro coordinate strutturali).
- Strumenti e persone possono comunque ragionare sulle cap in termini semplici (“questa è una Source: non prende input”).
- Il tipo non può divergere: è sempre derivabile dall’URN. Non c’è alcun campo separato da mantenere allineato, né alcun flag che una cartuccia potrebbe impostare in modo errato.
Semantica delle dimensioni
Le quattro coordinate strutturali (i, o, y, e) corrispondono a quattro
domande indipendenti. La tassonomia dei tipi di Tipi di cap è ciò che emerge quando
si risponde a quelle domande.
Dimensione di input (i)
in risponde a: quali dati consuma questa cap?
| Valore | Significato |
|---|---|
media:document;ext=pdf |
“Richiede un PDF.” |
media: |
“Accetta qualsiasi input.” (top; Identity / generica) |
media:void |
“Non prende dati in input.” (unità; Source / Effect) |
media: e media:void non sono intercambiabili: uno dice “qui va bene
qualsiasi cosa”, l’altro dice “qui non scorre nulla”.
Dimensione di output (o)
out risponde a: quali dati produce questa cap?
| Valore | Significato |
|---|---|
media:json |
“Produce JSON.” |
media: |
“Può produrre qualsiasi output.” (top) |
media:void |
“Non produce dati.” (unità; Sink / Effect) |
Dimensione dei cap-tag (y)
y risponde a: che cosa specifica, raffina o etichetta questa cap oltre alla
sua firma dei dati?
cap:...;extract;target=metadata
y è a sua volta un tagged URN (senza prefisso), con la stessa semantica
di corrispondenza di qualsiasi altro tagged URN. I tag in y sono arbitrari. Nessuna
chiave ha un significato funzionale per il protocollo. Distinguono cap
con la stessa firma dei dati (es. una cap extract e una cap summarize
possono avere entrambe media:document;ext=pdf → media:enc=utf-8 e restare distinte
perché il loro y è diverso).
Un y non vuoto è anche ciò che distingue cap:passthrough
(Transform) dalla forma top nuda rifiutata, anche se gli
assi direzionali coincidono.
Accesso ai componenti
Estrarre le dimensioni
Data una stringa di cap URN, si estrae:
let cap = CapUrn::from_string("cap:extract;in=media:pdf;out=media:record")?;
let input: &str = cap.in_spec(); // "media:document;ext=pdf"
let output: &str = cap.out_spec(); // "media:record"
let has_extract: bool = cap.has_marker_tag("extract"); // true
let kind: CapKind = cap.kind()?; // CapKind::Transform
kind() ricava la classificazione CapKind dalla struttura
(i, o, y, e) analizzata. Restituisce un errore solo in caso di stato internamente
incoerente (che la costruzione di CapUrn impedisce), il che è un segnale
netto che qualcosa a monte è guasto.
Tipi dei componenti
| Componente | Tipo | Accesso |
|---|---|---|
| Input | Stringa di media URN | in_spec() |
| Output | Stringa di media URN | out_spec() |
| Cap-tag | Mappa chiave-valore | tags, tag(key) |
| Tipo | Enum CapKind |
kind() |
Specificità
La specificità dei cap URN è definita in
Specificità. I cap URN hanno quattro coordinate
strutturali, ma il punteggio numerico di specificità ordina soltanto le tre
coordinate pesate che portano tag, out, in e y. Queste tre usano
la stessa scala per tag a sei forme (?x:0, x?=v:1, x (=x=*):2,
x!=v:3, x=v:4, !x:5), con i pesi degli assi:
spec_C(c) = 10_000 * spec_U(c.out)
+ 100 * spec_U(c.in)
+ spec_U(c.y)
La priorità lessicografica (out, in, y) riflette l’intento di instradamento:
produrre cose diverse è la differenza semantica più grande fra
due cap; consumare cose diverse viene dopo; i metadati descrittivi dell’asse y
vengono per ultimi. Due ordini di grandezza separano ciascun asse, così che
somme per asse fino a ~99 restino nella propria posizione di cifra, rendendo
l’intero sia totalmente ordinato sia decodificabile a vista (40205 si legge
come out=4, in=2, y=5).
La coordinata effect è strutturale ma non entra nel punteggio. Cambia il
comportamento del dispatch e del runtime, ma non viene trattata come una dimensione
di raffinamento graduata per il ranking.
Esempi per tipo, con le somme delle tre coordinate pesate
(out, in, y) e il
totale pesato:
| URN | Tipo | (out, in, y) | spec_C |
|---|---|---|---|
cap:?effect |
Transform | (0, 0, 0) | 0 |
cap:extract |
Transform | (0, 0, 2) | 2 |
cap:extract;in=media:pdf;out=media:record |
Transform | (2, 2, 2) | 20202 |
cap:in=media:void;out=media:void;ping |
Effect | (2, 2, 2) | 20202 |
cap:extract;target=metadata |
Transform | (0, 0, 6) | 6 |
La richiesta esplicita completamente non vincolata cap:?effect si trova a
specificità 0. L’identità è l’esplicito cap:effect=none, non
la forma top nuda.
Struttura di ordine parziale
I cap URN formano un ordine parziale (ordine di specializzazione) nello spazio
prodotto. La richiesta esplicita completamente non vincolata cap:?effect è il top:
cap:?effect (richiesta top)
|
cap:extract (Transform)
/ \
cap:extract;in=media:document;ext=pdf cap:extract;out=media:record
\ /
cap:extract;in=media:pdf;out=media:record
|
cap:extract;in=media:pdf;out=media:record;target=metadata (più specifica)
L’ordinamento deriva dalla relazione di dispatch (vedi
Dispatch). Nota che il tipo può cambiare man mano che
si scende nel reticolo: cap:effect=none è Identity, mentre
gli altri raffinamenti sono Transform/Source/Sink/Effect secondo la loro struttura.
Relazione con i media URN
I valori direzionali sono media URN
I valori dei tag in e out sono a loro volta media URN:
cap:in="media:bytes;document;ext=pdf";out="media:record"
↑ ↑
Media URN Media URN
La corrispondenza usa la semantica dei media URN
Quando si confrontano i valori direzionali, si usa la corrispondenza dei media URN:
let candidate_in = MediaUrn::from_string("media:bytes")?;
let request_in = MediaUrn::from_string("media:bytes;document;ext=pdf")?;
// Per il dispatch: request_in deve essere conforme a candidate_in
request_in.conforms_to(&candidate_in) // true
Regole di validazione
I cap URN devono soddisfare (da Regole di validazione):
- CU1: devono avere i tag
ineout(garantito tramite la normalizzazione) - CU2: i valori direzionali devono essere media URN validi oppure
*
Schemi comuni per tipo
Questa sezione percorre i cinque tipi con esempi concreti e idiomatici.
Identity
cap:effect=none
Il morfismo identità. Completamente generico su in, out e y, con una
promessa esplicita effect=none. Obbligatorio in tutti i capset.
Transform: elaboratore di dati tipizzati
cap:extract;in=media:pdf;out=media:record
cap:generate;constrained;in=media:enc=utf-8;language=en;out=media:json
cap:render-page-image;in=media:pdf;out=media:image
È il tipo più comune: dati reali entrano ed escono, e la
dimensione y etichetta l’operazione e gli eventuali modificatori.
Source: generatore
cap:in=media:void;out=media:model-artifact;warm
cap:in=media:void;out=media:model-list;list-compatible-models
cap:in=media:void;out=media:embeddings-dim;numeric;target=embeddings-dim
media:void sul lato di input: la cap produce un valore guidato dal
suo y (tag di configurazione, argomenti, stato del peer) invece che da un
input ricevuto in pipe.
Sink: consumatore
cap:discard;out=media:void
cap:in=media:json;log;out=media:void
media:void sul lato di output: la cap assorbe un valore ma
non fornisce dati al flusso a valle. Utile come terminatore
di un grafo.
Effect: effetto collaterale nullario
cap:in=media:void;out=media:void;ping
cap:in=media:void;out=media:void;warm-cache
cap:in=media:void;out=media:void;health-check
Entrambi i lati sono media:void. Lo scopo della cap è interamente l’effetto
collaterale: il protocollo non trasporta dati in nessuna direzione, soltanto
l’invocazione. Si legge come () → ().
Riepilogo
| Concetto | Definizione |
|---|---|
| Struttura | C = U × U × U × E |
| Componenti | (in, out, y, effect) |
| Tipo top | media:, il wildcard universale per entrambe le direzioni |
| Tipo unità | media:void, il valore nullario (su questo lato non scorrono dati) |
| Identità | cap:effect=none |
| Forma nuda non ammessa | cap: e cap:in=media:;out=media: sono inammissibili |
| Valori direzionali predefiniti | Mancante o * → media:; la forma canonica omette in/out quando entrambi sono media: nelle cap ammissibili |
| Assi funzionali | in, out ed effect partecipano al dispatch e alla tipizzazione a runtime; y è un metadato arbitrario |
| Tipi | Identity, Source, Sink, Effect, Transform (soltanto logici) |
I cap URN estendono i tagged URN con una struttura a quattro dimensioni. La relazione di dispatch (documento successivo) definisce come queste dimensioni interagiscono per l’instradamento. Una volta definito il dispatch, più cap URN possono essere collegati in un grafo di flusso dei dati e serializzati tramite la notazione delle macchine.