WAI Extension: AI Usage Preferences and Consumption Claims
Mirrored from the canonical text at commit b1681667 ().
Status: Draft. Registers the record
wai.ai.usage: AI usage preferences for media, bound to the bytes they govern, and the signed statement of an agent that consumed media. A usage statement carries, verbatim, the preferences of three published vocabularies: the AI usage preference vocabulary ofdraft-ietf-aipref-vocab-08, in its exemplary Structured Field form; the TDM Reservation Protocol’stdm-reservationandtdm-policy(Final Community Group ReportCG-FINAL-tdmrep-20240510); and the entries of thecawg.training-miningassertion (Training and Data Mining Assertion, version 1.1). WAI adds no category to any of them. The statement rides in an envelope’s manifest, where the object’s receipt signs it with the content, so it cannot be removed without the object failing its receipt; in a room usage record,WAU1, that the room authority signs; and in a room grant, as the terms one principal is granted. An HTTP origin writes theContent-Usagefield ofdraft-ietf-aipref-attach-05and the TDMRep fields from the signed statement, and a MoQ catalog states it for a track before a sink subscribes. One precedence rule decides a use: a grant’s terms, then every signed statement, the most restrictive governing, then unsigned statements where nothing is signed. An agent that consumed objects signs a consumption claim, the jwp-receipts claim classconsumption, naming the objects by content hash, the term it acted under in each vocabulary, its key as adid:key, the statements it saw and the grant it held; a publisher verifies it against the objects, and a relay or gateway MAY require one before it serves an agent. No new transport. The reference implementation is theai_usagemodule ofwai-rs(featureai_usage), with the class’s body inclaim_receipt; the corpus islive-conformance/usage/, and its second implementation islive-conformance/ai_usage_verify.py. Keywords MUST, MUST NOT, SHOULD, MAY are RFC 2119/8174.Texts read for this revision, each pinned to the version named:
draft-ietf-aipref-vocab-08(14 September 2026) anddraft-ietf-aipref-attach-05(19 August 2026), Internet-Drafts of the IETF AI Preferences Working Group, both Working Group documents intended for Proposed Standard and neither yet submitted to the IESG; the vocabulary marks its §3 and §4 as not yet having the group’s consensus. RFC 9651 (Structured Field Values for HTTP). The TDM Reservation Protocol, Final Community Group Report of 10 May 2024, the report’s latest. The Creator Assertions Working Group’s Training and Data Mining Assertion, version 1.1, ratified 16 May 2025, the current version. A section number of one of these texts is that version’s.
1. Scope
In scope: the usage statement, its three vocabularies, how each is read and what each says about a use (§3); where a statement is carried: an envelope, a room, a grant, an HTTP response and a MoQ catalog (§4); the precedence rule and what a conflict means (§5); the consumption claim (§6); the gate a relay or gateway applies before serving an agent (§7); and verification (§8).
Out of scope: whether a preference is followed, which the vocabulary leaves to its recipient
(draft-ietf-aipref-vocab-08 §3.2), and which this extension makes evidence of, not a duty;
the legal effect of a preference or of a claim; how a crawler or an agent is recognised as one
(§7.1); a profile of the agent protocols that fetch media, which this revision does not define;
and the robots.txt rule of draft-ietf-aipref-attach-05 §3, which is the origin’s and binds no
object (§4.4).
Relationship to the core spec: wai.ai.usage is a record (SPEC §5): a
signed record a WAI tool emits and verifies. It names no payload format and is not
dispatchable. The manifest member ai_usage (§4.1) is an OPTIONAL member under SPEC §8’s rule
for MINOR revisions.
Relationship to jwp-receipts: the envelope’s statement is signed by the
object’s receipt (§2.1 there); the consumption claim is a claim receipt of the class
consumption (§2.4.4 there), on that extension’s envelope, canonical form, signature and
chain, with the body and class rules of §6 here.
Relationship to live-rooms: the room descriptor’s layout is unchanged. A
room’s statement is a record of its own, chained like the review policy of
live-moderation §3.4, and a grant states its principal’s terms in the
attribute ai_usage (live-rooms §4.4).
2. Terms
- Vocabulary: one of
aipref,tdmrepandcawg, the three sources §3 carries. - Term: what a use is named by in a vocabulary: an
aiprefusage category label (train-ai,ai-useorsearch,draft-ietf-aipref-vocab-08§6.1); thetdmreppropertytdm-reservation, which governs text and data mining as a whole; or a key of acawg.training-miningassertion’s entries. - Preference: what a vocabulary says about one term: allow, disallow or
unknown (
draft-ietf-aipref-vocab-08§3). - Statement: a JSON object of §3 holding one or more vocabularies.
- Signed statement: one of an envelope whose receipts verify (§4.1), or of a room usage record that verifies (§4.2).
- Agent: a party that consumes media by automated means, for any use a vocabulary names.
An agent principal in a room is one whose grant carries the attribute
ai_usage(§4.3). - Content hash: an object’s jwp-receipts §2.1 content hash, 32 bytes, written as 64 lowercase hexadecimal digits in JSON.
Integers are little-endian. A digest is SHA-256 (FIPS 180-4), 32 bytes. Ed25519 is RFC
8032’s, verified strictly (SPEC §7 Signatures). The canonical form of a
JSON value is its JCS serialisation (RFC 8785) as jwp-receipts §2.4.3 restricts it: strings,
unsigned integers, null, arrays and objects.
3. The usage statement
3.1 Members
A statement is a JSON object with one or more of these members and no other:
| member | value | source |
|---|---|---|
aipref | an object: revision, value | draft-ietf-aipref-vocab-08 |
cawg | an object: revision, entries | Training and Data Mining Assertion |
tdmrep | an object: revision, tdm-reservation, tdm-policy | the TDM Reservation Protocol |
Each vocabulary keeps its own terms and its own preferences. A statement maps no term of one onto a term of another, and a WAI tool MUST NOT write a term none of them defines.
3.2 aipref
revision: the stringdraft-ietf-aipref-vocab-08.value: a statement of preference in the vocabulary’s exemplary serialisation (draft-ietf-aipref-vocab-08§6), as the text an HTTPContent-Usagefield would carry (draft-ietf-aipref-attach-05§2): for exampletrain-ai=n, search=y. It is 1 to 1024 characters, each U+0000 to U+007F (§6.3 there: the syntax is ASCII), and it MUST parse as a Dictionary (§3.3).
The preference of a term is read as draft-ietf-aipref-vocab-08 §6.5 has it: the Dictionary’s
member whose key is the term’s label, its parameters disregarded, gives allow when its value
is the Token y, disallow when it is the Token n, and unknown otherwise; a label
absent is unknown, and a key that is not one of the three labels is ignored (§6.4 there). When
a key repeats, the Dictionary keeps its last value (RFC 9651 §4.2.2), so train-ai=n, train-ai=y
allows.
3.3 The Dictionary
value parses as RFC 9651 §4.2 parses a field of type Dictionary: its characters are bytes
(§4.2 step 1, which fails on a byte above 0x7F); leading spaces are discarded; the Dictionary is
parsed by §4.2.2, with its keys (§4.2.3.3), parameters (§4.2.3.2), inner lists (§4.2.1.2) and
every bare item: Integer and Decimal (§4.2.4), String (§4.2.5), Token (§4.2.6), Byte Sequence
(§4.2.7), Boolean (§4.2.8), Date (§4.2.9) and Display String (§4.2.10); leading spaces are
discarded again; and any character left fails. RFC 9651 leaves two checks of a Byte Sequence
to the parser (§4.2.7); here the sequence parses when its content, the characters between its
colons, is characters of the base64 alphabet (RFC 4648 §4) followed by at most two =, with
the alphabet characters numbering other than one more than a multiple of four. Neither padding
nor pad bits are checked.
draft-ietf-aipref-vocab-08 §6.5.1 reads a value that does not parse as unknown for every
term. A statement does not carry one: a signer whose preference would be read as unknown
throughout has made a mistake that binding the statement would preserve, so it is refused.
3.4 cawg
revision: the string1.1.entries: an object of 1 to 32 members, the assertion’sentriesmap (Training and Data Mining Assertion 1.1 §3.2), member for member. Each key is 1 to 255 bytes of components separated by single., a component being one or more ofa–z,A–Z,0–9,_and-; a key beginningcawg.is one of the four the assertion defines,cawg.data_mining,cawg.ai_inference,cawg.ai_generative_trainingandcawg.ai_training, since it reserves the prefix (§3.1 there). Each value is an object holdinguse, one ofallowed,notAllowedandconstrained, and optionallyconstraint_info, 1 to 1024 bytes of UTF-8 (the member the assertion’s CDDL names; its prose spells itconstraints_info).
A term is a key: allowed is allow; notAllowed is disallow; constrained is
disallow, since the assertion treats it as notAllowed in the absence of additional
information (§3.1 there), which a grant can give (§5.2); a key absent is unknown. The
assertion’s metadata map is not carried.
3.5 tdmrep
revision: the stringCG-FINAL-tdmrep-20240510.tdm-reservation: the integer 1, TDM rights are reserved, or 0, they are not (the protocol’s §5.1). The protocol treats any other value as unset; a statement carries none.tdm-policy:null, or the URL of the rightsholder’s TDM policy (the protocol’s §5.2): 8 to 2048 bytes of!to~(0x21–0x7E), beginninghttps://orhttp://.
The one term is tdm-reservation: 1 is disallow and 0 is allow. tdm-policy is
carried for whoever seeks a licence and is not evaluated.
3.6 Reading a statement
A statement is read from JSON in which no object names a member twice. It is refused at the first of these that holds:
- It is not an object, it has no member, it has a member §3.1 does not list, or a
vocabulary’s object has a member absent, a member its section does not list, or a member
of another type or outside its range:
usage_malformed. Arevisionthat is a string is in range here; inaipref, avaluethat does not parse (§3.3) is not. - A vocabulary’s
revisionis other than the string its section names:usage_revision_unknown. - Its canonical form is longer than 4096 bytes:
usage_malformed.
So a statement with a malformed tdmrep and an unknown aipref revision is refused
usage_malformed. The digest of a statement is SHA-256 over its canonical form.
4. Carriage
4.1 The envelope: the manifest member ai_usage
A WAI1 or WAI2 manifest (SPEC §3, §7.1) MAY carry, at its top level, the
member ai_usage, a statement. It applies to the object: every rendition and companion of a
WAI2. A reader of an earlier revision ignores it (SPEC §8); a malformed one leaves the
manifest readable, and this extension refuses the statement, not the envelope.
The member is inside the envelope’s bytes, and the object’s content hash covers them (jwp-receipts §2.1): the group receipt that includes the object signs the statement with the content. An object whose statement is altered, added or removed no longer hashes to the content hash its receipt names, and fails its receipt. A verifier given an envelope and its receipts:
- accepts the receipts as jwp-receipts §3 steps 1 to 5 do, the envelope hashing to the
object receipt’s
content_hashexcepted; a refusal there isreceipt_invalid; - requires the envelope to hash to that
content_hash: otherwiseusage_unbound; - reads the manifest’s
ai_usage, where present, by §3.6. A manifest that does not read (SPEC §2) holds no statement that can be read:usage_malformed.
An object that passes all three is held, with its statement signed by the group
receipt’s signer_pubkey, or with none. A publisher that states a preference for an object writes the
member before it receipts the object. An envelope that carries no receipt carries an unsigned
statement, which §5.3 reads as it reads an HTTP field.
4.2 A room: the room usage record WAU1
The room authority states the room’s preference in a room usage record:
| field | size | meaning |
|---|---|---|
magic | 4 | WAU1 (ASCII) |
version | 1 | 1 in this revision |
room | 32 | the room id (live-rooms §3.2) |
prev | 32 | the digest of the record this one replaces; 32 zero bytes for the first |
effective | 8 | u64: the room-clock instant from which it applies; 0 for the first |
statement | 2 + n | a u16 length, then the statement’s canonical form, 2 to 4096 bytes |
sig | 64 | Ed25519 by the room descriptor’s authority over the 18 bytes wai:ai-usage-room (ASCII) and 0x01, followed by every byte from magic through statement |
The record’s digest is SHA-256 over the bytes from magic through statement. A reader
reads exactly the bytes it is given, in the order above, and refuses at the first of these that
holds: fewer than 4 bytes, truncated; a magic other than WAU1, malformed; no byte after
the magic, truncated; a version other than 1, unknown_version; the bytes end before a field,
truncated; bytes after sig, malformed. It then reads statement as JSON and by §3.6
(usage_malformed, usage_revision_unknown), and refuses bytes that are not the canonical form
of what they hold (usage_malformed). Then room is the room id (wrong_room), and the
signature verifies under the authority (bad_key, bad_signature).
A verifier is given a room’s records in a list. The first has prev zero and effective 0;
each later one has as prev the digest of the one before it, and an effective above that
one’s. A record that breaks this is refused room_usage_unlinked. The record in effect at
room-clock instant t is the last whose effective is at or below t. A record is replaced,
never amended: as draft-ietf-aipref-attach-05 §3.3 has it for robots.txt, a change applies
from its instant on and never to what was published before.
An object is the room’s when it is given with the room (§8). It is governed at its manifest’s
live.t (live-ingest §6), an integer; an object of the room whose manifest
has none is governed by every record in the list.
4.3 A grant’s terms: the attribute ai_usage
A room grant MAY carry the attribute ai_usage (live-rooms §4.4), whose value is the canonical
form of a statement: the terms the authority grants that principal. They are an
arrangement in the sense of draft-ietf-aipref-vocab-08 §5.2, which overrides a statement of
preference for the uses it names. A grant whose attribute does not read by §3.6, or is not the
canonical form of what it holds, is refused grant_usage_malformed, and its principal holds no
terms. The attribute is signed with the grant (live-rooms §4.2), and the 1024 bytes the grant’s
attributes take bound the terms.
4.4 HTTP: fields mapped from the signed statement
An origin that serves an object (http-delivery §5) whose envelope carries
a statement SHOULD send, for a GET or HEAD of it:
- for
aipref:Content-Usage:and the statement’svalue, byte for byte (draft-ietf-aipref-attach-05§2); - for
tdmrep:tdm-reservation:and0or1, and, wheretdm-policyis notnull,tdm-policy:and the URL (the TDM Reservation Protocol §6.2).
cawg has no HTTP field. These fields are unsigned. A client reads them as the response’s
statement and compares it with the object’s signed statement:
Content-Usagefield lines are combined as RFC 9110 §5.3 combines them, with a comma and a space, and parsed by §3.3. It conflicts when it does not parse, or when it gives any of the three labels a preference other than the signedvaluegives it. Parameters, unknown keys and spelling (train-ai=n,search=yagainsttrain-ai=n, search=y) do not conflict.tdm-reservationconflicts when more than one field line carries it, or when its value, without leading and trailing spaces and tabs, is other than the signed one written in decimal.tdm-policyconflicts when more than one field line carries it, or when its value, trimmed the same way, is other than the signed URL, or the signed one isnull. An absent field conflicts with nothing.- A field for a vocabulary the signed statement does not carry, or any field for an object with no signed statement, conflicts with nothing: it is an unsigned statement (§5.3).
A response whose fields conflict is refused header_conflicts. Field names compare without
regard to case. The robots.txt Content-Usage rule (draft-ietf-aipref-attach-05 §3) states a
preference for a path, not for an object, and is unsigned; a WAI origin MAY write one, and this
extension reads none.
4.5 MoQ: the catalog field wai_ai_usage
A WAI track’s catalog entry MAY carry wai_ai_usage, a statement
(moq-streaming-format §4), so that an agent knows the preference
before it subscribes. A catalog is unsigned. Its statement MUST be the statement of every
object on the track that carries one; a catalog whose statement does not read by §3.6, or whose
digest differs from the digest of a held object’s statement on the track, is refused
catalog_conflicts. A room track’s catalog SHOULD state the room record in effect when the
catalog is published.
5. Precedence
5.1 What governs an object
An object’s governing statements are its signed statements: the statement of its envelope,
when it is held (§4.1); and, when it is a room’s, the room record in effect at its live.t, or
every record of the room where it has none (§4.2). A principal’s terms are those of the grant
it acts under (§4.3).
5.2 The rule
The preference of a use, named by a term T of a vocabulary V, for an object and a principal:
- Terms. When the principal’s terms carry V and give T allow or disallow, that is the
preference: an arrangement overrides a statement of preference
(
draft-ietf-aipref-vocab-08§5.2). - Signed statements. Otherwise, of the governing statements that carry V: disallow when any gives T disallow; else allow when any gives it allow; else unknown. This is the vocabulary’s own rule for combining statements (§5.1 there), the most restrictive applying.
- Unsigned statements. When no governing statement carries V, an agent MAY read an unsigned statement for V (an HTTP field, a catalog, an envelope without receipts) by the same rule. It names no declaring party (§3.1 there), and no verifier can check what it said.
A use named in several vocabularies is disallowed when any of them disallows it; allowed when none disallows it and one allows it; unknown otherwise. A use that falls under no term of a vocabulary is outside that vocabulary, which then says nothing about it. What an agent does with an unknown preference is not this extension’s: the vocabulary takes no position on a default (§5 there), and a gate MAY (§7.1).
5.3 Conflicts
A signed statement governs over every unsigned one. An unsigned statement that differs from a
signed one is not the signer’s: a client that finds one ignores it in step 3, reports the
response or catalog refused (header_conflicts, catalog_conflicts), and decides by the signed
statement. A stricter unsigned statement is the preference of a party nothing identifies; an
agent MAY honour it as well, and a consumption claim is checked against the signed statements
alone. Two signed statements that differ are not a conflict: rule 2 applies, and the most
restrictive governs.
6. The consumption claim
6.1 The body
A consumption claim is a jwp-receipts §2.4.3 claim of class
consumption, subject_type object, signed by the agent’s key, whose subject is the first
of objects. Its signer_id is the did:key of signer_pubkey (jwp-receipts §7.1), the key
that traces the agent. Its body has exactly these members, read in this order at jwp-receipts
§3.1 step 2:
| member | type | meaning |
|---|---|---|
objects | array of 1 to 1024 32 B hex | the content hashes of the objects consumed |
usage | array of 1 to 3 entries | the use, in each vocabulary the agent answers |
seen | array of 0 to 64 32 B hex | the digests of the statements that governed the objects (§5.1) |
grant | 32 B hex or null | the digest of the room grant the agent consumed under (live-rooms §4.2) |
A usage entry has exactly vocabulary, one of aipref, cawg and tdmrep, and term, a
string of 1 to 255 bytes or null, read in that order. A term names the use as that vocabulary
names it; null states that the use falls under no term of the vocabulary. An array of another
length, a vocabulary outside the three and a term of another length are field_type.
6.2 Class rules
At jwp-receipts §3.1 step 4, in this order:
objectsis in strictly ascending order:consumption_objects_unordered.subjectis the first ofobjects:consumption_subject_mismatch.usageis in strictly ascending order ofvocabulary:consumption_usage_unordered.- Each
termthat is notnullis a term of its vocabulary: foraiprefone oftrain-ai,ai-useandsearch; fortdmrep,tdm-reservation; forcawg, one of the assertion’s four keys or a key of §3.4’s form that does not begincawg.:consumption_term_unknown. seenis in strictly ascending order:consumption_seen_unordered.signer_idis thedid:keyofsigner_pubkey:consumption_signer_not_principal.
6.3 Context
At jwp-receipts §3.1 step 6 a verifier is given the objects it holds, with their receipts (§4.1), and, where the claim names a grant or its objects are a room’s, the room: its descriptor, its grants and its usage records. It refuses at the first of these that fails:
- Each of
objectsis the content hash of an object it holds:consumption_object_unknown. - When
grantis notnull: it is the digest of one of the room’s grants that live-rooms §4.3 accepts, whoseprincipalissigner_pubkey, and which is good at thelive.tof every object of the room the claim names that has one; and every object the claim names is the room’s. Otherwisegrant_mismatch. A grant refusedgrant_usage_malformedholds no terms and is still the principal’s. seenis exactly the digests of the objects’ governing statements:preference_mismatch.usageanswers every vocabulary any governing statement carries:usage_unanswered.- For each object in the order of
objects, and each entry in the order ofusage, the preference of §5.2, with the grant’s terms wheregrantnames one, is not disallow:usage_disallowed.
A room whose usage records are refused (§4.2) states no preference: its objects are governed by their own statements alone. A grant the room refuses (live-rooms §4.3) is not one of its grants, and a claim that names it is refused at step 2.
6.4 What an accepted claim states
An accepted claim states, under the agent’s key, that the agent consumed those objects for that
use, having seen those statements, under that grant. A verifier reports, for each object, the
preference §5.2 gives the claimed use: allowed, unknown, or outside when every term
is null. A claim refused usage_disallowed is still its signer’s statement: its signature and
chain hold, and what it records is a use the governing statements disallow. A refusal at step 6
is of the use, never of the signature. The publisher, the agent and any party that holds the
objects and the claim reach the same verdict.
7. The gate
7.1 Policy
A relay or a gateway MAY require consumption claims before it serves an agent. Whether it does, and how it recognises an agent outside a room, is its own policy; in a room, an agent principal is one whose grant carries terms (§4.3). The policy has two parameters:
window, 0 to 16: how many of the most recent groups the gate served the agent may lack a claim. With 0, every object the agent requests is claimed before it is served, as over HTTP, where the agent names each object by its content hash before it fetches it (http-delivery §5.2). With n ≥ 1, the agent claims what it received after it received it, as over MOQT, where a live object’s content hash is known only once it is published.require_allowed: whether a use whose preference is unknown or outside is refused.
7.2 Decision
The gate holds the claims the agent gave it, each verified (§8) and signed by the agent’s key
(in a room, its grant’s principal; elsewhere, the key the gateway authenticates it by): an
accepted claim, or one refused usage_disallowed, is held; any other is not. It keeps the groups it served the agent,
in order, a group over HTTP being one object. For a request, a group of objects, the objects it
checks are the requested ones when window is 0, and otherwise those of every served group but
the last window. For each of those objects, in that order, it refuses at the first of these:
- No held claim names it:
claim_required. - A held claim that names it was refused
usage_disallowed:usage_disallowed. - With
require_allowed, a held claim that names it gives it a preference other than allowed:usage_not_granted.
Otherwise it serves the request. A gate that refuses tells the agent the reason; over MOQT a
relay ends the subscription, and over HTTP a gateway answers 403.
7.3 Over HTTP
An agent gives a gateway a claim with its request: the field WAI-Usage-Claim: and the claim’s
canonical form in base64url without padding (RFC 4648 §5). The gateway verifies it, holds it as
§7.2 says, and decides. WAI-Usage-Claim is proposed for the HTTP Field Name Registry (RFC 9110
§16.3), and is not registered. This revision defines no MOQT carriage for a claim; a relay that
gates over MOQT holds the claims its agents gave it over HTTP.
8. Verification
A verifier is given what each check reads, and nothing more:
| check | inputs | outcome |
|---|---|---|
| a statement (§3.6) | its JSON | accepted with its digest and every term’s preference, or refused |
| an object (§4.1) | its envelope, object receipt and group receipt | held, with its statement or none, or refused |
| a room (§4.2, §4.3) | its descriptor, grants and usage records | each record and grant accepted or refused |
| a response (§4.4) | an object and its response fields | consistent, or header_conflicts |
| a catalog (§4.5) | a catalog entry and the objects of its track | consistent, or refused |
| a claim (§6) | the claim, the claim before it of its signer, its objects, and its room | accepted with each object’s preference, or refused at a step, with its reason |
| a gate (§7) | the policy, the served groups, the claims given, and a request | served, or refused with its reason |
A room descriptor or a grant that does not verify is refused as live-rooms §3.4 and §4.3 refuse it; a room with no verified descriptor governs nothing.
9. Reasons
The codes this extension adds, each with where it is raised:
| reason | raised at |
|---|---|
usage_malformed | §3.6, §4.2 |
usage_revision_unknown | §3.6 |
receipt_invalid | §4.1 step 1 |
usage_unbound | §4.1 step 2 |
room_usage_unlinked | §4.2 |
grant_usage_malformed | §4.3 |
header_conflicts | §4.4 |
catalog_conflicts | §4.5 |
consumption_objects_unordered | §6.2 rule 1 |
consumption_subject_mismatch | §6.2 rule 2 |
consumption_usage_unordered | §6.2 rule 3 |
consumption_term_unknown | §6.2 rule 4 |
consumption_seen_unordered | §6.2 rule 5 |
consumption_signer_not_principal | §6.2 rule 6 |
consumption_object_unknown | §6.3 step 1 |
grant_mismatch | §6.3 step 2 |
preference_mismatch | §6.3 step 3 |
usage_unanswered | §6.3 step 4 |
usage_disallowed | §6.3 step 5, §7.2 |
claim_required | §7.2 |
usage_not_granted | §7.2 |
A room usage record also raises truncated, malformed, unknown_version, wrong_room,
bad_key and bad_signature, as live-rooms §3.4 names them, and a claim every code of
jwp-receipts §3.1 steps 1 to 5.
10. Conformance
live-conformance/usage/ holds the corpus, written from fixed
seeds by wai_ai_usage_vectors gen as vectors.json. It has:
- Statements: each vocabulary alone and the three together, with every term’s preference;
aiprefvalues that exercise the Dictionary: a repeated key, parameters, a value that is not a Token, an inner list, a key that is not a label, and every kind of bare item; and one statement refused for each defect of §3.6, among them a value that does not parse and an upper-case key. - Objects: a publication whose envelopes carry statements under one group receipt, among
them a
WAI2; the same envelope with its statement removed (usage_unbound), and altered (usage_unbound); one under a receipt whose signature fails (receipt_invalid); and one whose statement does not read. - Rooms: a room with two chained usage records and the grants of two agent principals, one of whose terms lift a disallow; a record of another room, one whose signature fails, one out of its chain, and one whose statement does not read; a grant whose terms do not read.
- Responses and catalogs: fields that agree with the signed statement in another spelling, and fields and a catalog that contradict it.
- Claims: claims accepted with each object’s preference — allowed, unknown, outside, and allowed under a grant over a room’s disallow — and one refused for each reason of §6.2 and §6.3, among them a use the statement forbids, objects the verifier does not hold, and a signature that fails.
- Gates: requests served and refused under each policy, for each reason of §7.2.
A conforming verifier gives every case the outcome, the reason, the step and everything else
the corpus states. wai_ai_usage_vectors verify and the test tests/ai_usage.rs check that the
file regenerates byte for byte, that wai-rs gives every case its outcome, that every reason of
§9 appears, and that §9 lists exactly the reference’s codes.
live-conformance/ai_usage_verify.py is the second implementation, written from this text: it
shares no code with wai-rs; it reads rooms with the live-rooms corpus’s second implementation
(live_rooms_verify.py), checks every signature with WAI’s strict rule
(claim-conformance/_ed25519.py) and computes BLAKE3 with claim-conformance/_blake3.py, and
parses Structured Fields, canonical forms, receipts and claims itself; and it mutates copies of
the corpus and requires every copy to fail.
11. Security and privacy considerations
- A preference is not a security mechanism (
draft-ietf-aipref-vocab-08§8). What this extension adds is evidence: the publisher’s statement bound to the bytes, and the agent’s statement of what it did, both signed. Neither makes a use happen or stops one. - Removing an envelope’s statement changes its content hash. An object served without its receipts carries an unsigned statement at most, and an agent that requires receipts sees the difference. A party that strips the statement and receipts the object under its own key becomes that object’s publisher, under its own key.
- An HTTP field and a catalog are written by whoever serves them. A signed statement governs over both (§5.3), so an intermediary that rewrites a field changes nothing a claim is checked against, and a client that compares them sees the rewrite.
- A consumption claim is signed by the agent’s key and names the agent by that key alone (jwp-receipts §7.1). A key-log confirmation, where the agent’s origin publishes one, says who holds the key; without one the claim is the key’s statement.
- A claim lists the objects an agent consumed. A publisher that holds it learns what the agent read and for what use, which is its purpose; an agent that claims under a gate discloses that to the gate’s operator too.
- A claim records the use its agent states. A false statement is a signed false statement: a verifier checks it against the objects and the statements, and cannot check what the agent did afterwards.
tdm-policyis a URL a statement carries and a verifier never fetches.