<?xml version="1.0" encoding="utf-8"?>
<rfc xmlns:xi="http://www.w3.org/2001/XInclude"
     docName="draft-schrock-canonical-action-identifier-04"
     category="std" ipr="trust200902"
     version="3" tocInclude="true" sortRefs="true" symRefs="true">
  <front>
    <title abbrev="CAID">The Canonical Action Identifier (CAID)</title>
    <seriesInfo name="Internet-Draft" value="draft-schrock-canonical-action-identifier-04"/>
    <author fullname="Iman Schrock">
      <organization>EMILIA Protocol, Inc.</organization>
      <address>
        <postal>
          <country>US</country>
        </postal>
        <email>team@emiliaprotocol.ai</email>
      </address>
    </author>
    <date year="2026" month="September" day="28"/>
    <area>sec</area>
    <keyword>AI agents</keyword>
    <keyword>action</keyword>
    <keyword>canonicalization</keyword>
    <keyword>digest</keyword>
    <keyword>identifier</keyword>
    <keyword>JSON</keyword>
    <abstract>
      <t>Authorization, delegation, execution, and audit artifacts often
      identify an action using format-local content and digests. Those
      digests are not directly comparable when the formats select or
      encode material action fields differently. This document defines
      the Canonical Action Identifier (CAID): a typed action object, a
      canonicalization and digest suite, a compact identifier string,
      and versioned action-type definitions with required material
      fields. External value sets are bound to integrity-checked
      snapshots. The document specifies a strict JSON input profile, a
      fixed and ordered set of refusal reasons, and a digest that
      identifies the validation semantics of a type definition. It
      requests seven registries: suites, action types, field types, code
      formats, reason codes, mapping transforms, and mapping loss
      policies. It also defines an Action-Mapping Profile for
      projecting natively verified artifacts into a common action type,
      with the closed results EQUIVALENT_UNDER_PROFILE, NOT_EQUIVALENT,
      and INDETERMINATE. CAID carries no trust semantics. It does not
      establish identity, authority, authorization, execution, safety,
      or legal reliance.</t>
    </abstract>
  </front>
  <middle>
    <section anchor="intro">
      <name>Introduction</name>
      <t>Many formats for permits, receipts, mandates, delegation, and
      outcome evidence reference "the action" by digest. Each format
      selects an action representation and canonicalization appropriate
      to its own protocol. The resulting identifiers are useful inside
      that format but are not necessarily comparable across formats.</t>
      <t>This creates two interoperability risks. The first is the
      material-fields failure: a digest over an underspecified object
      can omit the facts a relying party considers material. A
      digest computed over {"action": "wire"} commits to no amount, no
      currency, and no beneficiary; the artifact carrying it looks
      cryptographically bound to an action while committing to nothing
      that makes the action consequential. The second is the join
      failure: absent an agreed common definition, two artifacts about
      the same action, issued by different systems in different
      formats, can carry digests that cannot be compared without an
      explicit, reviewable mapping.</t>
      <t>This document defines the Canonical Action Identifier (CAID)
      to close both gaps. A CAID names typed content: an action object
      that declares its own type, carries every material field that
      type requires, is canonicalized under a registered suite, and is
      digested. The identifier is a compact string embedding the
      version, the action type, the suite, and the digest. When formats
      cannot emit the same action object, an Action-Mapping Profile
      (<xref target="mapping"/>) defines a relying-party-pinned,
      loss-aware projection into the common type and abstains when the
      comparison cannot be made.</t>
      <t>As informative examples of the artifact classes that can
      carry a CAID: authorization receipts
      <xref target="I-D.schrock-ep-authorization-receipts"/>, permit
      receipts <xref target="I-D.lee-orprg-permit-receipts"/>, and
      execution outcome attestations
      <xref target="I-D.morrow-sogomonian-exec-outcome-attest"/> each
      reference an action by digest and could carry a CAID in place of
      or alongside their existing action reference. These citations
      are examples only; this document neither depends on nor modifies
      any of them, and carrying a CAID changes nothing about how any
      such artifact is verified.</t>
      <t>A CAID deliberately carries no trust semantics. It does not
      assert that an action was authorized, executed, safe, or wise.
      <xref target="not"/> states the boundary.</t>
      <t>An executor that uses CAID as an authorization or execution join
      computes the action object from the operation it is prepared to
      perform, or validates every material field against an authoritative
      source. A presenter-supplied identifier, discovery document,
      authorization challenge, or receipt cannot substitute for that
      derivation (<xref target="effect-boundary"/>).</t>
      <section anchor="terms">
        <name>Terminology</name>
        <t>The key words "<bcp14>MUST</bcp14>", "<bcp14>MUST NOT</bcp14>",
        "<bcp14>REQUIRED</bcp14>", "<bcp14>SHALL</bcp14>",
        "<bcp14>SHALL NOT</bcp14>", "<bcp14>SHOULD</bcp14>",
        "<bcp14>SHOULD NOT</bcp14>", "<bcp14>RECOMMENDED</bcp14>",
        "<bcp14>NOT RECOMMENDED</bcp14>", "<bcp14>MAY</bcp14>", and
        "<bcp14>OPTIONAL</bcp14>" in this document are to be interpreted as
        described in BCP 14 <xref target="RFC2119"/>
        <xref target="RFC8174"/> when, and only when, they appear in all
        capitals, as shown here.</t>
        <t>Every operation of <xref target="overview"/> that an
        implementation offers <bcp14>MUST</bcp14> return exactly the result
        that this document specifies for it, including every reason and the
        order of the reasons.</t>
        <dl newline="false" spacing="normal">
          <dt>Action object:</dt>
          <dd>The typed data object, defined in
          <xref target="action-object"/>, over which a CAID's digest is
          computed.</dd>
          <dt>Action type:</dt>
          <dd>A versioned type name whose definition
          (<xref target="types"/>) declares the material fields an
          action object of that type is required to carry.</dd>
          <dt>Material field:</dt>
          <dd>A field that a type definition lists in its required_fields,
          because its absence would leave the digest uncommitted to
          something that makes the action consequential.</dd>
          <dt>Data model:</dt>
          <dd>The values of <xref target="data-model"/>. Every action
          object is a value of the data model.</dd>
          <dt>JSON text:</dt>
          <dd>Octets that encode a value in JSON
          <xref target="RFC8259"/>, decoded as specified in
          <xref target="json-text"/>.</dd>
          <dt>Host value:</dt>
          <dd>A value of an implementation's programming language that
          an application constructed itself
          (<xref target="host-values"/>).</dd>
          <dt>Kind:</dt>
          <dd>The JSON kind of a value, or "unsupported" for a host value
          of no JSON kind (<xref target="details"/>). Which host types have
          a JSON kind is a property of the language binding
          (<xref target="host-values"/>).</dd>
          <dt>Suite:</dt>
          <dd>A registered pairing of a canonicalization scheme and a
          digest algorithm (<xref target="suites"/>).</dd>
          <dt>Definition source:</dt>
          <dd>A collection of type definitions in the schema of
          <xref target="schema"/> that an implementation is configured
          with: the public registry, a local definitions file, or
          both.</dd>
          <dt>definition_sha256:</dt>
          <dd>The digest of a type definition's validation projection,
          which identifies its validation semantics
          (<xref target="definition-digest"/>).</dd>
          <dt>Enum snapshot:</dt>
          <dd>A locally available, immutable string array identified by an
          external value-set reference, a snapshot or edition label, and the
          SHA-256 digest of the array's JCS encoding
          (<xref target="enum-resolution"/>).</dd>
          <dt>Code format:</dt>
          <dd>A registered grammar that a code field's value must match
          (<xref target="code-fields"/>).</dd>
          <dt>Reason:</dt>
          <dd>A string from <xref target="appendix-reasons"/> that
          explains a refusal. Refusals are ordered lists of reasons.</dd>
          <dt>Issuer:</dt>
          <dd>The party that constructs an action object and computes
          its CAID.</dd>
          <dt>Verifier:</dt>
          <dd>The party that checks a presented CAID against a
          presented action object by recomputation
          (<xref target="verification"/>).</dd>
          <dt>Relying party:</dt>
          <dd>The party that decides whether to rely on a CAID or a mapping
          result, and that selects and pins the suites, definition sources,
          definition_sha256 values, enum snapshots, mapping profiles, and
          native trust anchors it accepts. A verifier, executor, or mapper
          applies that configuration.</dd>
          <dt>Executor:</dt>
          <dd>The party at an effect boundary that performs the operation
          that an action object describes
          (<xref target="effect-boundary"/>).</dd>
          <dt>Presenter:</dt>
          <dd>Any party that supplies a CAID, an action object, or a source
          artifact to a verifier, executor, or mapper. What a presenter
          supplies is a claim, not configuration.</dd>
          <dt>Mapping profile:</dt>
          <dd>A hash-identified projection, pinned by the relying
          party, from one exact source format and version into one CAID
          action type (<xref target="mapping"/>).</dd>
          <dt>Native verifier:</dt>
          <dd>The verifier defined by a source artifact's own
          specification. Native verification precedes mapping and is
          outside the CAID trust boundary.</dd>
          <dt>Mapper:</dt>
          <dd>An implementation of the map and compare operation
          (<xref target="mapping"/>).</dd>
        </dl>
      </section>
      <section anchor="overview">
        <name>Processing Overview</name>
        <t>CAID processing consists of the operations below. Each one
        returns either its result or an ordered list of reasons from
        <xref target="appendix-reasons"/>. None of them fails in any
        other way: malformed or hostile input of any shape yields
        reasons, never an exception, a crash, or a partial result, given
        the memory that an input within the limits of
        <xref target="limits"/> can require
        (<xref target="security-dos"/>).</t>
        <dl newline="false" spacing="normal">
          <dt>decode:</dt>
          <dd>JSON text to a data-model value, or malformed_json
          (<xref target="json-text"/>).</dd>
          <dt>parse:</dt>
          <dd>A CAID string to its version, action type, suite, and
          digest, or exactly one reason (<xref target="parsing"/>).</dd>
          <dt>compute:</dt>
          <dd>An action object, a suite, and definition sources to a
          CAID, its digest, and the definition_sha256 of the definition
          used (<xref target="computation"/>).</dd>
          <dt>verify:</dt>
          <dd>A CAID and an action object to a validity bit, reasons,
          and details (<xref target="verification"/>).</dd>
          <dt>map and compare:</dt>
          <dd>Natively verified sources, through relying-party-pinned
          profiles, to a projected action and a verdict
          (<xref target="mapping"/>).</dd>
        </dl>
        <t>Computation proceeds as follows:</t>
        <artwork><![CDATA[
  JSON text ---decode (2.4), phase 0 (gate)---+
                                              +--> data-model value
  host value ---convert (2.5)-----------------+           |
                                                          v
  phase 1  action_type is a valid type name        (gate)
  phase 2  exactly one conforming definition       (gate)
  phase 3  required fields present
  phase 4  present fields valid for their types
  phase 5  suite registered and implemented
  phase 6  every number, down to depth 64 and within the
           value count, in the data model
  phase 7  every other value in the data model
                                                          |
                                                          v
  canonical bytes (suite) --> digest (suite) --> base64url
  --> caid:1:<action_type>:<suite>:<digest>
]]></artwork>
        <t>The suite fixes the canonical bytes and the digest
        (<xref target="suites"/>).</t>
      </section>
    </section>
    <section anchor="object">
      <name>Data Model and JSON Input</name>
      <section anchor="action-object">
        <name>The Action Object</name>
        <t>An action object is a JSON object that identifies material
        action content. The
        same object is referenced, by CAID, from pre-execution artifacts
        (permits, challenges, receipts) and post-execution artifacts
        (outcome attestations, audit records, reliance events).</t>
        <t>An action object:</t>
        <ul spacing="normal">
          <li>is a value of the data model of
          <xref target="data-model"/>;</li>
          <li><bcp14>MUST</bcp14> contain an action_type member whose value is a
          registered or locally defined versioned type name
          (<xref target="types"/>). The type is inside the digested
          content, so the type asserted by an identifier cannot be
          swapped without changing the digest;</li>
          <li><bcp14>MUST</bcp14> contain every required material field of that type,
          encoded per the field types the type definition declares
          (<xref target="fieldtypes"/>);</li>
          <li><bcp14>MAY</bcp14> contain additional members beyond those the type
          definition declares. Extra members are covered by the
          digest;</li>
          <li><bcp14>MUST NOT</bcp14> encode money or quantity values as JSON numbers
          where the type definition declares the field amount-string.
          Floating-point and precision malleability across languages
          makes numeric encodings of money unsafe for
          canonicalization.</li>
        </ul>
      </section>
      <section anchor="data-model">
        <name>Data Model</name>
        <t>A value of the data model is one of:</t>
        <ul spacing="normal">
          <li>an object: members, each a name and a value, where every
          name is a string and no two members have the same name;</li>
          <li>an array: an ordered sequence of values;</li>
          <li>a string: a sequence of Unicode scalar values that contains
          no noncharacter;</li>
          <li>a number whose value is an integer in the range
          -(2^53-1) through 2^53-1 (<xref target="numbers"/>);</li>
          <li>true, false, or null.</li>
        </ul>
        <t>Surrogate code points are not Unicode scalar values
        <xref target="UNICODE"/>, so a string that contains an unpaired
        surrogate is outside the model. The
        noncharacters are U+FDD0 through U+FDEF and the last two code
        points of every plane: U+FFFE and U+FFFF, U+1FFFE and U+1FFFF,
        and so on through U+10FFFE and U+10FFFF. I-JSON
        <xref target="RFC7493"/> excludes both, and so does this
        model.</t>
        <t>The nesting depth of a value <bcp14>MUST NOT</bcp14> exceed 64. The
        outermost object or array is at depth 1, and each nested object
        or array adds one. The RFC 8785 encoding of an action object
        <bcp14>MUST NOT</bcp14> exceed 16,777,216 octets. That size is measured only
        for a value that is otherwise inside the model: a value outside
        it has no RFC 8785 encoding, so an oversized object that also
        holds a number outside the model yields unsupported_number and no
        unsupported_value. A host value is also bounded by a value count
        (<xref target="host-values"/>); past it, a host action object yields
        unsupported_value from phase 7 and no unsupported_number, whatever
        else it holds, while phases 3 and 4 still run
        (<xref target="computation"/>), and any other host value is refused
        by the step that reads it (<xref target="limits"/>). The contents of
        an object or array nested deeper than 64 are not examined and are not
        counted toward the value count, so a number inside one adds no
        unsupported_number; a number held by an object or array at depth 64
        or less still does. In a host value, a reference back to an enclosing
        object or array is a cycle: it counts as one value, and nothing
        beyond it is counted or examined, since what it refers to is counted
        and examined where it sits. An action object can be canonicalized
        when it is a value of the data model whose RFC 8785 encoding is at
        most 16,777,216 octets, whether or not the checks of computation
        phases 1 through 4 pass.</t>
        <t>A value outside the data model is refused and is never
        rewritten into a value inside it. Computation reports a number
        outside the model as unsupported_number, and anything else,
        including nesting beyond 64 and an encoding beyond the limit, as
        unsupported_value (<xref target="computation"/>, phases 6 and 7).
        A number is examined only where an object or array at depth 64 or
        less holds it, and not at all in a host action object past the
        value count, which yields unsupported_value instead
        (<xref target="host-values"/>).</t>
      </section>
      <section anchor="numbers">
        <name>Numbers</name>
        <t>The value of a number is the result of converting the exact
        decimal value it denotes to binary64 <xref target="IEEE754"/> under
        the roundTiesToEven rounding-direction attribute: the correctly
        rounded value. Under that attribute, a value of magnitude at least
        2^1024 - 2^970 rounds to an infinity. A number is in the data model
        if and only if its value is finite, is an integer, and has magnitude
        at most 2^53-1 (9,007,199,254,740,991). It is then canonicalized as
        that integer, which RFC 8785 serializes in plain decimal form.
        The literal form is irrelevant: the literals 1e3, 1000.0, and
        1000 all denote the integer 1000, exactly as an ECMAScript JSON
        parser sees them.</t>
        <ul spacing="normal">
          <li>A literal whose correctly rounded value is an infinity, such
          as 1e400 or 1.7976931348623159e308, is not finite, so it is
          refused as unsupported_number. A literal above the largest finite
          binary64 value, 2^1024 - 2^971, whose correctly rounded value is
          still that value, such as 1.7976931348623158e308, is a finite
          integer beyond 2^53-1: it is refused as unsupported_number too,
          but the integer field type accepts it
          (<xref target="fieldtypes"/>).</li>
          <li>A literal whose correctly rounded value is zero, such as
          1e-400 or -1e-400, is the integer 0, and so is -0. A literal whose
          correctly rounded value is a nonzero subnormal, such as 1e-310, is
          not an integer and is refused as unsupported_number.</li>
          <li>A literal whose exact value is not an integer but whose
          correctly rounded value is, such as 0.99999999999999999999, is
          that integer. Issuers <bcp14>MUST NOT</bcp14> emit such literals;
          <xref target="security-parsing"/> states the consequence for a
          reader that reads numbers as exact decimals.</li>
          <li>Fractional, NaN, infinite, and out-of-range values are
          refused as unsupported_number by every conforming implementation
          wherever an object or array at depth 64 or less holds them
          (<xref target="data-model"/>), except in a
          host action object past the value count, which yields
          unsupported_value instead (<xref target="host-values"/>).
          Fractional quantities are carried as strings.</li>
        </ul>
        <t>Rationale: ECMAScript number serialization is the leading
        source of cross-language canonicalization divergence, and a rule
        over the correctly rounded value is the only one that every
        language can implement identically. A rule over the literal form
        cannot be enforced by implementations, such as ECMAScript, whose
        JSON parsers do not preserve it.</t>
      </section>
      <section anchor="json-text">
        <name>JSON Text Input</name>
        <t>An implementation that receives an action object or a mapping
        source as JSON text <bcp14>MUST</bcp14> decode it as specified in this section
        before validating, canonicalizing, or mapping it, and <bcp14>MUST</bcp14> refuse
        input that fails with the single reason malformed_json. An
        implementation <bcp14>MUST NOT</bcp14> compute, verify, or map over received
        JSON text through a decoder that does not meet these rules.</t>
        <t>When the action object arrives as a member of a larger JSON text,
        such as a receipt, the carrying protocol identifies exactly one
        member that holds it, and the party that extracts it
        <bcp14>MUST</bcp14> apply rules 2 through 4 to the whole enclosing
        text, so that no object anywhere in that text, including one that
        holds a second candidate action object or a sibling CAID string,
        has two members with the same name. Rule 1 then limits the octets
        of the member value that encodes the action object, and rule 5
        limits that value's nesting, counted from the action object as
        depth 1. A failure of any of these is malformed_json.</t>
        <t>The input is refused unless all of the following hold:</t>
        <ol spacing="normal">
          <li>It is at most 33,554,432 octets long. This is checked
          before decoding.</li>
          <li>It is an I-JSON message <xref target="RFC7493"/>, except that
          <xref target="RFC7493" section="2.2" sectionFormat="of"/>, on
          numbers, does not apply: the decoder admits every number token
          that <xref target="RFC8259"/> admits (below). In particular the
          input is valid UTF-8 <xref target="RFC3629"/>; no string or member
          name, after unescaping, contains a surrogate code point or a
          noncharacter; and no object has two members whose names, after
          unescaping, are the same sequence of code points. An escaped
          surrogate pair, such as "&#92;uD83D&#92;uDE00", denotes one scalar
          value and is valid; an escape of an unpaired surrogate is not. The
          names "a" and "&#92;u0061" are the same name. A duplicate is
          refused, never resolved by keeping the first or the last
          member.</li>
          <li>It does not begin with the UTF-8 byte order mark (the
          octets EF BB BF). Section 8.1 of <xref target="RFC8259"/>
          permits a parser to ignore one; this profile refuses it.</li>
          <li>It is exactly one JSON text <xref target="RFC8259"/>: one
          value, optionally preceded and followed by the four JSON
          whitespace characters, and nothing else. The literals NaN and
          Infinity, comments, and a character U+0000 through U+001F that
          appears unescaped in a string are not JSON and are refused
          (<xref target="RFC8259" section="7" sectionFormat="of"/>). Other
          characters, including U+007F and U+0080 through U+009F, may
          appear unescaped.</li>
          <li>Its nesting does not exceed 64 (<xref target="data-model"/>).
          An implementation <bcp14>MUST</bcp14> check this without unbounded
          recursion.</li>
        </ol>
        <t>The decoder never refuses a number token that
        <xref target="RFC8259"/> admits. It converts the token to its
        correctly rounded value, and <xref target="numbers"/> decides
        whether that value is in the data model. A very long literal is
        therefore not a decoding failure; if its value is not a suitable
        integer, computation reports unsupported_number.</t>
        <t>Every failure of rules 1 through 5 yields malformed_json and
        nothing else, whichever rules failed. An implementation <bcp14>MAY</bcp14>
        report an informative detail beside the reason; that detail is
        not part of the result.</t>
        <t>A type definition, a registry, an enum snapshot
        (<xref target="enum-resolution"/> gives its shape), or a mapping
        profile read from JSON text is decoded under rules 2 through 5.
        Rule 1 does not apply to them: a registry or a value set can
        legitimately grow beyond any fixed bound, and these documents are
        configuration that a relying party pins by digest, not input to
        an operation. An implementation <bcp14>MUST NOT</bcp14> use such a document when
        it fails those rules. How the failure is reported is outside this
        document.</t>
      </section>
      <section anchor="host-values">
        <name>Host Values</name>
        <t>An implementation <bcp14>MAY</bcp14> also accept an action object, a type
        definition, a mapping profile, or a mapping source as a host value
        that the application constructed. Which host types represent each
        kind of the data model is a property of the implementation's
        language binding: a Python dict subclass, for example, can be read
        as an object through the dict's own accessors, while an ECMAScript
        object whose prototype is neither Object.prototype nor null is
        outside the model. Such an implementation:</t>
        <ul spacing="normal">
          <li><bcp14>MUST</bcp14> refuse any host value that is not a value of the data
          model. In a host action object within the value count below, a
          number outside the model that an object or array at depth 64 or
          less holds is refused as unsupported_number, and anything else as
          unsupported_value (<xref target="computation"/>, phases 6 and 7).
          A host action object past that count is refused as the value count
          below states, and any other host value by the step that reads it
          (<xref target="limits"/>). A declared field that holds such a value is also
          checked under its field type (phase 4) exactly as
          <xref target="fieldtypes"/> states, and fails that check whenever
          the value is not one that the type accepts. A host number is a
          host value that the language binding represents as a number, such
          as a Python int or float; its value is its correctly rounded
          binary64 value (<xref target="numbers"/>), as for a number token.
          A binding may instead represent other numeric host types, such as
          an ECMAScript BigInt or a Go uint64, as values of kind
          "unsupported" (<xref target="details"/>), and a host value of kind
          "unsupported" fails every field type. So NaN or 1.5 in an integer
          field is mistyped_field:&lt;name&gt; and unsupported_number
          (unsupported_value past the value count), and so is a host number
          whose correctly rounded value is an infinity, such as the Python
          int 10^400; a host number beyond 2^53-1 whose correctly rounded
          value is finite is refused by phase 6 alone (phase 7 alone past the
          value count); and
          a BigInt in an integer field, in a binding that gives it kind
          "unsupported", is mistyped_field:&lt;name&gt; and
          unsupported_value, whatever its value. A string with an unpaired
          surrogate, such as "1" followed by U+D800, is
          invalid_amount:&lt;name&gt; and unsupported_value in an
          amount-string field, mistyped_field:&lt;name&gt; and
          unsupported_value in a digest field, and unsupported_value alone in
          a string field. A map or a date in an object field is
          mistyped_field:&lt;name&gt; and unsupported_value. At the top
          level, a value whose kind is not "object" fails phase 1 as
          invalid_action_type alone, whatever it is;</li>
          <li><bcp14>MUST NOT</bcp14> serialize a host value as a different value. A map
          type, a date, a typed array, a cyclic structure, or an object
          with accessor properties or a non-default prototype is refused,
          never canonicalized as an empty or partial object;</li>
          <li><bcp14>MUST NOT</bcp14> fail with an exception, a crash, or unbounded
          recursion for any host value, including cyclic values and
          values nested deeper than 64. The depth check precedes any
          recursive traversal;</li>
          <li><bcp14>MUST</bcp14> refuse a host value made of more than 33,554,432 values
          (<xref target="limits"/>), counting the value itself and every
          value inside it once for every path that reaches it, so that a
          value reached through two members counts twice, except that an
          object or array nested deeper than 64 counts as one value and
          nothing inside it is counted, and a reference back to an enclosing
          object or array counts as one value and nothing beyond it is
          counted (<xref target="data-model"/>). For a host action object
          past this count, phase 7 yields unsupported_value and phase 6
          yields no reason, whatever the value holds, while phases 3 and 4
          still run (<xref target="computation"/>); a host definition whose
          validation projection is past it, or a host mapping profile or
          mapping source past it, is refused by the step that reads it
          (<xref target="limits"/>). No JSON text within the limit of
          <xref target="json-text"/> holds that many values. An
          implementation can process a value with shared references without
          walking its expansion, but the count of a value whose shared
          references form no cycle is that of the expansion, down to depth
          64;</li>
          <li><bcp14>MUST</bcp14> read a host type definition only as far as its
          validation projection (<xref target="definition-digest"/>). The
          projection <bcp14>MUST</bcp14> be a value of the data model, and a member outside
          it is never read, so a value there that is outside the model
          changes nothing;</li>
          <li><bcp14>MUST</bcp14> produce, for every value that the decoder of
          <xref target="json-text"/> can produce, exactly the result that
          the same operation over the corresponding JSON text
          produces.</li>
        </ul>
        <t>A host language's representation of an absent member, such as
        an ECMAScript property whose value is undefined, counts as absent
        for field presence (phase 3). The value itself is not a value of
        the data model, so the object is also refused as
        unsupported_value. The reason for a string that contains an unpaired
        surrogate or a noncharacter depends on the entry point:
        malformed_json when it arrives as JSON text, and unsupported_value
        when it arrives as a host value. It never depends on the
        implementation language.</t>
      </section>
      <section anchor="limits">
        <name>Limits</name>
        <t>The limits of this document are collected in
        <xref target="tab-limits"/>. Octets are UTF-8 octets. Every limit
        is a refusal with the reason shown, never an exception. A length
        limit on a string that a rule of <xref target="appendix-abnf"/>
        matches is checked before the rule is applied. The document
        encoding limit applies wherever a document other than an action
        object is canonicalized: a definition whose validation projection
        exceeds it is invalid_definition, a mapping source that exceeds it
        is source_not_canonicalizable, and an enum value array that exceeds
        it cannot match its values_sha256, so a present field is
        mistyped_field:&lt;name&gt;. The nesting limit and the value count
        apply in the same way to a host value that is not an action object
        (<xref target="host-values"/>): a host definition whose
        validation projection nests deeper than 64 or exceeds the value
        count is invalid_definition, a host mapping profile that does is
        invalid_mapping_profile and has no digest
        (<xref target="mapping-algorithm"/>), and a host mapping source that
        does is source_not_canonicalizable.</t>
<table anchor="tab-limits">
  <name>Limits</name>
  <thead><tr><th>Limit</th><th>Value</th><th>Applies to</th><th>Refusal</th></tr></thead>
  <tbody>
    <tr><td>JSON text</td><td>33,554,432 octets</td><td>an action object or a mapping source received as JSON text (decode)</td><td>malformed_json</td></tr>
    <tr><td>Nesting depth</td><td>64 levels</td><td>every value</td><td>malformed_json (action object or mapping source as JSON text); unsupported_value (host action object); otherwise the reason of the step that reads the value</td></tr>
    <tr><td>Canonical encoding</td><td>16,777,216 octets</td><td>an action object</td><td>unsupported_value</td></tr>
    <tr><td>Integer magnitude</td><td>2^53-1</td><td>every number held at depth 64 or less in a value within the value count</td><td>unsupported_number (action object); otherwise the reason of the step that reads the value</td></tr>
    <tr><td>Value count</td><td>33,554,432 values</td><td>a host value, each value counted once per path; an object or array nested deeper than 64, or a reference back to an enclosing one, counts as one value</td><td>unsupported_value and no unsupported_number (host action object); otherwise the reason of the step that reads the value</td></tr>
    <tr><td>Document encoding</td><td>134,217,728 octets</td><td>the RFC 8785 encoding of a validation projection, an enum value array, or a mapping source</td><td>the reason of the step that needs the encoding</td></tr>
    <tr><td>Identifier</td><td>1,024 octets</td><td>a CAID string</td><td>malformed_caid</td></tr>
    <tr><td>Code system</td><td>2,048 octets</td><td>the code_system of a code field</td><td>invalid_definition</td></tr>
    <tr><td>Action type</td><td>512 octets</td><td>an action type in a CAID, an action object, or a definition</td><td>malformed_caid; invalid_action_type; invalid_definition</td></tr>
    <tr><td>Mapping rules</td><td>1 to 128 rules</td><td>rules of a mapping profile</td><td>invalid_mapping_profile</td></tr>
    <tr><td>Source path</td><td>at most 2,048 octets</td><td>each source path of a mapping profile</td><td>invalid_mapping_profile</td></tr>
    <tr><td>Profile string</td><td>1 to 512 octets</td><td>profile_id, media_type, schema, version, and target_action_type</td><td>invalid_mapping_profile</td></tr>
    <tr><td>Omission reason</td><td>1 to 2,048 octets</td><td>each omission reason</td><td>invalid_mapping_profile</td></tr>
  </tbody>
</table>
        <t>A definition, registry, enum snapshot, or mapping profile read
        from JSON text that nests deeper than 64 fails the decoding of
        <xref target="json-text"/>, whose report this document leaves to the
        implementation. The JSON text limit is twice the canonical limit,
        which leaves room for insignificant whitespace and escapes. A tool call whose
        arguments would push an action object past the canonical limit is
        addressed in <xref target="tool-call-type"/>. A protocol that
        carries action objects can impose tighter limits on its own
        messages, such as a node count or a bound on each string; such a
        limit belongs to that protocol and is not a CAID refusal.</t>
      </section>
    </section>
    <section anchor="identifier">
      <name>Suites and the Identifier</name>
      <section anchor="suites">
        <name>Suites</name>
        <t>A suite names a canonicalization scheme and a digest
        algorithm, and fixes the length of its digest in octets. This
        document defines two suites; the CAID Suites registry
        (<xref target="iana-suites"/>) carries one entry per suite. A
        registered suite is never removed, reassigned, or
        redefined.</t>
        <dl newline="false" spacing="normal">
          <dt>jcs-sha256:</dt>
          <dd>The JSON Canonicalization Scheme
          <xref target="RFC8785"/> followed by SHA-256
          <xref target="RFC6234"/>, with a 32-octet digest. RFC 8785 sorts
          member names by their UTF-16 code units, not by their code points
          (<xref target="RFC8785" section="3.2.3" sectionFormat="of"/>), so a
          name that begins with U+1F600 sorts before one that begins with
          U+FF61. Support for this suite is <bcp14>REQUIRED</bcp14> for
          conforming implementations.</dd>
          <dt>cbor-sha256:</dt>
          <dd>The CBOR encoding of the action object under the core
          deterministic encoding requirements
          (<xref target="RFC8949" sectionFormat="of" section="4.2.1"/>)
          followed by SHA-256 <xref target="RFC6234"/>, with a 32-octet
          digest. The data model maps to CBOR as follows: an object is a
          map whose keys are text strings; an array is an array; a string
          is a text string; a number, which is always an integer
          (<xref target="numbers"/>), is an unsigned or negative integer
          (major type 0 or 1); and true, false, and null are the simple
          values 21, 20, and 22. No tag, byte string, or floating-point
          value appears. The input is always a value of the data model, and
          the size limit of <xref target="data-model"/> is measured on the
          RFC 8785 encoding for every suite. Map keys sort by the bytewise
          order of their encodings, which differs from the RFC 8785 member
          order; <xref target="example-compute"/> gives an example. Support
          for this suite is <bcp14>OPTIONAL</bcp14>.</dd>
        </dl>
        <t>A suite's status is not a type's status
        (<xref target="status"/>). A suite is deprecated once practical
        collision attacks on its digest are known or anticipated
        (<xref target="iana-suites"/>). Issuers then stop emitting new CAIDs
        under it (<xref target="security-digest"/>), and a relying party
        <bcp14>SHOULD</bcp14> remove it from the suites it accepts once the
        artifacts it relies on carry a CAID under a successor. Deprecation
        does not by itself make a verifier refuse a CAID: the suites that the
        relying party accepts decide (<xref target="equality"/>). A document
        that deprecates jcs-sha256 names the suite that becomes mandatory to
        implement in its place.</t>
      </section>
      <section anchor="digest">
        <name>The Digest</name>
        <t>The digest is computed directly over the canonical bytes of
        the action object:</t>
        <sourcecode type=""><![CDATA[
digest = H(canonical_bytes(action_object))
]]></sourcecode>
        <t>The suite fixes both the canonicalization that produces
        canonical_bytes and the digest function H
        (<xref target="suites"/>). For the two suites of this document, H
        is SHA-256.</t>
        <t>There is deliberately no domain separation prefix. The object is
        self-typed via its action_type member, and a design goal of CAID is
        that an existing artifact format whose signed or hashed payload is
        itself a valid action object can reuse the digest it already
        computes over the same canonical bytes under the same suite. The
        goal is limited to that reuse: it does not make an identifier
        computed under another profile comparable with a CAID
        (<xref target="coexistence"/>). Conforming verifiers
        <bcp14>MUST</bcp14> check that the in-object action_type equals the
        action type carried in the CAID string
        (<xref target="verification"/>); that check, not a byte prefix, is
        what prevents cross-context reinterpretation.
        <xref target="security"/> states this trade explicitly, and states
        that a signature meant to commit to a CAID covers the whole
        identifier string.</t>
      </section>
      <section anchor="syntax">
        <name>Identifier Syntax</name>
        <t>The identifier is a string matched by the caid rule of
        <xref target="appendix-abnf"/>:</t>
        <sourcecode type=""><![CDATA[
caid:1:<action_type>:<suite>:<digest-b64url>
]]></sourcecode>
        <t>For example, the action object of
        <xref target="example-compute"/> has this CAID (long lines in this
        document are folded as specified in <xref target="RFC8792"/>):</t>
<sourcecode anchor="ex-identifier"><![CDATA[
=============== NOTE: '\' line wrapping per RFC 8792 ================

caid:1:payment.release.1:jcs-sha256:liLG9pKgkLt3silrjf1wa0xIHz5YFrBB\
9HI-arxrO1Y
]]></sourcecode>
        <t>The grammar uses the ABNF of <xref target="RFC5234"/> with the
        case-sensitive string syntax of <xref target="RFC7405"/>, so the
        prefix is the lowercase string "caid". caid-version is the
        version of this identifier syntax and is "1" for this document.
        action-type is one or more lowercase dotted name segments
        followed by a final segment that is the integer version of the
        type (for example, payment.release.1). suite is a name from the
        suite registry, lowercase; the ABNF bounds the names a registry
        can assign, and a parser accepts only registered names
        (<xref target="parsing"/>). digest is the digest encoded in
        base64url
        (<xref target="RFC4648" sectionFormat="of" section="5"/>),
        unpadded and case-sensitive. A CAID is at most 1,024 octets, and
        its action type at most 512 octets (<xref target="limits"/>).</t>
        <t>A suite whose digest is n octets encodes it in ceil(8n/6)
        characters, and the unused low bits of the final character are
        zero; Appendix A derives the digest syntax from n. For the two
        suites defined here the digest is exactly 43 characters, encoding
        32 octets. Those 43 characters carry 258 bits, so the two low bits
        of the final character are unused and zero: the final character
        is one of "A", "E", "I", "M", "Q", "U", "Y", "c", "g", "k", "o",
        "s", "w", "0", "4", or "8".</t>
      </section>
      <section anchor="parsing">
        <name>Parsing</name>
        <t>A parser takes an identifier string and the suite registry
        and yields either the four components or exactly one reason. It
        applies these checks in order and stops at the first that
        fails:</t>
        <ol spacing="normal">
          <li>The string is at most 1,024 octets and matches the caid rule
          of <xref target="appendix-abnf"/>, and its action type is at most
          512 octets, else malformed_caid. The length of the string is
          checked before the rule is matched. This step does not consult
          the registry.</li>
          <li>The suite is in the suite registry, else unknown_suite. The
          digest of such an identifier is not checked, because the parser
          has no digest length for its suite.</li>
          <li>The digest matches the digest syntax of the suite's digest
          length (<xref target="appendix-abnf"/>), else
          malformed_caid.</li>
        </ol>
        <t>A parser operates on the exact sequence of code points it is
        given. It <bcp14>MUST NOT</bcp14> trim, case-fold, Unicode-normalize, or
        percent-decode it; removing a transport encoding is the carrying
        protocol's job before parsing. As a consequence, a conforming
        parser refuses as malformed_caid: base64url padding ("=") in the
        digest; uppercase characters in the prefix, the action type, or
        the suite (the digest is case-sensitive, and both cases are
        significant there); empty segments anywhere, including empty
        dotted segments within the action type; any content after the
        digest, including trailing separators, whitespace, or additional
        fields; a digest that is not exactly the length of the named
        suite or whose final character encodes nonzero unused bits; and
        any caid-version other than "1", which is never guessed at or
        parsed leniently.</t>
        <t>An unregistered suite is refused as unknown_suite rather than
        malformed_caid so that the reason says what the relying party
        needs to know. An identifier under a suite registered after the
        parser's registry snapshot is well formed, and the right response
        is a newer suite registry, not a report of corruption. Because a
        registered suite is never removed or redefined, an identifier
        that one registry snapshot refuses as malformed_caid is refused as
        malformed_caid by every later snapshot.</t>
        <t>A registered suite that an implementation does not implement
        is not unknown to its parser: the identifier is well formed, and
        computation and verification report the suite as
        unknown_suite.</t>
      </section>
      <section anchor="equality">
        <name>Equality</name>
        <t>Two CAIDs are equal if and only if their strings are
        byte-equal. Cross-suite equivalence is out of scope: no
        procedure in this document relates a jcs-sha256 CAID to a
        cbor-sha256 CAID for the same object. An artifact <bcp14>MAY</bcp14> carry
        multiple CAIDs for one action, one per suite its issuer
        computed.</t>
        <t>A relying party decides which suites it accepts, and a
        verifier <bcp14>MUST NOT</bcp14> accept a CAID under any other suite. When an
        artifact carries several CAIDs for one action, a verifier <bcp14>MUST</bcp14>
        verify every CAID whose suite it accepts and implements, and <bcp14>MUST</bcp14>
        treat the failure of any one as the failure of all. It <bcp14>MUST NOT</bcp14>
        select the CAID that verifies. When no carried CAID is under a
        suite that the verifier accepts and implements, verification fails.
        The relying party applies the suites it accepts to the suite of the
        parsed identifier (<xref target="parsing"/>); the verification
        operation of <xref target="verification"/> does not take that
        policy as an input.</t>
        <t>Direct CAID equality is content equality, not inferred
        semantic equality. The strings "1.50" and "1.5" are different
        content and yield different digests. Per-field normalization
        guidance lives in the type definition's digest_notes
        (<xref target="schema"/>), and normalization is the issuer's
        job: the issuer normalizes before computing the CAID, and no
        party renormalizes afterward.</t>
        <t>When two native formats cannot produce byte-equal action
        objects, the Action-Mapping Profile in <xref target="mapping"/>
        provides a narrower result: equivalence of the material
        projection under exact profiles pinned by a relying party. It
        does not claim general semantic equivalence.</t>
      </section>
      <section anchor="coexistence">
        <name>Coexistence with Other Identifier Profiles</name>
        <t>Other specifications define their own canonical action
        identifiers over their own canonical material, some under a
        distinct namespace prefix. <xref target="digest"/> limits the
        no-prefix design goal to the reuse of a digest over the same
        canonical bytes under the same suite. This section states the
        consequence for identifiers derived under other profiles.</t>
        <t>An identifier derived under a different profile
        <bcp14>MUST NOT</bcp14> be compared for equality with a CAID
        derived under this document, in either direction, and a
        verifier <bcp14>MUST NOT</bcp14> treat inequality between them
        as evidence that two artifacts describe different actions. The
        profiles canonicalize different material; inequality carries no
        information.</t>
        <t>An executor holding artifacts under two profiles for what it
        believes is one action derives an identifier under each profile
        from its own representation of the effect, compares within each
        profile, and joins on that representation rather than on the
        identifier strings. Where a relying party needs a stronger
        statement than same-representation, the Action-Mapping Profile
        in <xref target="mapping"/> is the mechanism, and its result is
        equivalence of a material projection under pinned profiles, not
        identifier equality.</t>
        <t><xref target="I-D.thallapelly-oasnt-caid"/> reaches the same
        conclusion for its own profile.</t>
      </section>
    </section>
    <section anchor="types">
      <name>Action Types and the Registry</name>
      <section anchor="names">
        <name>Type Names and Versioning</name>
        <t>An action type name is one or more lowercase dotted name
        segments with a final segment that is the integer version of
        the type, per the action-type rule of
        <xref target="appendix-abnf"/>, and is at most 512 octets long
        (<xref target="limits"/>). Registered types live in the CAID
        Action Types registry (<xref target="iana-action-types"/>), one
        entry per versioned type. A registered name has at least two name
        segments before its version, such as payment.release.1; a local
        definition (<xref target="local"/>) can use one.</t>
        <t>Once a version is published, every declaration that affects
        validation or material meaning is immutable, with the one
        exception below. Adding or removing a required or optional field,
        retyping a field, changing a normalization rule or a field's
        semantics, or changing an enum set in any other way <bcp14>MUST</bcp14> be
        published as a new version of the type (payment.release.2),
        never as an in-place edit.</t>
        <t>Monotone enum advance. A registry version <bcp14>MAY</bcp14>
        advance the value-set pin of an enum field in place, without a new
        type version, to a later edition that contains every member of the
        set the field accepted under the previous registry version, and it
        <bcp14>MUST NOT</bcp14> advance a pin in place to any other edition.
        The first pin of a field that previously resolved no set is such
        an advance, because that field accepted no value. Removing,
        renaming, or redefining a member is never an advance. The
        registry records each advance field by field.</t>
        <t>Under this rule an action object that is valid under one
        registry version remains valid under every later version of the
        same registry, while an advance can make valid an object that an
        earlier version refused. An advance changes the type's
        definition_sha256 (<xref target="definition-digest"/>), and every
        computation and verification result reports definition_sha256,
        so a relying party that needs exact reproducibility pins
        definition_sha256, and verification then refuses any other
        definition as definition_mismatch (<xref target="verification"/>).
        The registry keeps every definition_sha256 an entry has held
        (<xref target="iana-action-types"/>), so an earlier result can be
        replayed under the definition that produced it.</t>
      </section>
      <section anchor="schema">
        <name>The Type Definition Schema</name>
        <t>The members of a type definition are those described after
        the example below, and they are the same for local definitions
        (<xref target="local"/>). The example is informative. It is the
        entry for payment.release.1 in registry version 5 of the reference
        registry, whose definition_sha256 is the value that
        <xref target="example-compute"/> shows. Line breaks inside its
        strings are for presentation only: each line break inside a string,
        and the indentation after it, reads as one space. Its long line is
        folded as specified in <xref target="RFC8792"/>.</t>
        <sourcecode anchor="ex-definition" type="json"><![CDATA[
=============== NOTE: '\' line wrapping per RFC 8792 ================

{
  "action_type": "payment.release.1",
  "status": "active",
  "risk_class": "irreversible-financial",
  "summary": "Release of a payment instruction to settlement.",
  "required_fields": [
    {"name": "amount", "type": "amount-string",
     "notes": "decimal string, no exponent, no leading '+',
               no thousands separators"},
    {"name": "currency", "type": "enum",
     "values_ref": "ISO 4217 alpha-3",
     "values_snapshot": "SIX ISO 4217 List One published 2026-09-17",
     "values_sha256": "sha256:27f824317e9f271b956123fb77608daece5106\
       e1ee8253a17769390855ade270"},
    {"name": "beneficiary_account", "type": "digest",
     "notes": "sha256:<lowercase hex> of the normalized account
               identifier; normalization stated by the issuing
               system of record"},
    {"name": "payment_instruction_id", "type": "string"}
  ],
  "optional_fields": [
    {"name": "memo", "type": "string"}
  ],
  "digest_notes": "amounts never renormalized after signing; the
                   system of record's form is canonical",
  "references": []
}
]]></sourcecode>
        <t>action_type is the versioned type name. status is the
        lifecycle state of the entry (<xref target="status"/>).
        risk_class is a descriptive label for the consequence class of
        the action; it carries no verification semantics. required_fields
        declares the material fields, each with a name, a field type from
        <xref target="fieldtypes"/>, the members that field type defines,
        and optional notes. Notes guide issuers and never change how a
        field is validated. optional_fields declares fields the type
        recognizes but does not require. digest_notes carries per-type
        normalization guidance for issuers. references carries citations
        for the type's semantics. supersedes and superseded_by, when
        present, name the type version this one replaces and the one that
        replaces it.</t>
        <section anchor="conformance">
          <name>Definition Conformance</name>
          <t>A definition conforms if and only if all of the following
          hold:</t>
          <ul spacing="normal">
            <li>It is an object whose action_type member is a string of at
            most 512 octets that matches the action-type rule of
            <xref target="appendix-abnf"/>.</li>
            <li>required_fields is an array of at least one entry, and
            optional_fields is absent or an array.</li>
            <li>Every entry of either array is an object whose type member
            is a string and whose name member is a field name: a string
            that matches the field-name rule of
            <xref target="appendix-abnf"/>, which means it is non-empty and
            does not contain ":" (U+003A), and that is not action_type. No
            field name appears twice across the two arrays.</li>
            <li>An entry whose type is a field type of
            <xref target="fieldtypes"/> has no members other than name,
            type, notes, and the members that field type defines, and it
            carries every member that field type requires, well formed.
            For a code field, code_system is at most 2,048 octets and
            matches the code-system rule, and format matches the
            format-name rule, of <xref target="appendix-abnf"/>.</li>
            <li>The validation projection of the definition
            (<xref target="definition-digest"/>) is a value of the data
            model.</li>
          </ul>
          <t>An entry whose type is not a field type of
          <xref target="fieldtypes"/> is not member-checked; that field is
          refused as mistyped_field:&lt;name&gt; whenever it is present,
          and it does not make the definition nonconforming. The same
          holds for a code field whose format is well formed but not a
          registered code format. A definition written for a later field
          type therefore still computes while the field is absent. The
          form of an enum field is not checked here: an enum that does not
          resolve fails as mistyped_field:&lt;name&gt; when present
          (<xref target="enum-resolution"/>). Members of a definition
          other than action_type, required_fields, and optional_fields are
          not checked and never affect validation; in a host value they
          are never read (<xref target="host-values"/>).</t>
          <t>A definition that does not conform is refused as
          invalid_definition.</t>
        </section>
        <section anchor="definition-digest">
          <name>Definition Digest</name>
          <t>The validation projection of a definition that meets the
          first four conditions of <xref target="conformance"/> is the object
          with exactly three members:</t>
          <ul spacing="normal">
            <li>action_type;</li>
            <li>required_fields;</li>
            <li>optional_fields, which is the definition's optional_fields
            array, or an empty array when the definition has none.</li>
          </ul>
          <t>The arrays keep their order, because field order fixes the
          order of reasons (<xref target="reason-order"/>). Each entry is
          the definition's entry with its notes member removed and every
          other member kept.</t>
          <t>definition_sha256 is "sha256:" followed by the 64 lowercase
          hexadecimal digits of the SHA-256 digest of the RFC 8785
          encoding of the validation projection. It is defined only for a
          conforming definition; computing it for a nonconforming one
          yields invalid_definition.</t>
          <t>Everything outside the projection, including status,
          risk_class, summary, notes, digest_notes, references,
          supersedes, and superseded_by, never changes validation. Two
          definitions with equal definition_sha256 therefore validate
          every action object identically, given the same enum snapshots
          and the same registered field types and code formats. A field
          whose type or code format an implementation does not know is
          refused whenever present (<xref target="fieldtypes"/>), so
          implementations that know different field types or code formats
          can disagree about such a field. definition_sha256 does not cover
          the normalization guidance that notes and digest_notes give
          issuers (<xref target="security-definitions"/>). Computation and
          verification report the definition_sha256 of
          the definition they used (Sections <xref target="computation"
          format="counter"/> and <xref target="verification"
          format="counter"/>), and verification accepts an expected value.
          The reference registry lists the definition_sha256 of every type
          in each registry version. <xref target="example-projection"/>
          gives an example.</t>
          <t>This is the only digest this document calls a definition
          digest. A digest over a whole registry entry, including status
          or notes, identifies that entry's bytes, not its validation
          semantics, and a specification that uses one names it
          differently.</t>
        </section>
        <section anchor="resolution">
          <name>Resolution</name>
          <t>To resolve the definition for an action type, an
          implementation:</t>
          <ol spacing="normal">
            <li>collects every configured definition, from all of its
            definition sources, that is an object whose action_type member
            is exactly that string;</li>
            <li>refuses with unknown_action_type when none is
            collected;</li>
            <li>refuses with invalid_definition when any collected
            definition does not conform, or when two collected definitions
            have different definition_sha256 values;</li>
            <li>otherwise uses the collected definitions, which are all
            the same definition.</li>
          </ol>
          <t>The order in which definitions are configured never affects
          the result. A local definition that shares a name with a
          registered one resolves only when the two have the same
          validation projection.</t>
        </section>
        <section anchor="status">
          <name>Status and Succession</name>
          <t>status is "active" or "deprecated". Status never affects
          resolution, computation, or verification: a deprecated type
          resolves, computes, and verifies wherever its fields resolve,
          and deprecating a type never makes an earlier result invalid.
          Deprecation tells issuers to use the successor that
          superseded_by names; supersedes, on the successor, names its
          predecessor. Both are informative and outside definition_sha256.
          An issuer <bcp14>MAY</bcp14> decline to issue new CAIDs under a deprecated type
          as a matter of policy. A verifier <bcp14>MUST NOT</bcp14> refuse a CAID because
          its type is deprecated.</t>
        </section>
      </section>
      <section anchor="fieldtypes">
        <name>Field Types</name>
        <t>A field type fixes which values a field accepts. Every check
        applies to the whole value: nothing may precede or follow the
        matched text, not even a line feed. A string field accepts the
        empty string, and a required field that holds "" is present. The
        field types of this document are listed below; the CAID Field
        Types registry (<xref target="iana-field-types"/>) records
        them.</t>
        <dl newline="false" spacing="normal">
          <dt>string:</dt>
          <dd>A string.</dd>
          <dt>amount-string:</dt>
          <dd>
            <t>A decimal amount carried as a string that matches the
            amount-string rule of <xref target="appendix-abnf"/>. There
            is no exponent, leading "+", whitespace, or thousands
            separator, and the integer part has no leading zero. For
            example, "0", "0.50", "-0", and "-0.50" match, while "01.5",
            "00", "+1", "1e3", ".5", "1.", and "1,000" do not. The rule
            is lexical and never normalizes: "0.50" and "0.5" produce
            different digests (<xref target="equality"/>). A string that
            does not match is refused as invalid_amount:&lt;name&gt;, and
            a value that is not a string as
            mistyped_field:&lt;name&gt;.</t>
          </dd>
          <dt>digest:</dt>
          <dd>A string that matches the digest-field rule: the literal
          prefix "sha256:" followed by 64 lowercase hexadecimal
          characters. Used where a raw identifier must not appear in the
          object (<xref target="privacy"/>).</dd>
          <dt>enum:</dt>
          <dd>A string in the closed value set resolved as specified in
          <xref target="enum-resolution"/>. Its members are values,
          values_ref, values_snapshot, and values_sha256.</dd>
          <dt>code:</dt>
          <dd>A string that a registered code format matches as a whole
          (<xref target="code-fields"/>). Its members are code_system and
          format, both required. A string that does not match is refused
          as invalid_code:&lt;name&gt;.</dd>
          <dt>timestamp:</dt>
          <dd>A string that matches the timestamp rule of
          <xref target="appendix-abnf"/> and whose day does not exceed
          the length of its month in the proleptic Gregorian calendar.
          This is the <xref target="RFC3339"/> profile with an uppercase
          "T" and "Z" and UTC time: a lowercase "t" or "z", an offset
          other than "Z", and a second of 60 are refused. The fraction is
          lexical, so "2026-01-01T00:00:00.000Z" and
          "2026-01-01T00:00:00Z" are different content, as "0.50" and
          "0.5" are.</dd>
          <dt>integer:</dt>
          <dd>A number whose value (<xref target="numbers"/>) is a finite
          integer, whatever its literal form: 12, 12.0, and 1.2e1 are the
          integer 12. Magnitude is not part of the type. A finite integer
          beyond 2^53-1 is type-valid and is refused once, as
          unsupported_number (unsupported_value in a host action object past
          the value count, <xref target="host-values"/>). A literal whose correctly rounded value is an
          infinity (<xref target="numbers"/>) is not an integer, so it is
          refused both as mistyped_field:&lt;name&gt; and as
          unsupported_number. For counts only, never for money.</dd>
          <dt>boolean:</dt>
          <dd>true or false.</dd>
          <dt>object:</dt>
          <dd>An object. Values nested inside it are checked by computation
          phases 6 and 7, not by this field type: an object field that
          holds a fractional number fails no field type, and the number is
          refused as unsupported_number wherever phase 6 examines it
          (<xref target="computation"/>).</dd>
          <dt>array:</dt>
          <dd>An array. Values nested inside it are checked by computation
          phases 6 and 7, not by this field type.</dd>
        </dl>
        <t>Except where stated above, a present field whose value fails
        its field type is refused as mistyped_field:&lt;name&gt;. A field
        whose type is not one of these is refused as
        mistyped_field:&lt;name&gt; whenever it is present.</t>
        <t>A new validation constraint on an existing field type is always
        a new field type, never a new member on an existing type. An
        implementation of an earlier revision ignores an unknown member
        and would accept what a later one refuses, while an unknown field
        type makes it refuse. A registered field type or code format is
        never removed, renamed, or redefined; a changed grammar is
        registered as a new code format name.</t>
      </section>
      <section anchor="enum-resolution">
        <name>Enum Value-Set Resolution</name>
        <t>A member of a field definition is present when its name is
        present; a <tt>values</tt> or <tt>values_ref</tt> member whose value
        is null is present and malformed, not absent. An enum definition
        <bcp14>MUST</bcp14> take exactly one of three forms:</t>
        <dl newline="false" spacing="normal">
          <dt>Inline array:</dt>
          <dd>A non-empty, duplicate-free array of non-empty strings in
          <tt>values</tt>, and no <tt>values_ref</tt> member.</dd>
          <dt>Compact inline:</dt>
          <dd>A values_ref string that begins with <tt>inline:</tt>. The
          prefix is case-sensitive. The text after it is split at every
          "|" character, and each member is trimmed of leading and
          trailing U+0020 SPACE characters only; no other whitespace or
          control character is trimmed. The members
          <bcp14>MUST</bcp14> be non-empty and duplicate-free. A
          <tt>values</tt> member that accompanies this form
          <bcp14>MUST</bcp14> equal the resulting list exactly, in
          order.</dd>
          <dt>External:</dt>
          <dd>Any other non-empty values_ref string, together with
          <tt>values_snapshot</tt> and <tt>values_sha256</tt> members that
          are non-empty strings. The
          pinned array is the definition's own <tt>values</tt> member when
          that member is present, and otherwise a locally available snapshot
          whose values_ref, values_snapshot, and values_sha256 all match
          exactly. A supplied snapshot never replaces an embedded
          <tt>values</tt> member.</dd>
        </dl>
        <t>For an external reference, the issuer or verifier
        <bcp14>MUST</bcp14> check that the pinned array is a non-empty,
        duplicate-free array of non-empty strings, compute SHA-256 over the
        RFC 8785 canonical JSON encoding of that complete array, and compare
        the lowercase hexadecimal result, prefixed with <tt>sha256:</tt>, to
        values_sha256 before testing membership.</t>
        <t>An enum snapshot read from JSON text is a JSON object whose
        values_ref, values_snapshot, and values_sha256 members are strings
        and whose values member is the pinned array. Other members, such as
        a record of provenance, never affect resolution. A set of snapshots
        read from JSON text is a JSON array of such objects.</t>
        <t>A definition in none of these forms, a bare external values_ref, a
        missing or unresolved snapshot, a digest mismatch, or a value absent
        from the resolved list <bcp14>MUST</bcp14> fail as
        <tt>mistyped_field:&lt;name&gt;</tt> whenever the field is present.
        A type with such a field among its required fields therefore
        cannot produce or verify any CAID until the value set is pinned.
        Computation and verification
        <bcp14>MUST NOT</bcp14> fetch a mutable network resource to resolve an
        enum. An external source's later additions, removals, or corrections
        do not change a pinned array. Publishing a different accepted array
        requires a new action-type version, except for the monotone advance
        of <xref target="names"/>.</t>
      </section>
      <section anchor="code-fields">
        <name>Code Fields</name>
        <t>Some material values come from code systems that are large,
        change often, or are licensed: diagnosis and procedure codes,
        drug product codes, payment return reasons. A pinned value set
        cannot follow such a system without a new type version for every
        edition, and a licensed system cannot be redistributed as a
        snapshot. A code field identifies such a value by its system and
        its syntax instead:</t>
        <sourcecode type="json"><![CDATA[
{"name": "diagnosis_code", "type": "code",
 "code_system": "http://hl7.org/fhir/sid/icd-10-cm",
 "format": "icd-10-cm"}
]]></sourcecode>
        <ul spacing="normal">
          <li>code_system names the code system. It is a string of at most
          2,048 octets that matches the code-system rule of
          <xref target="appendix-abnf"/>: a scheme, ":", and URI
          characters, with no fragment and no IP-literal host.
          Implementations check only that rule. A code_system <bcp14>SHOULD</bcp14> be the
          absolute URI <xref target="RFC3986"/> that the code system's owner
          assigns. It is part of the validation projection, so it
          distinguishes fields with the same syntax from different systems.
          No implementation dereferences it.</li>
          <li>format names a registered code format. The code formats of
          this document are the rules of part A.4 of
          <xref target="appendix-abnf"/>, each named by its rule name. Their
          syntax follows the published code systems: ICD-10-CM
          <xref target="ICD-10-CM"/>, the National Drug Code
          <xref target="NDC"/>, CPT <xref target="CPT"/>, HCPCS Level II
          <xref target="HCPCS"/>, ISO 3166-2 <xref target="ISO3166-2"/>, the
          ISO 20022 External Code Sets <xref target="ISO20022"/>, and the
          Nacha Standard Entry Class codes <xref target="NACHA"/>. A format
          fixes syntax only, never which codes exist.</li>
          <li>The value is a string, valid if and only if the format
          matches the whole string. There is no normalization: the
          canonical form is the exact string. "G47.33" and "G4733" are
          different content, and only the first matches icd-10-cm. An
          issuer converts a native form to the format before
          computing.</li>
          <li>A string that the format does not match is refused as
          invalid_code:&lt;name&gt;. A value that is not a string, and any
          value of a field whose format is not a registered code format,
          is refused as mistyped_field:&lt;name&gt;.</li>
        </ul>
        <t>CAID pins the syntax and the system of a code field, never a
        value set. Whether a code exists in some edition of its system,
        is billable, or suits the action is a question for the relying
        party. A registry <bcp14>MUST NOT</bcp14> publish a value set for a code field.
        For a licensed system it <bcp14>MUST NOT</bcp14> redistribute codes, descriptors,
        or value sets at all; CPT, whose codes the American Medical
        Association licenses, is the leading example. The hcpcs format
        accepts HCPCS Level I (CPT) and Level II codes by syntax alone,
        so a type can carry either without the registry carrying a single
        CPT code. Each lexical form of a code is its own format, so that
        no format admits two spellings of one code: the 11-digit and the
        hyphenated 10-digit forms of a National Drug Code are the formats
        ndc-11 and ndc-10-hyphenated.</t>
        <t>A code system whose complete value list is small and stable, and
        whose maintenance agency publishes that list free of charge, such as
        ISO 3166-1 alpha-2 <xref target="ISO3166-1"/> or ISO 4217
        <xref target="ISO4217"/>, is an enum pinned to a snapshot
        (<xref target="enum-resolution"/>), never a code format. The Nacha Standard Entry Class codes are few,
        but their complete list is published only in the licensed Nacha
        Operating Rules, so nacha-sec is a code format.</t>
        <t>Every code format matches only strings of bounded length and
        compiles to a regular expression with no nested quantifiers, no
        quantified alternatives that can begin with the same character,
        and no optional repetition whose first characters overlap what can
        follow it. Matching therefore takes time linear in the length of
        the value, in backtracking and automaton engines alike
        (<xref target="security-redos"/>); this document calls that the
        linear-matching property. A new code format is registered in the
        CAID Code Formats registry (<xref target="iana-code-formats"/>) with
        its ABNF and must have this property.</t>
      </section>
      <section anchor="local">
        <name>Definition Sources and Unknown Types</name>
        <t>There is no reserved private-use name syntax. The
        distinction between registered and local types is presence: a
        type is either present in a definition source the
        implementation is configured with (the public registry, or a
        local definitions file in the same schema) or it is unknown.
        A deployment inside a single vendor's boundary can therefore
        use CAID with purely local definitions. Parties that use CAID
        across domains <bcp14>MUST</bcp14> pin the same exact definition,
        registry snapshot, or definition_sha256. A local deployment
        <bcp14>SHOULD</bcp14> give its types an organization-specific first
        segment (for example, acmecorp.ledger.close.1), so that a later
        registration does not take the same name. A local definition that
        collides
        by name with a different registered definition <bcp14>MUST NOT</bcp14> be
        treated as interoperable, and resolution refuses the pair when
        both are configured (<xref target="resolution"/>).</t>
        <t>A definition source read from JSON text is a JSON array of type
        definitions, or a JSON object whose types member is such an array,
        as the reference registry is. Other members of that object never
        affect resolution.</t>
        <t>An unknown type is a refusal for issuers and verifiers alike.
        A verifier that holds no definition for the type reports
        invalid_object with the detail unknown_action_type
        (<xref target="verification"/>). A deployment that correlates
        identifiers of unknown types by digest alone is not performing
        CAID verification and <bcp14>MUST NOT</bcp14> report the result as valid.</t>
      </section>
      <section anchor="tool-call-type">
        <name>The tool.call.1 Type</name>
        <t>Agent frameworks invoke a named tool with an argument
        object. That is a common material action in agent deployments.
        This section registers a type for it so that its action object
        is fixed by the registry rather than by an implementation. The
        registration is the tool.call.1 entry of the reference registry
        <xref target="CAID-REGISTRY"/>, reproduced here member for
        member:</t>
        <sourcecode anchor="ex-tool-definition" type="json"><![CDATA[
{
  "action_type": "tool.call.1",
  "status": "active",
  "risk_class": "varies-by-tool",
  "summary": "Invocation of a named agent-framework tool with a
    complete argument object.",
  "required_fields": [
    {"name": "target",
     "type": "string",
     "notes": "stable identity of the service that will execute the
       call, supplied by the governing profile and compared
       case-sensitively; use the literal local only when execution
       occurs in the caller process; never infer this value from
       ambient routing metadata"},
    {"name": "tool",
     "type": "string",
     "notes": "tool name exactly as the invoking framework declares
       it"},
    {"name": "args",
     "type": "object",
     "notes": "complete argument object handed to the tool after
       framework defaults; all nested values remain subject to the
       CAID numeric profile"}
  ],
  "optional_fields": [
    {"name": "occurrence_id",
     "type": "string",
     "notes": "executor occurrence identity when the relying profile
       requires two otherwise identical invocations to remain
       distinct"}
  ],
  "digest_notes": "The CAID Action Object includes action_type,
    target, tool, args, and occurrence_id when present.
    Framework-local selector or routing hints derived from args are
    not separate members. Existing base:sha256:<hex> executor-binding
    strings are a different profile and are not CAIDs.",
  "references": []
}
]]></sourcecode>
        <t>Line breaks inside the strings of this registration are for
        presentation only; each line break and the indentation after it
        read as one space.</t>
        <t>occurrence_id is optional because args can already carry an
        occurrence identifier. A deployment that needs to tell repeated
        identical calls apart (<xref target="security-replay"/>)
        <bcp14>MUST</bcp14> include occurrence_id unless args already
        carries an identifier that tells them apart, and one whose calls
        need to resist recovery by guessing (<xref target="privacy"/>)
        <bcp14>MUST</bcp14> include an occurrence_id that carries at least
        128 bits of entropy unless args already carries an identifier with
        at least that entropy.</t>
        <t>The member is named <tt>args</tt>. An implementation
        <bcp14>MUST NOT</bcp14> substitute another name such as
        <tt>arguments</tt> for the same content: the member name is
        inside the canonical bytes, so a rename produces a different
        digest for an identical call, and two conforming-looking
        adapters then emit identifiers that never compare equal.</t>
        <t>A framework-derived selector or routing key
        <bcp14>MUST NOT</bcp14> be added as a member when it is
        computed from values already present in <tt>args</tt>. Such a
        hint adds no material content and, being optional in practice,
        makes the digest depend on whether a particular adapter chose
        to compute it. This does not apply to <tt>target</tt>, which is
        material, is a required field, and is not derived from
        <tt>args</tt>.</t>
        <t>The <tt>target</tt> field is required because a tool name is
        not unique across providers. Where a caller can reach two
        services offering the same tool name, an object omitting the
        callee yields one identifier for two different executions, and
        a permit issued against one provider recomputes equal against
        the other. An issuer <bcp14>MUST NOT</bcp14> omit
        <tt>target</tt> merely because its deployment currently reaches
        one provider: the identifier can outlive that assumption. The
        governing profile defines the stable target identifier;
        implementations compare its exact, case-sensitive string and
        <bcp14>MUST NOT</bcp14> infer it from ambient connection state,
        a display label, or a derived routing hint.</t>
        <t>A tool.call.1 action object consists of exactly
        <tt>action_type</tt>, <tt>target</tt>, <tt>tool</tt>, and
        <tt>args</tt>, plus <tt>occurrence_id</tt> when present. An issuer
        <bcp14>MUST NOT</bcp14> add any other member to a tool.call.1 action
        object: content material to the call belongs in <tt>args</tt>,
        <tt>target</tt>, or <tt>occurrence_id</tt>, and any other member
        makes the digest depend on the adapter. A verifier still accepts
        extra members (<xref target="action-object"/>). The complete object
        is canonicalized and encoded as the CAID string in
        <xref target="identifier"/>. Existing framework-local strings,
        such as the <tt>base:sha256:&lt;hex&gt;</tt> executor-binding
        strings that the digest_notes name, are not CAIDs and
        <bcp14>MUST NOT</bcp14> be compared with one.</t>
        <t>For example, this action object:</t>
        <sourcecode anchor="ex-tool-object" type="json"><![CDATA[
{
  "action_type": "tool.call.1",
  "target": "https://payments.example",
  "tool": "payment.release",
  "args": {
    "amount_usd": 4000,
    "beneficiary": "vendor@example.com",
    "memo": "invoice 7781"
  }
}
]]></sourcecode>
        <t>has the following CAID under <tt>jcs-sha256</tt>:</t>
<sourcecode anchor="ex-tool-caid"><![CDATA[
=============== NOTE: '\' line wrapping per RFC 8792 ================

caid:1:tool.call.1:jcs-sha256:FdawgFwgN5tAtiZa-SCkVDrV3dS9w1yeXVQaDa\
ZLQQQ
]]></sourcecode>
        <t>The example's args carries amount_usd as a JSON number, as the
        tool receives it; <xref target="security-parsing"/> states how a
        relying party that evaluates such a number reads it.</t>
        <t>This registration is motivated by a divergence observed in the
        author's own software: two of its framework adapters hashed the
        same argument object under different member names (args and
        arguments), and one also hashed a derived selector.
        The resulting strings were not CAIDs, but the incident showed
        why a future cross-framework CAID profile cannot leave its
        material member names to implementers.</t>
        <t>All nested members of <tt>args</tt> remain subject to the
        data model of <xref target="data-model"/>. A framework call
        containing a fractional JSON number can use its own exact-action
        binding profile, or map the quantity to a CAID type that carries
        the value as a string; it is not a conforming
        <tt>tool.call.1</tt> CAID.</t>
        <t>A call whose arguments carry a large body inline, such as a
        file or an image, can push the action object past the canonical
        limit of 16,777,216 octets (<xref target="limits"/>). Such a call
        is not a conforming tool.call.1 CAID. It is identified by a
        tool-specific type in which the large member is a digest field
        over the body's octets: the digest binds the body without placing
        it in the action object, and the body travels beside the
        artifact.</t>
      </section>
    </section>
    <section anchor="computation">
      <name>Computation</name>
      <t>A conforming issuer computes a CAID from an action object
      (JSON text or a host value), a suite name, its configured
      definition sources, and the enum snapshots available to it. A
      suite, definition-source, or enum-snapshot option of the wrong type
      is treated as absent. An absent suite yields unknown_suite: a suite
      given as anything other than a string is no suite. Absent definition
      sources leave every action type unknown, so a valid action type is
      unknown_action_type. Absent enum snapshots refuse nothing by
      themselves; they matter only to a present field whose external enum
      has no embedded values member, which is then
      mistyped_field:&lt;name&gt; (<xref target="enum-resolution"/>).</t>
      <t>Computation evaluates the phases of
      <xref target="tab-compute"/> in order. Phases 0 through 2 are
      gates: the first gate that fails yields exactly one reason, and
      computation stops. When the gates pass, phases 3 through 7 are all
      evaluated, and every reason they produce is collected. The reason
      strings are normative. Each reason of phases 3 and 4 takes the name
      of the field it concerns as its parameter
      (<xref target="appendix-reasons"/>), as in
      missing_material_field:&lt;name&gt;.</t>
      <t>A field is present when the object has a member of that name
      of its own. A name that an implementation's object model inherits
      from elsewhere, for example through an ECMAScript prototype, is not
      present. Phase 4 checks only present fields that the definition
      declares, in required_fields or in optional_fields. Enum validation
      includes the snapshot resolution and integrity check of
      <xref target="enum-resolution"/>. A string that contains an
      unpaired surrogate has no UTF-8 encoding, and Section 3.2.2.2 of
      <xref target="RFC8785"/> requires a JCS implementation to refuse
      it; phase 7 is that refusal. A host value of kind "object" that
      holds values outside the data model passes phase 1 and is refused by
      phase 6 or 7. Phase 6 does not examine values inside an object or
      array nested deeper than 64, or beyond a reference back to an
      enclosing object or array, and the value count does not count them
      (<xref target="data-model"/>). When a host action object is made of
      more values than the value count (<xref target="host-values"/>),
      phase 6 yields no reason and phase 7 yields unsupported_value,
      whatever the value holds; phases 3 and 4 still run.</t>
      <table anchor="tab-compute">
        <name>Computation Phases</name>
        <thead>
          <tr><th>Phase</th><th>Reasons</th><th>Refused when</th></tr>
        </thead>
        <tbody>
          <tr><td>0</td><td>malformed_json</td><td>the object is JSON text
          that fails <xref target="json-text"/></td></tr>
          <tr><td>1</td><td>invalid_action_type</td><td>the value's kind
          (<xref target="details"/>) is not "object", or its action_type
          member is absent, is not a string, is longer than 512 octets, or
          does not match the action-type rule of
          <xref target="appendix-abnf"/></td></tr>
          <tr><td>2</td><td>unknown_action_type,
          invalid_definition</td><td>resolution fails
          (<xref target="resolution"/>)</td></tr>
          <tr><td>3</td><td>missing_material_field</td><td>a required field
          is not present</td></tr>
          <tr><td>4</td><td>mistyped_field, invalid_amount,
          invalid_code</td><td>a present declared field fails its field type
          (<xref target="fieldtypes"/>)</td></tr>
          <tr><td>5</td><td>unknown_suite</td><td>the suite is not a
          registered suite that the implementation implements</td></tr>
          <tr><td>6</td><td>unsupported_number</td><td>a number that an
          object or array at depth 64 or less holds, in an object within the
          value count, is outside the data model</td></tr>
          <tr><td>7</td><td>unsupported_value</td><td>any other value is
          outside the data model, including a string or member name with an
          unpaired surrogate or a noncharacter, nesting beyond 64, a
          canonical encoding beyond 16,777,216 octets, and a host value past
          the value count</td></tr>
        </tbody>
      </table>
      <section anchor="reason-order">
        <name>Reason Order</name>
        <t>The collected reasons are sorted by phase. Within phase 3 they
        are sorted by the field's index in required_fields, and within
        phase 4 by the field's index in required_fields followed by
        optional_fields. Identical reason strings are then reduced to the
        first. A field yields at most one phase 4 reason, and phases 5, 6,
        and 7 yield at most one reason each.</t>
        <t>The order does not depend on the order in which an
        implementation traverses the object, so every implementation, and
        every suite, reports the same list for the same input. In
        particular unsupported_number always precedes unsupported_value.
        The result is an ordered list; implementations <bcp14>MUST NOT</bcp14> reorder,
        merge, or add reasons. <xref target="example-refusal"/> gives an
        example.</t>
      </section>
      <section anchor="compute-result">
        <name>Result</name>
        <t>On success, computation returns three strings: the CAID; the
        digest, which is the suite's digest of the canonical bytes, written
        for the two suites of this document as "sha256:" followed by 64
        lowercase hexadecimal digits; and the definition_sha256 of the
        resolved definition. On failure it returns the ordered list of
        reasons and no identifier. Computation is fail-closed: malformed or
        junk input of any shape yields reasons, never an exception or a
        partial identifier (<xref target="overview"/>).</t>
      </section>
    </section>
    <section anchor="verification">
      <name>Verification</name>
      <t>A conforming verifier checks a presented CAID string against a
      presented action object (JSON text or a host value), using its own
      configured definition sources and enum snapshots and, when the
      relying party supplies one, an expected definition_sha256. An
      expected definition_sha256 that is supplied is never treated as
      absent: phase 5 compares it, whatever its type, with the
      definition_sha256 of the resolved definition, and any value other
      than that string is definition_mismatch. A host language's
      representation of an absent option, such as an ECMAScript undefined,
      is absent. The verifier evaluates the phases of
      <xref target="tab-verify"/> in order.
      Phases 1 through 3 are gates that yield exactly one reason and stop
      verification. Phases 4 through 7 are all evaluated, and each yields
      at most one reason.</t>
      <table anchor="tab-verify">
        <name>Verification Phases</name>
        <thead>
          <tr><th>Phase</th><th>Reasons</th><th>Refused when</th></tr>
        </thead>
        <tbody>
          <tr><td>1</td><td>malformed_caid, unknown_suite</td><td>parsing
          fails (<xref target="parsing"/>)</td></tr>
          <tr><td>2</td><td>malformed_json</td><td>the object is JSON text
          that fails <xref target="json-text"/></td></tr>
          <tr><td>3</td><td>invalid_object</td><td>the value's kind is not
          "object"</td></tr>
          <tr><td>4</td><td>action_type_mismatch</td><td>the object's
          action_type member is absent, is not a string, or is not the
          action type in the CAID</td></tr>
          <tr><td>5</td><td>definition_mismatch</td><td>an expected
          definition_sha256 was supplied, a conforming definition resolved,
          and the expected value is not a string equal to its
          definition_sha256</td></tr>
          <tr><td>6</td><td>unknown_suite, digest_mismatch</td><td>unknown_suite
          when the verifier does not implement the CAID's suite; otherwise
          digest_mismatch when the object can be canonicalized
          (<xref target="data-model"/>) and its digest differs from the
          CAID's</td></tr>
          <tr><td>7</td><td>invalid_object</td><td>computation phases 1
          through 4, 6, and 7 over the object yield any reason</td></tr>
        </tbody>
      </table>
      <t>The in-object action type check of phase 4 is mandatory; see
      <xref target="digest"/> and <xref target="security"/>. No digest
      comparison is made for an object that cannot be canonicalized. An
      identifier whose object fails validation is invalid_object, not
      merely mismatched: a digest that matches an invalid object still
      binds nothing material. The suite check of computation phase 5 is
      not part of phase 7, because phase 6 checks the suite of the
      presented CAID.</t>
      <t>Phases 5 and 7 resolve the definition of the object's own
      action_type member, not the type named in the CAID. They run even
      when phase 4 reports action_type_mismatch, and the definition_sha256
      in the result is that of the object's type.</t>
      <t>Phase 1 is the strict parse of <xref target="parsing"/>, which
      yields malformed_caid or, for a grammatical suite outside the suite
      registry, unknown_suite. Phase 6 yields unknown_suite for a
      registered suite that the verifier does not implement.</t>
      <t>The result has the members valid, reasons, and details, plus
      definition_sha256 whenever a conforming definition resolved,
      whether or not the result is valid. valid is true if and only if
      reasons is empty. Verification is deterministic and offline: the
      same inputs produce the same result, and any third party with the
      object, the identifier, the definitions, and any referenced enum
      snapshots can replay the check without contacting anyone.</t>
      <section anchor="details">
        <name>Verification Details</name>
        <t>details lists one entry for each reason, in the order of
        reasons. The exception is invalid_object, which contributes one
        entry for each computation reason it stands for instead of one for
        itself: for verification phase 7, the reasons of computation phases
        1 through 4, 6, and 7; for verification phase 3, the computation
        reason for the value, invalid_action_type. Each entry is an object
        with exactly these four members:</t>
        <dl newline="false" spacing="normal">
          <dt>reason:</dt>
          <dd>The reason string.</dd>
          <dt>field:</dt>
          <dd>The parameter of a parameterized reason, the string
          action_type for invalid_action_type and action_type_mismatch,
          and null otherwise.</dd>
          <dt>rule:</dt>
          <dd>The identifier of the rule that failed, from
          <xref target="tab-details"/>.</dd>
          <dt>observed:</dt>
          <dd>The kind of value the check saw, or null. For a reason whose
          observed source in <xref target="tab-details"/> is the member,
          it is the kind of the object's own member named by field, or
          "absent" when there is no such member; when the value is not an
          object, it is the kind of the value itself. For malformed_caid it
          is the kind of the CAID argument.</dd>
        </dl>
        <t>A kind is one of "absent", "null", "boolean", "number",
        "string", "array", "object", and "unsupported". Every JSON number,
        and every host value that the language binding represents as a
        number (<xref target="host-values"/>), is "number", whether or not
        it is in the data model; "unsupported" is a host value of no JSON
        kind, such as a map, a date, or a numeric type that the binding
        does not represent as a number.
        Details carry no other information. They are deterministic: two
        conforming verifiers given the same inputs produce the same
        details, as in the example of <xref target="example-verify"/>.</t>
<table anchor="tab-details">
  <name>Verification Detail Rules</name>
  <thead><tr><th>Reason</th><th>rule</th><th>field</th><th>observed</th></tr></thead>
  <tbody>
    <tr><td>malformed_json</td><td>json-text</td><td>null</td><td>null</td></tr>
    <tr><td>malformed_caid</td><td>caid</td><td>null</td><td>the CAID argument</td></tr>
    <tr><td>unknown_suite</td><td>suite</td><td>null</td><td>null</td></tr>
    <tr><td>invalid_action_type</td><td>action-type</td><td>action_type</td><td>the member</td></tr>
    <tr><td>unknown_action_type</td><td>definition-resolution</td><td>null</td><td>null</td></tr>
    <tr><td>invalid_definition</td><td>definition-conformance</td><td>null</td><td>null</td></tr>
    <tr><td>definition_mismatch</td><td>definition-sha256</td><td>null</td><td>null</td></tr>
    <tr><td>missing_material_field</td><td>required-field</td><td>the parameter</td><td>the member</td></tr>
    <tr><td>mistyped_field</td><td>field-type</td><td>the parameter</td><td>the member</td></tr>
    <tr><td>invalid_amount</td><td>amount-string</td><td>the parameter</td><td>the member</td></tr>
    <tr><td>invalid_code</td><td>code-format</td><td>the parameter</td><td>the member</td></tr>
    <tr><td>unsupported_number</td><td>number</td><td>null</td><td>null</td></tr>
    <tr><td>unsupported_value</td><td>data-model</td><td>null</td><td>null</td></tr>
    <tr><td>action_type_mismatch</td><td>action-type-equal</td><td>action_type</td><td>the member</td></tr>
    <tr><td>digest_mismatch</td><td>digest-equal</td><td>null</td><td>null</td></tr>
  </tbody>
</table>
      </section>
    </section>
    <section anchor="effect-boundary">
      <name>Effect-Boundary Use</name>
      <t>When a CAID is used at an effect boundary, the enforcing executor
      <bcp14>MUST</bcp14> construct the action object from the operation it
      is prepared to invoke, or <bcp14>MUST</bcp14> validate every material
      field against a relying-party-controlled system of record. It
      <bcp14>MUST</bcp14> recompute the CAID from that object. It
      <bcp14>MUST</bcp14> then invoke the operation using only the values it
      constructed or validated, read from the data-model value that
      <xref target="json-text"/> or <xref target="host-values"/> produced,
      and <bcp14>MUST NOT</bcp14> use any other member, such as an optional
      field or an extra member, unless it validated that member too. It
      <bcp14>MUST NOT</bcp14> re-read the action object through a separate
      parser to drive the invocation (<xref target="security-parsing"/>). A
      CAID received from a presenter <bcp14>MAY</bcp14> be compared with the
      recomputed value, but <bcp14>MUST NOT</bcp14> replace executor-side
      construction.</t>
      <t>Discovery documents, authorization challenges, receipts, permits,
      and other evidence can carry a CAID. Their identifiers are claims about
      content under their own integrity and trust rules. Before comparing
      such an identifier with the executor-computed CAID, the artifact
      <bcp14>MUST</bcp14> be verified under its native specification and
      the relying party's native trust anchors
      (<xref target="mapping-boundary"/>). If the native representation
      differs from the CAID action object, comparison <bcp14>MUST</bcp14>
      use an exact, relying-party-pinned Action-Mapping Profile as
      specified in <xref target="mapping"/>.</t>
      <t>A successful comparison establishes only the matching result in this
      document. Evidence satisfaction, local authorization, one-time
      consumption, invocation, execution status, reconciliation, revocation,
      and remedy remain separate protocol decisions. The Action Evidence
      Boundary <xref target="I-D.schrock-action-evidence-boundary"/> and the
      Authorization Evidence Chain
      <xref target="I-D.schrock-ep-authorization-evidence-chain"/> are
      informative examples of specifications that keep those decisions
      separate.</t>
      <t>A multi-stage authorization program <bcp14>MAY</bcp14> bind a root CAID and the
      digests of predecessor stage receipts in a separate program artifact.
      It <bcp14>MUST NOT</bcp14> reinterpret the root CAID as proof that any stage completed.
      A stage that authorizes a materially different action uses a different
      CAID. Program order, quorum, stage completion, and authority attenuation
      are outside the CAID trust boundary.</t>
    </section>
    <section anchor="mapping">
      <name>Action-Mapping Profile</name>
      <t>Two native formats can represent the same material action with
      different member names, nesting, or format-local metadata. Direct
      digest comparison cannot establish whether those representations
      denote the same material action. This section defines a narrow,
      explicit projection into a common CAID action type. The projection
      is identified by its digest and pinned by the relying party.</t>
      <t>A mapping result is content correlation only. It does not
      establish identity, authority, authorization, provenance,
      execution, or legal reliance.</t>
      <section anchor="mapping-boundary">
        <name>Native Verification Boundary</name>
        <t>Before mapping, each source artifact <bcp14>MUST</bcp14> be verified under
        its native specification and the relying party's native trust
        anchors. The source object supplied to the mapper <bcp14>MUST</bcp14> be the
        payload whose integrity that native verification established,
        or a projection for which the native adapter has established
        that every mapped source field is covered by the native
        integrity mechanism. A mapper <bcp14>MUST NOT</bcp14> read an unsigned sibling
        member and treat it as part of a signed payload.</t>
        <t>The source media type, schema identifier, and version supplied
        to the mapper <bcp14>MUST</bcp14> come from relying-party configuration or the
        native verifier. They <bcp14>MUST NOT</bcp14> be accepted solely from a label
        inside the presenter-controlled artifact. CAID mapping does not
        replace native verification.</t>
        <t>The mapping interface <bcp14>MUST</bcp14> receive a native
        verification result that is the boolean true through a
        relying-party-controlled adapter or equivalent trusted call path.
        That result is an API precondition, not a member a presenter can
        place in the artifact. Any other native verification result,
        including an absent one, yields INDETERMINATE.</t>
      </section>
      <section anchor="mapping-object">
        <name>Mapping Profile Object</name>
        <t>A version 1 profile is a JSON object with the following
        shape:</t>
<sourcecode anchor="ex-map-profile" type="json"><![CDATA[
{
  "@version": "CAID-MAPPING-PROFILE-v1",
  "profile_id": "urn:example:map:checkout-to-order:1",
  "source_format": {
    "media_type": "application/example-checkout+json",
    "schema": "urn:example:checkout:1",
    "version": "1"
  },
  "target_action_type": "order.place.1",
  "loss_policy": "no-material-field-loss",
  "material_source_paths": [
    "/checkout/order_id",
    "/checkout/merchant_id",
    "/checkout/total_amount",
    "/checkout/currency",
    "/checkout/line_items",
    "/checkout/customer_id",
    "/checkout/fulfillment"
  ],
  "rules": [
    {"source_path": "/checkout/order_id",
     "target_field": "order_id", "transform": "copy"},
    {"source_path": "/checkout/merchant_id",
     "target_field": "merchant_ref", "transform": "sha256-utf8"},
    {"source_path": "/checkout/total_amount",
     "target_field": "total_amount", "transform": "copy"},
    {"source_path": "/checkout/currency",
     "target_field": "currency", "transform": "copy"},
    {"source_path": "/checkout/line_items",
     "target_field": "items_digest", "transform": "sha256-jcs"},
    {"source_path": "/checkout/customer_id",
     "target_field": "customer_ref", "transform": "sha256-utf8"},
    {"source_path": "/checkout/fulfillment",
     "target_field": "fulfillment_ref", "transform": "sha256-jcs"}
  ]
}
]]></sourcecode>
        <t>The profile digest is the lowercase hexadecimal SHA-256
        digest of the profile's JCS serialization, prefixed with
        "sha256:". The relying party <bcp14>MUST</bcp14> pin that exact digest. A
        profile identifier by itself is not a trust anchor.</t>
        <t>Version 1 is a closed object model. The members of a profile
        are exactly @version, profile_id, source_format,
        target_action_type, loss_policy, material_source_paths, rules,
        and, optionally, omitted_source_fields. source_format has exactly
        media_type, schema, and version; a rule has exactly source_path,
        target_field, and transform; an omitted_source_fields entry has
        exactly source_path and reason. A mapper <bcp14>MUST</bcp14> reject an unknown
        member at any of these levels, and <bcp14>MUST</bcp14> treat a member whose value
        is null as malformed. This prevents a misspelled or future policy
        member from being covered by the profile digest while being
        silently ignored by the mapping algorithm.</t>
        <t>The members are constrained as follows. Lengths are counted
        in UTF-8 octets (<xref target="limits"/>), and strings are
        compared as exact sequences of code points.</t>
        <ul spacing="normal">
          <li>@version is "CAID-MAPPING-PROFILE-v1".</li>
          <li>profile_id, the three source_format members, and
          target_action_type are strings of 1 to 512 octets.
          source_format binds the exact media type, schema identifier,
          and version accepted by the profile. target_action_type names a
          type from a definition source pinned by the relying party.</li>
          <li>loss_policy is a registered loss policy (below).</li>
          <li>rules is an array of 1 to 128 rules. Each source_path is a
          JSON Pointer <xref target="RFC6901"/> other than the empty
          pointer, of at most 2048 octets: the source-path rule of
          <xref target="appendix-abnf"/>. Each target_field is a field
          name (<xref target="conformance"/>) other than action_type. Each
          transform is a registered transform (below).</li>
          <li>material_source_paths is a non-empty array of source
          paths.</li>
          <li>omitted_source_fields, when present, is an array whose
          entries each carry a source path and a reason string of 1 to
          2048 octets.</li>
          <li>No two rules share a source_path or a target_field, no path
          repeats within material_source_paths or within
          omitted_source_fields, the set of rule source paths equals the
          set of material_source_paths, and no omitted path is also a rule
          source path. Each material source path therefore has exactly one
          rule.</li>
          <li>Every required field of the target action type is the
          target_field of exactly one rule.</li>
        </ul>
        <t>The loss policies form a closed set, recorded in the CAID
        Mapping Loss Policies registry
        (<xref target="iana-loss-policies"/>):</t>
        <dl newline="false" spacing="normal">
          <dt>no-material-field-loss:</dt>
          <dd>omitted_source_fields is absent or empty. Every concept the
          source treats as material is mapped.</dd>
          <dt>declared-source-semantic-loss:</dt>
          <dd>omitted_source_fields is non-empty. Each entry names a source
          path that the source format treats as material to its own action
          identity but that the target type does not carry, with a reason.
          A mapping under this policy never succeeds: it yields
          INDETERMINATE with declared_source_semantic_loss, which makes the
          loss reviewable instead of silent.</dd>
        </dl>
        <t>The transforms form a closed set, recorded in the CAID Mapping
        Transforms registry (<xref target="iana-transforms"/>):</t>
        <dl newline="false" spacing="normal">
          <dt>copy:</dt>
          <dd>Copy the source value after confirming that it is a value of
          the data model.</dd>
          <dt>sha256-utf8:</dt>
          <dd>For a source string, emit "sha256:" followed by the
          lowercase hexadecimal SHA-256 digest of its UTF-8 bytes.</dd>
          <dt>sha256-jcs:</dt>
          <dd>Emit "sha256:" followed by the lowercase hexadecimal
          SHA-256 digest of the source value's JCS representation.</dd>
          <dt>sha256-hex-to-digest:</dt>
          <dd>For a source string of exactly 64 lowercase hexadecimal
          characters (the hex-sha256 rule), emit "sha256:" followed by
          that string.</dd>
        </dl>
        <t>A mapper <bcp14>MUST</bcp14> refuse an unregistered transform or loss policy.
        Version 1 performs no unit conversion, currency conversion, date
        inference, case folding, or lossy normalization.</t>
      </section>
      <section anchor="mapping-algorithm">
        <name>Mapping and Comparison Algorithm</name>
        <t>A mapper takes a source, a profile, the verifier-derived source
        descriptor, the relying party's pinned profile digest, the native
        verification result, definition sources, enum snapshots, and a
        suite. The suite is jcs-sha256 when the suite argument is absent,
        and only then. A suite argument that is present but is not a
        string is no suite, and stage D reports
        mapped_action:unknown_suite.
        The mapper runs four stages. Each ends in a gate: when a stage
        produces a reason, mapping stops after that stage, except that
        stage B always runs after stage A and the two stop together.</t>
        <dl newline="true" spacing="normal">
          <dt>Stage A, the profile.</dt>
          <dd>If the profile is outside the data model or is not an
          object, its @version differs, it has a member outside the closed shape, or a
          member fails its type, length, pointer, field-name, or closed-set
          constraint, stage A yields exactly invalid_mapping_profile.
          Otherwise stage A evaluates all of the following:
          invalid_mapping_profile when a uniqueness, set-equality,
          disjointness, or loss-policy constraint fails; unknown_action_type
          or invalid_definition when the target type does not resolve
          (<xref target="resolution"/>); and, when it resolves,
          unmapped_material_field:&lt;name&gt; for each required field of
          its definition that is no rule's target_field, in required_fields
          order.</dd>
          <dt>Stage B, the preconditions.</dt>
          <dd>native_verification_required when the native verification
          result is not the boolean true; mapping_profile_unpinned when no
          pinned digest was supplied or it differs from the profile digest,
          which a profile outside the data model does not have;
          source_format_mismatch when the source descriptor is not an
          object, when the profile is not an object, or when the RFC 8785
          encoding of the descriptor differs from that of the profile's
          source_format member, as it does when either has no RFC 8785
          encoding or that member is absent; source_not_object when the source is not
          an object; source_not_canonicalizable when the source is not an
          object of the data model, so that no source digest exists; and
          declared_source_semantic_loss when the profile's loss_policy
          member is declared-source-semantic-loss. In this stage an object
          is a value whose kind (<xref target="details"/>) is "object", and
          stage B reads the profile's source_format and loss_policy members
          whenever the profile is an object, whether or not the profile is
          in the data model and whether or not stage A failed. A source that
          is not an object yields both source_not_object and
          source_not_canonicalizable. If stage A or stage B produced any
          reason, mapping stops.</dd>
          <dt>Stage C, extraction.</dt>
          <dd>For each rule, in rule order, the mapper resolves source_path
          against the source as specified in <xref target="RFC6901"/> and
          applies the transform. A rule yields at most one reason:
          invalid_source_path:&lt;p&gt; when a reference token applied to
          an array does not match the array-index rule;
          missing_source_field:&lt;p&gt; when a token names no member of an
          object, an index is not less than the array's length, or a token
          is applied to a value that is neither an object nor an array;
          source_value_type_mismatch:&lt;p&gt; when sha256-utf8 or
          sha256-hex-to-digest receives a value it does not accept; and
          source_value_not_canonicalizable:&lt;p&gt; when copy or
          sha256-jcs receives a value outside the data model. Here
          &lt;p&gt; is the rule's source_path. Two of these cannot occur:
          unknown_transform:&lt;p&gt;, because stage A refuses an
          unregistered transform, and
          source_value_not_canonicalizable:&lt;p&gt;, because stage B admits
          only a source that is an object of the data model, and every value
          inside such an object is in the data model. Both are registered
          for completeness. If any rule produced a reason, mapping
          stops.</dd>
          <dt>Stage D, the projected action.</dt>
          <dd>The projected action object has an action_type member equal
          to target_action_type and one member per rule, named by its
          target_field and holding its transformed value, and no other
          members. Computation (<xref target="computation"/>) runs over it
          with the requested suite, definition sources, and enum snapshots.
          If computation refuses, each of its reasons r, in computation
          order, becomes mapped_action:r, for example
          mapped_action:missing_material_field:amount. Otherwise the
          mapping succeeds.</dd>
        </dl>
        <t>A source received as JSON text is decoded as specified in
        <xref target="json-text"/> before mapping begins. A decoding failure
        is the decode operation's malformed_json. It yields no mapping
        result and no comparison, and it is never a mapping or comparison
        reason.</t>
        <t>A successful mapping result carries the source digest
        ("sha256:" and the SHA-256 of the source's JCS encoding), the
        profile digest, the projected action object, the resulting CAID,
        its digest, the definition_sha256 of the target type's
        definition, and the suite. A comparison result retains both
        mapping results. A consumer that persists or transmits only the
        final verdict or CAID loses the information needed to reproduce
        which profiles and source objects produced that result.
        <xref target="example-mapping"/> gives an example.</t>
        <t>Both mapping results of a comparison are computed under one
        suite. Comparison of two mapping results returns exactly one
        of:</t>
        <dl newline="false" spacing="normal">
          <dt>INDETERMINATE:</dt>
          <dd>Either mapping failed, or both succeeded but target
          different action types. In the first case the reasons are those
          of the left mapping, each prefixed with "left:", followed by
          those of the right mapping, each prefixed with "right:", for
          example left:mapped_action:invalid_amount:amount. In the second
          case the reason is target_action_type_mismatch.</dd>
          <dt>EQUIVALENT_UNDER_PROFILE:</dt>
          <dd>Both mappings succeeded, both target the same action
          type, and the resulting CAID strings are byte-equal. There are
          no reasons.</dd>
          <dt>NOT_EQUIVALENT:</dt>
          <dd>Both mappings succeeded and target the same action type,
          but the resulting CAIDs differ. The reason is
          material_projection_mismatch.</dd>
        </dl>
        <t>A consumer <bcp14>MUST NOT</bcp14> convert INDETERMINATE into equivalence.
        It also <bcp14>MUST NOT</bcp14> treat EQUIVALENT_UNDER_PROFILE as authorization.
        Authorization remains a separate relying-party decision over
        separately verified evidence.</t>
      </section>
      <section anchor="mapping-reasons">
        <name>Mapping Reasons</name>
        <t>The mapping reasons are listed in
        <xref target="tab-mapping-reasons"/>, except unknown_action_type
        and invalid_definition, which stage A shares with computation and
        which <xref target="tab-core-reasons"/> lists. Within a mapping
        result,
        stage A reasons come first, in the order invalid_mapping_profile,
        unknown_action_type, invalid_definition, and then the
        unmapped_material_field reasons in required_fields order, followed
        by stage B reasons in the order listed above; identical reason
        strings are reduced to the first. Stage C reasons are in rule
        order, and stage D reasons in computation order. These are the
        only mapping reasons: a conforming mapper produces a result for
        every input and never reports an internal fault as a reason.</t>
      </section>
      <section anchor="mapping-assumption">
        <name>Completeness Assumption</name>
        <t>The algorithm proves that a pinned profile maps every field
        the target action type declares material. It cannot prove that
        the profile author correctly identified every material concept
        in the native source schema. The relying party's selection and
        review of mapping profiles is therefore an explicit policy
        assumption. Profiles <bcp14>SHOULD</bcp14> be versioned, publicly reviewable,
        and accompanied by positive, negative, and indeterminate
        conformance vectors.</t>
      </section>
    </section>
    <section anchor="not">
      <name>What a CAID Is Not</name>
      <t>Under the selected suite's security assumptions
      (<xref target="security-digest"/>), recomputing a CAID
      establishes that an identifier commits to the supplied canonical typed
      content. Comparing CAIDs emitted directly from the same action type, or
      emitted through pinned Action-Mapping Profiles, provides the scoped
      matching result defined here. It does not prove that the action was
      authorized,
      executed, safe, or wise. It confers no trust, names no humans,
      and replaces no verifier: every artifact that carries a CAID
      still verifies inside its own trust boundary under its own
      specification, exactly as it did before carrying one.</t>
      <t>In particular:</t>
      <ul spacing="normal">
        <li>A CAID is not authorization. Possession of an identifier,
        or of the object it digests, authorizes nothing.</li>
        <li>A capability scope can name one or more CAIDs as exact content
        constraints. The capability's signature, issuer trust, holder proof,
        budget state, and local policy create that authorization context;
        the CAIDs themselves still grant nothing.</li>
        <li>A capability grant, a narrowing delegation, and each capability
        exercise are different material actions and can have separate CAIDs.
        Equality or EQUIVALENT_UNDER_PROFILE does not establish that an
        exercise falls within a grant. Scope containment, attenuation,
        remaining budget, and permission to act are evaluated by the
        capability protocol under relying-party-selected inputs.</li>
        <li>A CAID is not identity. It names content, not any human,
        agent, workload, or organization.</li>
        <li>A CAID is not proof of execution or of outcome. An
        artifact asserting execution proves that under its own
        specification, or not at all.</li>
        <li>Composition joins on the identifier and never ingests
        another verifier's evidence. When two artifacts about one
        action are composed, the join key is the CAID; each leg's
        evidence is verified by that leg's own verifier under that
        leg's own trust anchors, and no verifier imports another's
        conclusions into its own trust boundary.</li>
      </ul>
    </section>
    <section anchor="security">
      <name>Security Considerations</name>
      <t>CAID defines a data format and processing rules, not a protocol
      exchange. Issuers and presenters may be adversarial and control every
      octet of an action object, including extra members (Sections
      <xref target="overview" format="counter"/> and
      <xref target="effect-boundary" format="counter"/>). Definition sources
      and enum snapshots are trusted only through relying-party pins
      (Sections <xref target="enum-resolution" format="counter"/> and
      <xref target="security-definitions" format="counter"/>), and mapping
      profiles only through relying-party selection
      (<xref target="mapping-assumption"/>). Insertion, removal, or
      substitution of a CAID in transit is governed by the carrying
      artifact's own integrity mechanism (Sections
      <xref target="effect-boundary" format="counter"/> and
      <xref target="security-domain" format="counter"/>). The property that
      CAID provides is stated in <xref target="not"/>; everything else
      there is a non-goal.</t>
      <section anchor="security-digest">
        <name>Digest Strength and Suite Agility</name>
        <t>When the party that constructs the action object is trusted, the
        binding between an identifier and its content rests on the
        second-preimage resistance of the suite's digest. When that party
        may be adversarial, for example an agent that proposes an action for
        approval and later requests the operation, the binding rests on
        collision resistance: free-form fields such as the args of
        tool.call.1, and extra members (<xref target="action-object"/>),
        give such a party bytes to vary. SHA-256 provides about 128 bits of
        collision resistance and more against second preimages. If
        practical collision attacks on SHA-256 become known, the migration
        path is suite agility: a new suite is registered and issuers move to
        it, emitting new identifiers (<xref target="suites"/>). There is no
        in-place algorithm change within a suite, ever. A suite's digest is
        at least 256 bits, and the suite registry does not accept a digest
        formed by truncating the output of a hash function to fewer octets
        than that function specifies; a function whose specification
        defines a shorter output, such as SHA&#8209;384 or
        SHA&#8209;512/256, is not such a truncation
        (<xref target="iana-suites"/>).</t>
        <t>Suite agility moves only the CAID digest. Whatever the suite, the
        following are fixed to SHA-256: definition_sha256
        (<xref target="definition-digest"/>), values_sha256
        (<xref target="enum-resolution"/>), the profile and source digests
        of a mapping (Sections <xref target="mapping-object"
        format="counter"/> and <xref target="mapping-algorithm"
        format="counter"/>), the registry-file digest
        (<xref target="iana-action-types"/>), the digest field type, and the
        sha256-utf8, sha256-jcs, and sha256-hex-to-digest transforms. The
        "sha256:" prefix of each labels its algorithm. A new digest field
        type or transform is added through its registry (Sections
        <xref target="iana-field-types" format="counter"/> and
        <xref target="iana-transforms" format="counter"/>). Replacing the
        algorithm of definition_sha256, of values_sha256, or of the profile
        and source digests requires a revision of this document, which
        follows the guidance of <xref target="RFC7696"/>. Equal
        definition_sha256 values in resolution
        (<xref target="resolution"/>) and pinned profile digests also rest
        on collision resistance.</t>
        <t>A new suite does not migrate digests embedded in action objects,
        so an object's commitment to a field that it carries only as a
        digest remains bounded by SHA-256 until the type is versioned with a
        new field type.</t>
      </section>
      <section anchor="security-domain">
        <name>Domain Separation and Signatures</name>
        <t>The digest input carries no domain separation prefix,
        deliberately, so that existing formats can adopt a digest they may
        already compute over canonical bytes (<xref target="digest"/>). The
        compensating control is mandatory: verifiers <bcp14>MUST</bcp14> enforce the check
        that the in-object action_type equals the type carried in the CAID
        string. Skipping that check re-opens cross-context
        reinterpretation, in which bytes canonicalized for one context are
        presented under a type label from another. The check is phase 4 of
        <xref target="verification"/> and is not optional.</t>
        <t>Because extra members are permitted, one JSON object can be both
        a valid action object and another protocol's signed payload, and
        its bare digest is the same in both roles. Reusing an existing
        digest for correlation is permitted. A signature, MAC, or
        commitment that is to be read as a commitment to a CAID <bcp14>MUST</bcp14> cover
        the complete CAID string, whose caid:1:&lt;type&gt;:&lt;suite&gt;:
        prefix supplies the domain separation that the digest omits.</t>
      </section>
      <section anchor="security-truncation">
        <name>Truncation</name>
        <t>A CAID <bcp14>MUST NOT</bcp14> be abbreviated for comparison. A display <bcp14>MAY</bcp14>
        abbreviate an identifier, but an abbreviated form is not a CAID:
        parsers refuse it (<xref target="parsing"/>), and a relying party
        <bcp14>MUST NOT</bcp14> compare it with anything.</t>
      </section>
      <section anchor="security-replay">
        <name>Identical Actions and Replay</name>
        <t>Identical action objects have identical CAIDs. A CAID is not a
        nonce and gives no replay protection. A consume-once permit keyed
        on a CAID alone blocks a legitimate second identical operation,
        and a permit without consume-once semantics authorizes both. A
        type that must distinguish repeated identical operations <bcp14>SHOULD</bcp14>
        require an occurrence identifier. The occurrence_id member of
        tool.call.1 is optional, so two identical tool calls without it
        share a CAID; <xref target="tool-call-type"/> says when a deployment
        includes it.</t>
      </section>
      <section anchor="security-multiple">
        <name>Multiple Identifiers and Downgrade</name>
        <t>An artifact that carries several CAIDs for one action invites a
        verifier to check only the one that passes. <xref target="equality"/>
        forbids that: a verifier <bcp14>MUST</bcp14> verify every CAID whose suite it
        accepts and implements, and a relying party pins the suites it
        accepts, so an attacker cannot steer verification to a weaker
        suite. That rule protects only CAIDs that the carrying artifact
        integrity-protects as a set (<xref target="security-domain"/>).
        Against a suite that has weakened, the protection is the relying
        party's accepted set: an artifact that carries only a CAID under an
        accepted but weakened suite verifies, so a relying party removes a
        deprecated suite from its accepted set (<xref target="suites"/>).</t>
      </section>
      <section anchor="security-parsing">
        <name>Canonicalization and Parser Differentials</name>
        <t>Cross-language number serialization is the historical source of
        canonicalization divergence, which is why numbers are restricted
        to the value-based integer rule and money is carried as
        amount-string (<xref target="numbers"/>). The canonical form of an
        action object is the one its suite fixes (<xref target="suites"/>);
        no other serialization, however stable it appears, is a conforming
        digest input.</t>
        <t>Host JSON parsers differ in ways that change identified content.
        Some keep the first of two duplicate members and some the last.
        Some replace invalid UTF-8 or an unpaired surrogate escape with
        U+FFFD, so two different inputs yield one CAID. Some accept a byte
        order mark, NaN, or unbounded nesting. Each difference lets a
        native verifier and a CAID computation read different values from
        one text. <xref target="json-text"/> fixes one reading of JSON text,
        including the text that encloses an embedded action object, and
        <xref target="host-values"/> extends it to host values. For every
        text on which the parsers above disagree about structure or strings,
        <xref target="json-text"/> refuses the text, so no CAID exists to
        disagree with a native reading. It does not constrain a native
        verifier, and one number differential remains by design:
        <xref target="numbers"/> maps literals with different exact decimal
        values to one integer, such as 3999.99999999999999999,
        4000.0000000000001, and 4000, or 1e-400 and 0. A native verifier or
        policy engine that reads numbers as exact decimals can therefore
        evaluate a value other than the one a matching CAID commits to. A
        relying party that evaluates a number in an action object
        <bcp14>SHOULD</bcp14> evaluate the value of
        <xref target="numbers"/>; otherwise, before relying on a CAID match,
        it <bcp14>SHOULD</bcp14> refuse any number token that has a fraction
        or exponent part. A quantity that policy compares against a
        threshold <bcp14>SHOULD</bcp14> be typed amount-string.</t>
        <t>Member names raise a related problem. Some host decoders match
        member names case-insensitively, as Go's encoding/json does when it
        decodes into a struct, and some compare names by canonical
        equivalence, as Swift's String type does. The object
        {"amount":"1.00","Amount":"99999.00"} has a valid CAID that commits
        to both members, yet a case-insensitive decoder reads 99999.00 for
        amount, and a decoder that compares names by canonical equivalence
        treats "caf" followed by U+00E9 and "cafe" followed by U+0301 as one
        name in the same way.
        <xref target="effect-boundary"/> therefore requires an executor to
        act only on the values it validated.</t>
      </section>
      <section anchor="security-dos">
        <name>Limits and Denial of Service</name>
        <t>An implementation bounds the work one input can cause: the text
        limit is checked before decoding, the depth limit before any
        recursive traversal, and the canonical limit before hashing
        (<xref target="limits"/>). Mapping profiles are bounded in rules
        and string lengths. Registries, definitions, and enum snapshots are
        exempt from the text limit, so an implementation bounds the size of
        the configuration it loads by its own policy. Every limit is a
        refusal with a reason, never an exception or a crash. The lengths
        of identifiers, action types, and code_system values are checked
        before any pattern runs, and a host value is bounded by its value
        count, so no input reaches the internal limits of a regular
        expression engine or walks an exponential expansion of shared
        references.</t>
        <t>The limits still admit large inputs. Decoding and canonicalizing
        an action object near the 33,554,432-octet text limit can take
        seconds and more than a gigabyte of memory in some
        implementations. A protocol that accepts action objects from
        parties it does not trust <bcp14>SHOULD</bcp14> bound its own
        messages well below these limits (<xref target="limits"/>). The
        statement of <xref target="overview"/> that every input yields a
        result assumes that memory; an implementation that cannot obtain it
        fails as its platform fails when memory runs out, which this
        document does not specify.</t>
      </section>
      <section anchor="security-redos">
        <name>Code Format Matching</name>
        <t>A pattern language chosen per definition would let a definition
        author, or anyone who can supply a definition over the network,
        choose a pattern with catastrophic backtracking. A pattern such as
        (a|a){1,99} takes time exponential in the length of the input in
        common backtracking engines. CAID has no such language. A code
        field names a registered format, and every format is a fixed
        grammar that matches strings of bounded length and compiles to a
        regular expression with no nested quantifiers, no quantified
        alternatives that can begin with the same character, and no
        optional repetition whose first characters overlap what can follow
        it. A bounded length alone is not enough: (a|a){1,99} matches only
        strings of at most 99 characters. Matching is therefore linear in
        the length of the input in every engine. An
        implementation <bcp14>MAY</bcp14> match a format with a hand-written recognizer
        instead of a regular expression.</t>
      </section>
      <section anchor="security-unicode">
        <name>Unicode Normalization and Confusables</name>
        <t>CAID performs no Unicode normalization. Visually identical
        strings in different normalization forms, or homoglyphs such as
        U+0430 in place of "a", are different content with different
        CAIDs. That fails safe for equality but not for human review. An
        interface that displays an action object for approval <bcp14>SHOULD</bcp14> apply
        confusable detection to identifier-like fields such as hosts,
        accounts, email addresses, and tool names. It <bcp14>SHOULD</bcp14>
        also display every member, escape control and bidirectional
        formatting characters in member names, and flag any member that the
        type does not declare whose name equals a declared field name after
        case folding, after NFKC normalization <xref target="UNICODE"/>, or
        under the confusable skeleton of <xref target="UTS39"/>, because an
        executor that matched names that way would read the wrong member
        (<xref target="security-parsing"/>). A relying party
        <bcp14>MAY</bcp14> refuse such an object as a matter of local
        policy. A type whose fields
        name such identifiers <bcp14>SHOULD</bcp14> state their normalization in
        digest_notes, and issuers apply it before computing. The action
        type and the suite are ASCII by grammar.</t>
        <t>A reason carries a field name or a source path verbatim, and a
        field name can hold control and bidirectional formatting
        characters. An interface or log that displays reasons escapes
        them. The field names of the reference registry are printable
        ASCII.</t>
      </section>
      <section anchor="security-definitions">
        <name>Definition Stability and Distribution</name>
        <t>A versioned action-type definition is immutable once published,
        apart from the monotone enum advance of <xref target="names"/>.
        definition_sha256 identifies validation semantics exactly, and a
        relying party that needs exact reproducibility pins it. A local and
        a registered definition that share a name but differ in validation
        semantics are not the same type, and resolution refuses the pair
        when both are configured, so a second definition slipped into a
        configured source causes invalid_definition instead of silently
        changing validation. A definition source obtained over the network
        <bcp14>MUST</bcp14> be checked against the pinned SHA-256 digest of the registry
        file (<xref target="iana-action-types"/>) or against pinned
        definition_sha256 values before use. The registry-file digest covers
        the file's octets, so an implementation <bcp14>SHOULD</bcp14> check
        it before it parses the file; a check against definition_sha256
        values necessarily follows decoding under
        <xref target="json-text"/>, within a size that the implementation
        bounds by its own policy (<xref target="security-dos"/>).
        definition_sha256 does not cover notes or digest_notes, which carry
        normalization guidance for issuers, so a party that relies on that
        guidance checks the source against the registry-file digest.</t>
        <t>A code-set name or URL does not identify immutable validation
        semantics. Issuers and verifiers <bcp14>MUST</bcp14> use the exact locally
        available snapshot and verified digest required by
        <xref target="enum-resolution"/>. Resolving a mutable network
        resource at computation or verification time can make the same
        object alternate between valid and invalid and is prohibited.
        Missing, unresolved, or digest-mismatched snapshots fail
        closed.</t>
      </section>
      <section anchor="security-mapping">
        <name>Mapping</name>
        <t>Direct CAID verification does not infer semantic equality. The
        Action-Mapping Profile makes only a narrower statement about
        material projections under exact pinned profiles. A malicious or
        incomplete profile can omit a concept that the relying party should
        have considered material. Profile selection is therefore a
        relying-party policy decision. The algorithm of
        <xref target="mapping-algorithm"/> yields INDETERMINATE when a
        profile is unpinned or its source format does not match, when it
        declares source semantic loss, or when a required target field has
        no rule. It cannot detect a material source concept that the profile
        neither maps nor declares (<xref target="mapping-assumption"/>);
        only profile review guards against that.</t>
        <t>A valid native signature does not make unsigned members beside
        the signed payload trustworthy. A native adapter <bcp14>MUST</bcp14> establish
        that every mapped field is covered by the native integrity
        mechanism. The source descriptor is verifier-derived, not
        presenter-asserted (<xref target="mapping-boundary"/>).</t>
      </section>
      <section anchor="security-capability">
        <name>A CAID Is Not a Capability</name>
        <t>Possession of an identifier proves nothing and grants nothing.
        Protocols <bcp14>MUST NOT</bcp14> treat knowledge of a CAID as evidence of
        anything beyond knowledge of the object's content. A CAID also
        hides nothing that can be guessed; <xref target="privacy"/>
        explains why.</t>
      </section>
    </section>
    <section anchor="privacy">
      <name>Privacy Considerations</name>
      <t>A CAID has the same confidentiality as its action object. It is
      an unsalted, deterministic hash of the whole object, and it carries
      the action type in cleartext. When every member of an object is
      guessable, as with a small amount, a
      currency, a known payee, and a sequential instruction identifier,
      anyone who holds the identifier can recover the object by testing
      candidates offline, at the cost of one SHA-256 computation each. The
      tool.call.1 example of <xref target="tool-call-type"/> shows this:
      enumerating amount_usd upward from 1 recovers the value 4000 after
      4000 candidates. A CAID therefore <bcp14>SHOULD</bcp14> be logged, transmitted, and
      placed in URLs only where the action object itself could be. The
      digest that computation returns and the source digest of a mapping
      result carry the same exposure.</t>
      <t>A CAID is meant to be recomputed by a party that already holds the
      action object, such as a verifier (<xref target="verification"/>) or
      an executor (<xref target="effect-boundary"/>), and receipts and
      other evidence carry it for such parties. It is not designed as a
      correlation identifier to propagate to parties that do not hold the
      object: to them it discloses whatever of the object can be
      guessed.</t>
      <t>The digest field type keeps raw values out of an action object
      but does not by itself provide confidentiality or unlinkability. A
      plain SHA-256 digest of an account number, email address, or
      patient identifier is pseudonymous, not anonymous: an observer can
      test likely values by dictionary attack. The digest-typed values in
      <xref target="appendix-examples"/> are digests of short example
      strings and can be recovered this way.</t>
      <t>Type authors handling personal data <bcp14>SHOULD</bcp14> prefer high-entropy
      opaque references or a deployment-specific privacy-preserving
      commitment scheme, document its normalization and correlation scope,
      and avoid placing unnecessary personal data in the action object. A
      type whose required fields can all be low-entropy <bcp14>SHOULD</bcp14> require a
      member that carries at least 128 bits of entropy from the system of
      record, such as a random instruction or occurrence identifier. A
      deployment-specific commitment scheme can require an explicit
      mapping profile for cross-domain joins.</t>
      <t>The initial CAID Action Types entries rely on identifiers from the
      system of record, such as payment_instruction_id,
      authorization_number, and order_id, that the registry cannot require
      to be high-entropy. Where such an identifier is sequential and the
      other members can be guessed, anyone who holds a CAID of that type can
      recover its action object, so the CAID needs the protection its action
      object needs, including personal-data protection when the object
      carries personal data. The
      notes of a registered type fix what each of its digest
      fields commits to, and that is part of the entry's immutable meaning
      (<xref target="iana-action-types"/>), so a deployment does not carry
      a keyed commitment, such as HMAC-SHA-256 <xref target="RFC6234"/>
      under a deployment-scoped key, in a digest field whose notes, like
      those of patient_ref, describe a plain digest. A deployment that
      needs a keyed commitment uses a type whose notes specify it: a local
      type (<xref target="local"/>) or a new version registered for that
      purpose. Nothing in an action object says which scheme a digest
      field used, so comparison across deployments then needs a mapping
      profile (<xref target="mapping"/>).</t>
      <t>Action objects, CAIDs, verification details, and their
      correlations should be assumed to travel and to appear in logs.</t>
    </section>
    <section anchor="iana">
      <name>IANA Considerations</name>
      <t>IANA is requested to create a registry group named "Canonical
      Action Identifier (CAID)" containing the seven registries of
      Sections <xref target="iana-suites" format="counter"/> through
      <xref target="iana-loss-policies" format="counter"/>, and to register
      the URI scheme of <xref target="iana-uri"/>. The registration
      policies are those of <xref target="RFC8126"/>. Until IANA creates
      the registries, the author's reference registry records their
      contents: the CAID Suites and CAID Action Types entries in files
      published under a public-domain dedication beside
      <xref target="CAID-REGISTRY"/>, and the other five registries in the
      specification sources of the same repository. Its Action Types file
      records a superset of the initial CAID Action Types contents: it
      also carries the entries that IANA is not asked to register, which
      <xref target="appendix-action-types-reference-only"/> lists. The
      reference for every initial entry of every registry below is this
      document; each initial CAID Action Types entry also references <xref target="CAID-REGISTRY"/>, which
      holds its definition, and <xref target="tool-call-type"/> reproduces
      the definition of tool.call.1. The change controller of every
      initial entry is the IETF.</t>
      <t>Only an entry's change controller may request a change to that
      entry, such as deprecation with superseded_by or a monotone enum
      advance, and the designated expert reviews the request under the
      policy that applies to a new registration. For entries registered by
      IETF-stream documents, the change controller is the IETF, acting
      through the IESG. The IESG may also act for any other change
      controller that cannot be reached or does not respond.</t>
      <section anchor="iana-suites">
        <name>CAID Suites</name>
        <t>Registration policy: Specification Required. Each entry
        records: the suite name, which matches the suite rule of
        <xref target="appendix-abnf"/>; the canonicalization scheme and its
        reference; the digest algorithm and its reference; the digest
        length in octets, at least 32; the status, active or deprecated;
        the change controller; and a reference. The designated expert
        refuses a digest formed by truncating the output of a hash function
        to fewer octets than that function specifies, and a name that
        differs from a registered name only by hyphens; a function whose
        specification defines a shorter output, such as SHA&#8209;384 or
        SHA&#8209;512/256, is not such a truncation. A registered name is
        never
        reassigned, an entry is never removed, and a suite is never
        redefined. A suite is deprecated once practical collision attacks on
        its digest are known or anticipated: its change controller requests
        the deprecation, or the IESG does for a controller that cannot be
        reached or does not respond (<xref target="iana"/>), and a new
        suite is registered.
        <xref target="suites"/> states what deprecation means for issuers
        and relying parties. The initial contents are:</t>
<table anchor="tab-suites">
  <name>CAID Suites: Initial Contents</name>
  <thead><tr><th>Suite</th><th>Canonicalization</th><th>Digest</th><th>Octets</th><th>Status</th></tr></thead>
  <tbody>
    <tr><td>jcs-sha256</td><td>RFC 8785</td><td>SHA-256, RFC 6234</td><td>32</td><td>active</td></tr>
    <tr><td>cbor-sha256</td><td>RFC 8949, Section 4.2.1</td><td>SHA-256, RFC 6234</td><td>32</td><td>active</td></tr>
  </tbody>
</table>
      </section>
      <section anchor="iana-action-types">
        <name>CAID Action Types</name>
        <t>Registration policy: Specification Required. Each entry records:
        the action type, which matches the action-type rule of
        <xref target="appendix-abnf"/> and has at least two name segments;
        the definition, in the schema of <xref target="schema"/>; its
        definition_sha256; the status; supersedes and superseded_by where
        they apply; the change controller; and a reference. The expert does
        not register a name whose first segment is organization-specific
        (<xref target="local"/>) unless that organization is the change
        controller.</t>
        <t>The content of an entry that affects validation or material
        meaning, including the normalization guidance in notes and
        digest_notes, is immutable, with two exceptions: the status may move
        from active to deprecated, with superseded_by naming the successor;
        and the expert may approve a monotone enum advance
        (<xref target="names"/>) after checking that every previously
        accepted value remains accepted. An advance request cites the
        edition and values_sha256 of the new value set. An advance updates
        definition_sha256, and the entry keeps every earlier
        definition_sha256. A new version of a registered type name is
        registered by the change controller of its earlier versions, or with
        that controller's written agreement, and the expert refuses a
        registration, or a supersedes or superseded_by value, that would
        link type versions held by different change controllers without that
        agreement.</t>
        <t>The expert applies the material-fields test: every required field
        is material; field names are printable ASCII; amounts are
        amount-string; identifiers that are personal or secret-adjacent are
        digest fields; in a registration made after this document, a type
        whose required fields can all be low-entropy requires a member that
        carries at least 128 bits of entropy, or its digest_notes or its
        specification state why not (<xref target="privacy"/>); every enum
        is closed or pinned to an integrity-checked snapshot; and values
        from large, changing, or licensed code systems are code fields, with
        no value set and no licensed content. The initial entries of
        <xref target="appendix-action-types-initial"/> are registered by
        this document: <xref target="privacy"/> states why their identifiers
        are not required to carry 128 bits of entropy, and
        <xref target="tool-call-type"/> why occurrence_id is optional in
        tool.call.1. The 9 deprecated initial entries are registered to
        record the history of the successors that superseded_by names, not
        for new identifiers, and they do not meet the test: each has a
        required enum field whose external values_ref has no pinned
        snapshot, and four of them hold as enums values that their
        successors carry as code fields. Such an enum field refuses whenever
        it is present, so, as registered, none of the 9 produces or verifies
        a CAID (<xref target="enum-resolution"/>). A registrant whose type
        pins an
        external enum supplies the snapshot file, in the shape of
        <xref target="enum-resolution"/> together with the source it was
        derived from and what is known of that source's terms, and the
        SHA-256 digest of the file; the expert confirms that the file is
        publicly available under the terms it states before approving the
        entry.</t>
        <t>The initial contents are the 54 entries of
        <xref target="appendix-action-types-initial"/>, 45 active and 9
        deprecated. The definition of each entry is the entry with that
        name in the file action-types.json of
        <xref target="CAID-REGISTRY"/>, registry version 5 of the reference
        registry, whose SHA-256 digest over the octets of that file, in
        hexadecimal, is
        1e30ddd312c888f6a27055dac0ed453398e20b64cfdcb7c5019fcf0e1ac2551a.
        <xref target="tool-call-type"/> reproduces the tool.call.1 entry
        member for member. The reference registry also carries types
        defined by other specifications, and one whose name misdescribes
        it; they are listed in
        <xref target="appendix-action-types-reference-only"/> and are not
        initial entries. Each of the seven types defined by other
        specifications may be registered under Specification Required with
        its own specification and change controller. The eighth,
        dns.zone.transfer.1, is not to be registered, because its name
        misdescribes the type; the registrar transfer it defines can be
        registered under a name that describes it.</t>
        <t>IANA is asked to store each entry's definition, in the schema of
        <xref target="schema"/>, as a file linked from the entry, and to
        record with each entry every definition_sha256 it has held, in
        order, with the date of each change, starting with the value that
        <xref target="appendix-action-types-initial"/> gives. A monotone enum
        advance adds a value to that list and never removes one. IANA is
        also asked to store, and to link from each entry that pins it, each
        enum snapshot file that an initial entry pins and that is derived
        from an IANA registry: the DNS Resource Record TYPEs list, the JOSE
        algorithm and elliptic curve lists, and the ISO 3166-1 alpha-2 list
        as the Language Subtag Registry carries it. The ISO 4217 snapshot,
        which every currency field of the initial entries pins, is archived
        with those files beside action-types.json at the commit that
        <xref target="CAID-REGISTRY"/> cites. Each snapshot file records the
        source it was derived from, and its entry in the enum_snapshot_files
        member of action-types.json records what is known of its terms.</t>
      </section>
      <section anchor="iana-field-types">
        <name>CAID Field Types</name>
        <t>Registration policy: IETF Review. A field type defines new
        members, refusal behavior, and processing, so it changes what every
        implementation validates. An entry records the name, which matches
        the format-name rule of <xref target="appendix-abnf"/>; the JSON
        kind of its values; the members it defines; its refusal reasons;
        and a reference. A registered field
        type is never removed, renamed, or redefined. The initial contents
        are:</t>
<table anchor="tab-field-types">
  <name>CAID Field Types: Initial Contents</name>
  <thead><tr><th>Field type</th><th>JSON kind</th><th>Members</th><th>Refusals</th></tr></thead>
  <tbody>
    <tr><td>string</td><td>string</td><td>none</td><td>mistyped_field</td></tr>
    <tr><td>amount-string</td><td>string</td><td>none</td><td>invalid_amount, mistyped_field</td></tr>
    <tr><td>digest</td><td>string</td><td>none</td><td>mistyped_field</td></tr>
    <tr><td>enum</td><td>string</td><td>values, values_ref, values_snapshot, values_sha256</td><td>mistyped_field</td></tr>
    <tr><td>code</td><td>string</td><td>code_system, format</td><td>invalid_code, mistyped_field</td></tr>
    <tr><td>timestamp</td><td>string</td><td>none</td><td>mistyped_field</td></tr>
    <tr><td>integer</td><td>number</td><td>none</td><td>mistyped_field</td></tr>
    <tr><td>boolean</td><td>boolean</td><td>none</td><td>mistyped_field</td></tr>
    <tr><td>object</td><td>object</td><td>none</td><td>mistyped_field</td></tr>
    <tr><td>array</td><td>array</td><td>none</td><td>mistyped_field</td></tr>
  </tbody>
</table>
      </section>
      <section anchor="iana-code-formats">
        <name>CAID Code Formats</name>
        <t>Registration policy: Specification Required. A code format is a
        grammar applied by the unchanged rule of
        <xref target="code-fields"/>; it adds no member, reason, or
        processing step. An implementation that does not know a format
        refuses only the fields that name it, as mistyped_field
        (<xref target="conformance"/>), which fails closed, and the checks
        below bound what a format can admit. An entry records: the format
        name, which matches the format-name rule; its grammar in ABNF
        <xref target="RFC5234"/> <xref target="RFC7405"/> over printable
        ASCII, which is complete, defining every rule it uses other than the
        core rules of <xref target="RFC5234"/>; the maximum length of a
        matching string; the reference that defines its syntax; the change
        controller; and a reference. The designated expert checks that the
        format fixes syntax only, never a value set; that it matches only
        strings of bounded length; that it has the linear-matching property
        of <xref target="code-fields"/> (see also
        <xref target="security-redos"/>); that each distinct lexical form of
        a code is a distinct format; and that the registration carries no
        licensed content. A registered code format is never removed,
        renamed, or redefined; a changed grammar is registered as a new
        format name. The grammar of each initial entry is the rule of part
        A.4 of <xref target="appendix-abnf"/> with the same name, together
        with the rules of part A.4 that it references: UALPHA and UALNUM,
        and, for hcpcs, the cpt and hcpcs-level-ii rules. The initial
        contents are:</t>
<table anchor="tab-code-formats">
  <name>CAID Code Formats: Initial Contents</name>
  <thead><tr><th>Code format</th><th>Maximum length</th><th>Syntax reference</th></tr></thead>
  <tbody>
    <tr><td>icd-10-cm</td><td>8</td><td>ICD-10-CM Official Guidelines for Coding and Reporting, Section I.A.2</td></tr>
    <tr><td>ndc-11</td><td>11</td><td>FDA National Drug Code format, 11-digit form</td></tr>
    <tr><td>ndc-10-hyphenated</td><td>12</td><td>FDA National Drug Code format, 10-digit forms</td></tr>
    <tr><td>cpt</td><td>5</td><td>AMA CPT code set</td></tr>
    <tr><td>hcpcs-level-ii</td><td>5</td><td>CMS HCPCS Level II</td></tr>
    <tr><td>hcpcs</td><td>5</td><td>CMS HCPCS Level II; AMA CPT (HCPCS Level I)</td></tr>
    <tr><td>iso-3166-2</td><td>6</td><td>ISO 3166-2</td></tr>
    <tr><td>iso20022-external-code</td><td>4</td><td>ISO 20022 External Code Sets</td></tr>
    <tr><td>nacha-sec</td><td>3</td><td>Nacha Operating Rules, Standard Entry Class codes</td></tr>
  </tbody>
</table>
      </section>
      <section anchor="iana-reasons">
        <name>CAID Reason Codes</name>
        <t>Registration policy: Standards Action. A new reason changes
        what every conforming implementation reports and where the reason
        sorts (<xref target="reason-order"/>), so it is registered only by
        a Standards Track RFC that also updates the reason rule of
        <xref target="appendix-abnf"/> and names the phase or stage that
        reports it. Each entry records: the reason code, in lowercase
        letters and underscores; the kind of its parameter (none,
        field-name, source-path, or compute-reason); the operations and
        phases, or the mapping stage, that report it; and a reference. The
        reason rule of <xref target="appendix-abnf"/> accepts exactly the
        reasons registered by this document. The prefixes left: and right:
        of a comparison (<xref target="mapping-algorithm"/>) are not
        registered reasons: each marks which mapping a registered mapping reason came
        from, and a mapping reason gains both prefixed forms when it is
        registered. The initial contents are the two tables of
        <xref target="appendix-reasons"/>.</t>
      </section>
      <section anchor="iana-transforms">
        <name>CAID Mapping Transforms</name>
        <t>Registration policy: IETF Review. A mapper written from an
        earlier specification refuses an unknown transform, so a
        registration changes what mappers accept. Each entry records:
        the transform name, which matches the format-name rule of
        <xref target="appendix-abnf"/>; the source values it accepts; its
        output; the
        reason for a value it does not accept; and a reference. The initial
        contents are:</t>
<table anchor="tab-transforms">
  <name>CAID Mapping Transforms: Initial Contents</name>
  <thead><tr><th>Transform</th><th>Accepts</th><th>Output</th><th>Refusal</th></tr></thead>
  <tbody>
    <tr><td>copy</td><td>any value of the data model</td><td>the value</td><td>source_value_not_canonicalizable</td></tr>
    <tr><td>sha256-utf8</td><td>a string</td><td>"sha256:" and the SHA-256 of its UTF-8 octets</td><td>source_value_type_mismatch</td></tr>
    <tr><td>sha256-jcs</td><td>any value of the data model</td><td>"sha256:" and the SHA-256 of its RFC 8785 encoding</td><td>source_value_not_canonicalizable</td></tr>
    <tr><td>sha256-hex-to-digest</td><td>a string matching hex-sha256</td><td>"sha256:" and the string</td><td>source_value_type_mismatch</td></tr>
  </tbody>
</table>
      </section>
      <section anchor="iana-loss-policies">
        <name>CAID Mapping Loss Policies</name>
        <t>Registration policy: IETF Review. A mapper written from an
        earlier specification refuses an unknown loss policy, so a
        registration changes what mappers accept. Each entry records:
        the policy name, which matches the format-name rule of
        <xref target="appendix-abnf"/>; the constraint on
        omitted_source_fields; its
        effect on the mapping result; and a reference. The initial contents
        are:</t>
<table anchor="tab-loss-policies">
  <name>CAID Mapping Loss Policies: Initial Contents</name>
  <thead><tr><th>Policy</th><th>Omissions</th><th>Effect</th></tr></thead>
  <tbody>
    <tr><td>no-material-field-loss</td><td>absent or empty</td><td>none</td></tr>
    <tr><td>declared-source-semantic-loss</td><td>non-empty</td><td>INDETERMINATE, reason declared_source_semantic_loss</td></tr>
  </tbody>
</table>
      </section>
      <section anchor="iana-uri">
        <name>The "caid" URI Scheme</name>
        <t>A CAID is a syntactically valid URI <xref target="RFC3986"/>: the
        scheme "caid" followed by ":" and a rootless path made of
        unreserved characters and ":". IANA is requested to
        register the scheme in the "Uniform Resource Identifier (URI)
        Schemes" registry with the following template
        <xref target="RFC7595"/>:</t>
        <dl newline="false" spacing="normal">
          <dt>Scheme name:</dt>
          <dd>caid</dd>
          <dt>Status:</dt>
          <dd>Permanent</dd>
          <dt>Applications/protocols that use this scheme name:</dt>
          <dd>Authorization receipts, permits, execution attestations,
          audit records, and other artifacts that identify an action by
          its Canonical Action Identifier.</dd>
          <dt>Contact:</dt>
          <dd>Iman Schrock &lt;team@emiliaprotocol.ai&gt;</dd>
          <dt>Change controller:</dt>
          <dd>IETF &lt;iesg@ietf.org&gt;</dd>
          <dt>References:</dt>
          <dd>This document.</dd>
        </dl>
        <t>Syntax: the caid rule of <xref target="appendix-abnf"/>.
        Semantics: a caid URI identifies typed action content by digest.
        It is not a locator: no operation is defined on it, and an
        application <bcp14>MUST NOT</bcp14> dereference it. Encoding: the
        identifier is ASCII and contains no percent-encoded octets; a
        percent-encoded form is not a CAID, and a carrying protocol removes
        any transport encoding before parsing. Interoperability: CAIDs are
        compared as exact strings (<xref target="equality"/>).
        <xref target="RFC3986"/> treats scheme names as case-insensitive
        and makes lowercase the normal form; every CAID is already in that
        form, so normalization under
        <xref target="RFC3986" section="6" sectionFormat="of"/> leaves a
        CAID unchanged. An application <bcp14>MUST NOT</bcp14> normalize a
        string before parsing it as a CAID, because normalization can turn a
        string that a parser refuses, such as one whose scheme is written
        "CAID", into a CAID (<xref target="parsing"/>). Security: <xref target="security"/> and
        <xref target="privacy"/>.</t>
        <t>Utility (<xref target="RFC7595" section="3.1" sectionFormat="of"/>):
        a CAID names an action by the digest of a canonicalization that its
        suite fixes, applied to an action object whose type definition
        decides which members are required and how each is typed, and the
        identifier carries the action type and the suite, both of which take
        part in comparison (<xref target="equality"/>). An ni URI
        <xref target="RFC6920"/> names an object by the digest of its octets,
        unless a specification defines another input, under an algorithm
        from the Named Information Hash Algorithm Registry. It names no
        canonicalization, and two ni names that share the algorithm and the
        digest value refer to the same object whatever else they carry, so
        an action type or a suite in their authority or query parameters
        would take no part in comparison. A URN namespace
        <xref target="RFC8141"/> could carry the same fields in its
        namespace-specific string, but URN-equivalence lowercases "urn" and
        the namespace identifier, ignores the r-, q-, and f-components, and
        lets a namespace add equivalences but never remove one, so it would
        equate spellings that a parser under <xref target="parsing"/> refuses
        and that <xref target="equality"/> compares as different
        strings.</t>
      </section>
      <section anchor="iana-media-types">
        <name>Media Types</name>
        <t>This document registers no media type <xref target="RFC6838"/>.
        A media type earns registration when a recipient must recognize a
        message by it, and no step of this document sends one of its
        objects that way:</t>
        <ul spacing="normal">
          <li>A type definition is configuration. A relying party pins it
          by definition_sha256 (<xref target="definition-digest"/>) or by
          the SHA-256 digest of the registry file
          (<xref target="iana-action-types"/>), and a definition obtained
          over the network is checked against that pin before use, never
          trusted for its label.</li>
          <li>A mapping profile is pinned by its digest and comes from
          relying-party configuration; a label inside a presented artifact
          is never accepted as the profile or its source format
          (<xref target="mapping-boundary"/>).</li>
          <li>An enum snapshot is local by rule: computation and
          verification never fetch one (<xref target="enum-resolution"/>).</li>
          <li>An action object travels inside the artifact that carries it,
          under that artifact's own format.</li>
        </ul>
        <t>A specification that defines a transfer of any of these objects
        can register a media type for it.</t>
      </section>
    </section>
    <section anchor="impl-status">
      <name>Implementation Status</name>
      <t>This section records the known implementations of this
      specification at the time of posting, as described in
      <xref target="RFC7942"/>. Listing an implementation here does not
      imply endorsement by the IETF. The RFC Editor is asked to remove
      this section before publication.</t>
      <t>EMILIA Protocol, Inc., the author's organization, maintains three
      implementations, in JavaScript, Python, and Go. Each implements
      decoding, parsing, computation, verification, the definition digest,
      and mapping for the jcs-sha256 suite, and refuses cbor-sha256 as
      unknown_suite. The JavaScript implementation uses only the platform's
      cryptographic library, and the Python and Go implementations use only
      their standard libraries. All three run one shared conformance corpus
      of core and mapping vectors, plus candidate cross-format mapping
      vectors that encode the author's reading of other formats' published
      specifications and have not been validated by those formats' authors;
      they skip the corpus vectors that apply only to an implementation of
      cbor-sha256. They are licensed under Apache-2.0 and published at
      &lt;https://github.com/emiliaprotocol/emilia-protocol/tree/main/caid&gt;.
      The next major release (6.0.0) of the author's verification package
      will vendor a byte-for-byte copy of caid.mjs, the module of the
      JavaScript implementation that carries every operation except
      mapping; the published 5.0.0 vendors a copy of an earlier revision.
      Contact:
      team@emiliaprotocol.ai.</t>
      <t>Version: all three implement revision -04 of this document.
      Coverage: every operation of <xref target="overview"/>, for JSON text
      and host values, under the jcs-sha256 suite; none implements the
      cbor-sha256 suite. Maturity: they are the reference implementations
      of the author's conformance tooling, reviewed only within the
      author's organization. This section was last updated on 28 September
      2026.</t>
      <t>All three implementations come from the author's organization,
      and none of them is independent. No independent implementation is
      known to the author. A party that runs these implementations or
      their conformance corpus reproduces the author's results; such
      external re-runs are reproductions, not independent
      implementations.</t>
    </section>
    <section anchor="changes-03" removeInRFC="true">
      <name>Changes since -03</name>
      <t>This revision makes the processing model complete and checkable,
      and it is a substantive revision. The suites, the digest, and the
      canonical form of every object that both -03 and -04 accept do not
      change. The identifier syntax changes only by refusing the forms
      listed in <xref target="changes-03-refused"/>. The lists below give
      every normative change. Each item in the first four lists changes
      what an implementation of the operations of
      <xref target="overview"/> accepts, refuses, or reports, and is pinned
      by conformance vectors. The fifth list gives new requirements on
      parties whose behavior those operations cannot observe, and the last
      list gives changes to the text alone.</t>
      <section anchor="changes-03-refused">
        <name>Newly Refused Inputs</name>
        <t>This revision refuses each of the following inputs, which -03
        accepted or did not address. The first four items, and the
        timestamp, amount, length, and value count items, refuse action
        objects whose CAIDs were valid under -03.</t>
        <ul spacing="normal">
          <li anchor="chg-refused-depth">Action objects nested deeper than
          64 levels: malformed_json as JSON text, unsupported_value as host
          values (Sections <xref target="data-model" format="counter"/> and
          <xref target="json-text" format="counter"/>). A host definition
          whose validation projection is nested that deep, or a host mapping
          profile or mapping source nested that deep, is refused by the step
          that reads it: invalid_definition, invalid_mapping_profile, or
          source_not_canonicalizable (<xref target="limits"/>).</li>
          <li anchor="chg-refused-canonical-size">Action objects whose
          canonical encoding exceeds 16,777,216 octets: unsupported_value
          (<xref target="data-model"/>).</li>
          <li anchor="chg-refused-noncharacter">Strings and member names
          that contain a Unicode noncharacter, which I-JSON excludes:
          malformed_json as JSON text, unsupported_value as host values
          (Sections <xref target="data-model" format="counter"/> and
          <xref target="json-text" format="counter"/>).</li>
          <li anchor="chg-refused-text-size">JSON text longer than
          33,554,432 octets, even when the object it encodes is within the
          canonical limit: malformed_json (<xref target="json-text"/>).</li>
          <li anchor="chg-refused-json-text">JSON text that begins with a
          byte order mark, is not valid UTF-8, is not exactly one JSON text,
          or contains NaN, Infinity, or a character U+0000 through U+001F
          unescaped in a string: malformed_json. U+007F and U+0080 through
          U+009F may appear unescaped. <xref target="RFC8259"/> lets a parser ignore a
          byte order mark; this profile refuses it.</li>
          <li anchor="chg-refused-duplicate-names">JSON text with duplicate
          member names, including names that differ only in escaping:
          malformed_json. -03 required a raw parser to reject duplicates in
          its Security Considerations; the rule is now part of the decoder
          and has a reason.</li>
          <li anchor="chg-refused-host-values">Host values outside the data
          model, which an implementation now refuses instead of
          serializing as another value. A top-level value that is not an
          object is invalid_action_type, and a host type definition is read
          only as far as its validation projection
          (<xref target="host-values"/>).</li>
          <li anchor="chg-refused-definitions">Action objects under a
          nonconforming definition, or under two configured definitions of
          one type with different validation projections:
          invalid_definition (Sections <xref target="conformance"
          format="counter"/> and <xref target="resolution"
          format="counter"/>). -03 did not say what a nonconforming
          definition does, so an implementation could issue a CAID that
          bound none of the intended fields.</li>
          <li anchor="chg-refused-field-names">Definitions with a field name
          that is empty, contains ":", is action_type, or repeats, and field
          entries of a registered field type that carry members the type
          does not define: invalid_definition
          (<xref target="conformance"/>).</li>
          <li anchor="chg-refused-timestamps">Timestamps with a lowercase
          "t" or "z", or with a second of 60, which <xref target="RFC3339"/>
          permits and the -03 description "an RFC 3339 timestamp in UTC"
          therefore admitted: mistyped_field
          (<xref target="fieldtypes"/>).</li>
          <li anchor="chg-refused-caid-case">Identifiers that begin with
          "CAID:" or "Caid:", which the -03 ABNF admitted because an
          <xref target="RFC5234"/> string literal is case-insensitive:
          malformed_caid (<xref target="parsing"/>).</li>
          <li anchor="chg-refused-amount">Amount strings whose integer part
          has a leading zero, such as "01.5", which the -03 prose admitted:
          invalid_amount (<xref target="fieldtypes"/>).</li>
          <li anchor="chg-refused-suite">Identifiers whose suite begins with
          a digit, which the -03 suite ABNF already excluded, and
          identifiers whose digest's final character sets an unused bit,
          which -03 did not address: malformed_caid
          (<xref target="parsing"/>). The reference implementations
          accepted both before this revision.</li>
          <li anchor="chg-refused-mapping">Mapping profiles with two rules
          for one source path, which -03 already forbade, a member whose
          value is null, a target_field that is not a string, a string
          outside its limit when measured in UTF-8 octets, or a
          target_action_type longer than 512 octets: invalid_mapping_profile
          (<xref target="mapping-object"/>).</li>
          <li anchor="chg-refused-lengths">Action types longer than 512
          octets, identifiers longer than 1,024 octets, and code_system
          values longer than 2,048 octets, which -03 did not bound:
          invalid_action_type in an action object, malformed_caid in an
          identifier, and invalid_definition in a definition
          (<xref target="limits"/>).</li>
          <li anchor="chg-refused-value-count">Host action objects that hold
          more than 33,554,432 values, each counted once for every path that
          reaches it, where an object or array nested deeper than 64, or a
          reference back to an enclosing object or array, counts as one
          value: unsupported_value and no unsupported_number, while phases 3
          and 4 still run (<xref target="host-values"/>). A host definition whose validation
          projection, or a host mapping profile or mapping source, holds that
          many is refused by the step that reads it: invalid_definition,
          invalid_mapping_profile, or source_not_canonicalizable
          (<xref target="limits"/>).</li>
        </ul>
      </section>
      <section anchor="changes-03-features">
        <name>New Rules and Features</name>
        <ul spacing="normal">
          <li anchor="chg-json-text">JSON text input
          (<xref target="json-text"/>). Action objects and mapping sources
          received as text are decoded under an I-JSON profile, and every
          decoding failure is the single reason malformed_json. Definitions,
          registries, snapshots, and profiles get the same rules without the
          size limit.</li>
          <li anchor="chg-data-model">The data model
          (<xref target="data-model"/>), the number rule
          (<xref target="numbers"/>), and one table of limits
          (<xref target="limits"/>). A literal whose correctly rounded value
          is an infinity is unsupported_number; one whose correctly rounded
          value is zero is the integer 0, and one whose correctly rounded
          value is a nonzero subnormal is unsupported_number.</li>
          <li anchor="chg-host-values">Host values
          (<xref target="host-values"/>): refused, never rewritten, never an
          exception, and with the same result as the corresponding JSON
          text. A declared field that holds a host value outside the data
          model is checked under its field type as
          <xref target="fieldtypes"/> states, and the contents of an object
          or array nested deeper than 64 are not examined
          (<xref target="data-model"/>).</li>
          <li anchor="chg-reason-order">Reason order
          (<xref target="reason-order"/>). Computation phases 0 through 2 are
          gates that yield exactly one reason. The other phases all run,
          and their reasons are sorted by phase and field position and
          deduplicated, so unsupported_number always precedes
          unsupported_value.</li>
          <li anchor="chg-definition-conformance">Definition conformance and
          resolution (Sections <xref target="conformance" format="counter"/>
          and <xref target="resolution" format="counter"/>). A field name is
          a non-empty string without ":", unique, and not action_type. The
          order of configured definitions no longer affects the
          result.</li>
          <li anchor="chg-definition-digest">definition_sha256
          (<xref target="definition-digest"/>), which computation,
          verification, and mapping report.</li>
          <li anchor="chg-definition-mismatch">An expected definition_sha256
          for verification, and the reason definition_mismatch
          (<xref target="verification"/>).</li>
          <li anchor="chg-verify-details">Verification details, one
          closed-shape entry per underlying reason
          (<xref target="details"/>).</li>
          <li anchor="chg-deprecated">Status never affects computation or
          verification, so a deprecated type resolves, computes, and verifies
          wherever its fields resolve (<xref target="status"/>).</li>
          <li anchor="chg-code-type">The code field type, named code
          formats, and the reason invalid_code
          (<xref target="code-fields"/>).</li>
          <li anchor="chg-field-type-rules">Field types match whole values,
          empty strings are present, and the integer type is value-based
          (<xref target="fieldtypes"/>).</li>
          <li anchor="chg-pin-rule">The monotone enum advance
          (<xref target="names"/>) replaces the narrow correction rule of
          -03. The -03 sentences that treated any added value as a new type
          version are replaced; a relying party that needs exact
          reproducibility pins definition_sha256. The migration from
          reference registry version 3 to version 4 removed accepted values
          before this rule existed; its decisions remain decisions under
          version 3.</li>
          <li anchor="chg-option-guards">A suite, definition-source, or
          enum-snapshot option of the wrong type counts as absent, and an
          expected definition_sha256 of any type is compared, never ignored
          (Sections <xref target="computation" format="counter"/> and
          <xref target="verification" format="counter"/>).</li>
          <li anchor="chg-accept-unregistered">The accept-unregistered
          verifier option of -03 is removed. An object whose type has no
          definition fails verification as invalid_object with the detail
          unknown_action_type (<xref target="local"/>).</li>
          <li anchor="chg-mapping-extensions">The loss policy
          declared-source-semantic-loss, the transform
          sha256-hex-to-digest, and the mapping profile member
          omitted_source_fields (<xref target="mapping-object"/>). The
          reference implementations and their conformance corpus already
          used them; a mapper written from -03 refused such profiles.</li>
          <li anchor="chg-mapping-limits">Mapping limits, counted in UTF-8
          octets: 1 to 128 rules, source paths of at most 2048 octets,
          profile strings of 1 to 512 octets, and omission reasons of 1 to
          2048 octets (<xref target="limits"/>).</li>
          <li anchor="chg-mapping-target-field">A target_field may be any
          field name other than action_type, so a required field such as
          @version can be mapped (<xref target="mapping-object"/>).</li>
          <li anchor="chg-mapping-order">Mapping stages A through D, and the
          left: and right: composition of comparison reasons, are normative
          (Sections <xref target="mapping-algorithm" format="counter"/> and
          <xref target="mapping-reasons" format="counter"/>).</li>
          <li anchor="chg-mapping-suite">The mapper uses jcs-sha256 only
          when no suite is given (<xref target="mapping-algorithm"/>).</li>
          <li anchor="chg-mapping-stage-b">Mapping stage B reads the
          profile's source_format and loss_policy members whenever the
          profile is an object, whether or not it is in the data model, and
          a profile outside the data model has no digest, so it yields
          mapping_profile_unpinned (<xref target="mapping-algorithm"/>).
          Before this revision, one of the reference implementations read
          neither member of a profile nested deeper than 64, past the value
          count, cyclic, or holding a host value of no JSON kind.</li>
          <li anchor="chg-enum-snapshot-shape">The shape of an enum snapshot
          read from JSON text, and the requirement that the values_snapshot
          and values_sha256 members of an external enum be non-empty
          strings (<xref target="enum-resolution"/>).</li>
          <li anchor="chg-cbor-suite">The mapping of the data model to CBOR
          under cbor-sha256: an object is a map with text-string keys, a
          number is an integer of major type 0 or 1, and no tag, byte
          string, or floating-point value appears. The size limit is
          measured on the RFC 8785 encoding for every suite, support for
          the suite is optional, and <xref target="example-compute"/> gives
          the encoding, digest, and CAID of an example
          (<xref target="suites"/>). -03 named only CBOR core deterministic
          encoding (Section 4.2 of RFC 8949).</li>
        </ul>
      </section>
      <section anchor="changes-03-reasons">
        <name>Reason Changes</name>
        <ul spacing="normal">
          <li anchor="chg-reason-unknown-suite-parse">A grammatical suite
          outside the suite registry parses to unknown_suite instead of
          malformed_caid (<xref target="parsing"/>). This changes
          verification step 1 of -03, "Strict-parse the CAID string ...,
          else malformed_caid": verification phase 1 now yields
          malformed_caid or unknown_suite (<xref target="verification"/>).
          The input is refused either way.</li>
          <li anchor="chg-reason-surrogate">An unpaired surrogate escape in
          JSON text is malformed_json; in a host value it remains
          unsupported_value (Sections <xref target="json-text"
          format="counter"/> and <xref target="host-values"
          format="counter"/>).</li>
          <li anchor="chg-reason-amount">A string that fails amount-string is
          invalid_amount and a value that is not a string is mistyped_field;
          -03 allowed either reason for the former
          (<xref target="fieldtypes"/>).</li>
          <li anchor="chg-reason-registered-suite">A registered suite that an
          implementation does not implement parses, and computation and
          verification report it as unknown_suite; -03 left the
          verification reason unstated
          (<xref target="verification"/>).</li>
        </ul>
      </section>
      <section anchor="changes-03-registry">
        <name>Reference Registry</name>
        <ul spacing="normal">
          <li anchor="chg-registry-v5">The reference registry
          <xref target="CAID-REGISTRY"/> advances to registry version 5,
          with 62 type versions: 53 active, every one of which can compute,
          and 9 deprecated. dns.record.delete.1 and vendor.onboard.1
          receive their first enum pins. key.create.2, key.rotate.2,
          firewall.rule.open.2, pii.export.2, and phi.disclose.2 resolve
          their open enums with existing field types. payment.refund.2,
          ach.debit.originate.2, rx.dispense.2, and prior.auth.approve.2 use
          code fields. contract.execute.2 requires both contract_value and
          currency; contract.execute.1 stays active for contracts that state
          no monetary value. The nine superseded version 1 types are
          deprecated and still resolve. Registry version 4 is kept byte for
          byte as <tt>history/action-types.v4.json</tt>, the last file
          that declared registry version 4, which <tt>digests.json</tt>
          pins by its SHA-256, and every type's definition_sha256 is
          published.</li>
        </ul>
      </section>
      <section anchor="changes-03-parties">
        <name>Requirements on Other Parties</name>
        <t>These requirements bind issuers, type authors, registrants,
        executors, carrying protocols, relying parties, deployments, and
        applications. The operations of <xref target="overview"/> cannot
        observe them, so no conformance vector pins them.</t>
        <ul spacing="normal">
          <li anchor="ed-embedded-text">The party that extracts an action
          object embedded in a larger JSON text applies rules 2 through 4 of
          <xref target="json-text"/> to the whole enclosing text, so a
          duplicate member anywhere in it is malformed_json.</li>
          <li anchor="ed-executor-values">An executor invokes the operation
          only with the values it constructed or validated, and never
          re-reads the action object through a separate parser
          (<xref target="effect-boundary"/>).</li>
          <li anchor="ed-tool-call-members">An issuer adds no member to a
          tool.call.1 action object beyond action_type, target, tool, args,
          and occurrence_id, and a deployment that must tell identical calls
          apart, or resist guessing, includes occurrence_id unless args
          already carries an identifier that does so
          (<xref target="tool-call-type"/>).</li>
          <li anchor="ed-number-literals">Issuers do not emit a number literal
          whose exact value is not an integer but whose correctly rounded
          value is (<xref target="numbers"/>).</li>
          <li anchor="ed-number-readers">A relying party that evaluates a
          number in an action object evaluates the value of
          <xref target="numbers"/>, or refuses number tokens that have a
          fraction or exponent part before relying on a match, and a
          quantity compared against a threshold is typed amount-string
          (<xref target="security-parsing"/>).</li>
          <li anchor="ed-multiple-caids">A relying party decides which suites
          it accepts, and a verifier accepts no CAID under another suite. When
          an artifact carries several CAIDs for one action, the verifier
          verifies every CAID whose suite it accepts and implements, treats
          the failure of any one as the failure of all, and never selects the
          CAID that verifies (<xref target="equality"/>).</li>
          <li anchor="ed-signature-coverage">A signature, MAC, or commitment
          that is to be read as a commitment to a CAID covers the complete
          CAID string (<xref target="security-domain"/>).</li>
          <li anchor="ed-truncation">A CAID is never abbreviated for
          comparison, and a relying party compares an abbreviated form with
          nothing (<xref target="security-truncation"/>).</li>
          <li anchor="ed-occurrence">A type that must distinguish repeated
          identical operations requires an occurrence identifier
          (<xref target="security-replay"/>).</li>
          <li anchor="ed-message-bounds">A protocol that accepts action objects
          from parties it does not trust bounds its own messages well below
          the limits of <xref target="limits"/>
          (<xref target="security-dos"/>).</li>
          <li anchor="ed-suite-deprecation">A suite is deprecated once
          practical collision attacks on its digest are known or
          anticipated; issuers then stop emitting CAIDs under it, and
          relying parties remove it from the suites they accept (Sections
          <xref target="suites" format="counter"/> and
          <xref target="iana-suites" format="counter"/>).</li>
          <li anchor="ed-approval-display">An approval interface applies
          confusable detection to identifier-like fields, displays every
          member with the control and bidirectional formatting characters of
          member names escaped, and flags an undeclared member whose name
          matches a declared one under case folding, NFKC normalization, or
          the confusable skeleton; an interface or log that displays reasons
          escapes them (<xref target="security-unicode"/>).</li>
          <li anchor="ed-identifier-normalization">A type whose fields name
          identifiers such as hosts, accounts, email addresses, or tool names
          states their normalization in digest_notes, and issuers apply it
          before computing (<xref target="security-unicode"/>).</li>
          <li anchor="ed-network-pins">A registry file obtained over the
          network is checked against its digest before it is parsed
          (<xref target="security-definitions"/>).</li>
          <li anchor="ed-local-names">Parties that use CAID across domains
          pin the same definition, registry snapshot, or definition_sha256,
          as -03 required of cross-domain verifiers, and a local deployment
          gives its types an organization-specific first segment
          (<xref target="local"/>).</li>
          <li anchor="ed-uri-use">An application does not dereference a
          CAID and does not normalize a string before parsing it as one
          (<xref target="iana-uri"/>).</li>
          <li anchor="ed-logging">A CAID is logged, transmitted, and placed in
          URLs only where its action object could be, which reverses the -03
          recommendation that identifiers be treated as public values
          (<xref target="privacy"/>).</li>
          <li anchor="ed-type-entropy">A type whose required fields can all be
          low-entropy should require a member that carries at least 128 bits
          of entropy from the system of record; a later registration without
          one states why (Sections <xref target="privacy" format="counter"/>
          and <xref target="iana-action-types" format="counter"/>).</li>
          <li anchor="ed-keyed-commitment">A deployment that needs a keyed
          commitment in a digest field uses a type whose notes specify it
          (<xref target="privacy"/>).</li>
          <li anchor="ed-snapshot-files">A registrant whose type pins an
          external enum supplies the snapshot file, with its source and what
          is known of its terms, and the SHA-256 digest of the file
          (<xref target="iana-action-types"/>).</li>
        </ul>
      </section>
      <section anchor="changes-03-editorial">
        <name>Other Changes</name>
        <t>The following changes add or correct text. None of them changes
        what an implementation of the operations of
        <xref target="overview"/> accepts, refuses, or reports.</t>
        <ul spacing="normal">
          <li anchor="ed-structure">A processing overview
          (<xref target="overview"/>) and four appendices: the collected
          ABNF, now the only statement of every grammar, with case-sensitive
          strings <xref target="RFC7405"/>; the reason tables; worked
          examples that recompute; and the initial CAID Action Types.</li>
          <li anchor="ed-example">The identifier example of
          <xref target="syntax"/>, which had no action object, is replaced
          by the example of <xref target="example-compute"/>. Long lines in
          examples are folded as specified in
          <xref target="RFC8792"/>.</li>
          <li anchor="ed-terms">Terminology defines relying party, executor,
          presenter, mapper, and kind, and one sentence states conformance:
          every operation of <xref target="overview"/> that an implementation
          offers returns exactly the result that this document specifies
          (<xref target="terms"/>).</li>
          <li anchor="ed-json-precision"><xref target="json-text"/> excludes
          Section 2.2 of RFC 7493, whose number constraint the decoder does
          not apply, and states that an escaped surrogate pair is valid.
          <xref target="suites"/> notes that RFC 8785 sorts member names by
          UTF-16 code units.</li>
          <li anchor="ed-processing-text">Processing text is corrected
          where it did not match the processing: what absent options do
          in <xref target="computation"/>; the phase 1 test of
          <xref target="tab-compute"/> and the test of
          <xref target="host-values"/>, which use the value's kind, and
          which host numeric types a binding represents as numbers; the
          nesting row of <xref target="tab-limits"/>; stage C, which names
          the two reasons it cannot report; the validation projection, whose
          definition no longer depends on the conformance condition that uses
          it; and
          <xref target="details"/>.</li>
          <li anchor="ed-security">Security Considerations now open with
          what CAID defines and whom it trusts; name collision resistance
          where the party that constructs an action object may be
          adversarial; list the values fixed to SHA-256 and how each
          migrates; and explain the memory that the limits admit, why
          code-format matching is linear, and why a new suite leaves digest
          fields bounded by SHA-256. The requirements that Security
          Considerations add are listed in
          <xref target="changes-03-parties"/>. The parser requirements moved
          from Security Considerations to <xref target="json-text"/>.</li>
          <li anchor="ed-privacy">Privacy Considerations are a section of
          their own. They state that a CAID has the confidentiality of its
          action object, explain the preimage-guessing risk and the entropy
          of the identifiers that the initial types rely on, and state that a
          CAID is meant to be recomputed by parties that hold the action
          object, not propagated as a correlation identifier to parties that
          do not. The requirements they add are listed in
          <xref target="changes-03-parties"/>.</li>
          <li anchor="ed-iana">IANA Considerations request seven registries,
          each with a registration policy set by what a registration
          changes, and the caid URI scheme with Permanent status, and
          explain why no media type is registered. Of the 62 types of
          reference registry version 5, IANA is asked to register the 54 of
          <xref target="appendix-action-types-initial"/>; the 8 of
          <xref target="appendix-action-types-reference-only"/> are defined
          by other specifications, or carry a name that misdescribes the
          type, and stay in the reference registry. The section says who may
          request a change to an entry and that the IESG may act for a
          change controller that cannot be reached or does not respond;
          registers a new version of a type name only by, or with the
          written agreement of, the change controller of its earlier
          versions; registers a name with an organization-specific first
          segment only with that organization as change controller; and
          asks IANA to store the snapshot files derived from IANA
          registries. The -03 statement that the author's organization
          maintains the registries is removed.</li>
          <li anchor="ed-uri-utility">The registration of the caid URI scheme
          states why the scheme is defined instead of using an ni URI
          <xref target="RFC6920"/> or a URN namespace
          <xref target="RFC8141"/> (<xref target="iana-uri"/>).</li>
          <li anchor="ed-examples">The example of <xref target="schema"/> is
          the registry entry for payment.release.1 with its real
          values_sha256, the registration of <xref target="tool-call-type"/>
          is the registry entry for tool.call.1, member for member, and
          <xref target="example-projection"/> describes the projection
          correctly.</li>
          <li anchor="ed-implementation-status">An Implementation Status
          section <xref target="RFC7942"/>.</li>
          <li anchor="ed-references">Normative references to RFC 8259,
          RFC 3629, RFC 7405, RFC 7493, RFC 3986, IEEE 754, and the
          reference registry at a fixed commit, with the URL of the raw file
          whose octets its digest covers, and informative references to
          RFC 7595, RFC 6920, RFC 8141, RFC 7696, RFC 7942, RFC 8126,
          RFC 8792, RFC 6838, RFC 5730, RFC 5936, the Unicode Standard and its
          UTS #39, ISO 3166-1 and ISO 4217, whose code lists two enum
          snapshots carry, and the code systems whose syntax the code formats
          follow.</li>
          <li anchor="ed-wording">Wording that referred to earlier revisions
          as "this revision" is made revision-neutral.</li>
        </ul>
      </section>
    </section>
    <section anchor="changes" removeInRFC="true">
      <name>Changes since -02</name>
      <t>Revision -03 makes enum validation replayable. External enum
      references now require a snapshot or edition label, a SHA-256 pin over
      the complete JCS values array, exact local resolution, and a verified
      membership check. Bare, unresolved, digest-mismatched, and out-of-set
      values fail closed.</t>
      <t>The enum definition forms are now exact: a null member is present and
      malformed, compact inline members are trimmed of U+0020 SPACE only, a
      values array beside a compact inline reference must equal it, and an
      embedded values array beside an external reference is the pinned array.
      Values outside a compact inline list now fail closed.</t>
      <t>Required-field presence means a member of the action object itself.
      Strings and member names containing an unpaired surrogate are refused
      as unsupported_value, making explicit the refusal that RFC 8785 already
      requires. Registries could correct an existing value-set pin in a new
      registry version under narrow conditions; -04 replaces that rule with
      the monotone advance of <xref target="names"/>.</t>
      <t>The reference registry advances from version 3 to version 4. It pins
      the SIX ISO 4217 List One snapshot published 2026-09-17 for every
      currency field, by values digest and by a digest over the whole snapshot
      file, and pins the Dispense As Written codes of rx.dispense.1 inline.
      Existing action objects containing a code in that snapshot produce the
      same CAID bytes; a code that version 3 accepted but the snapshot omits
      is refused. Eleven active types in the reference registry require an
      external value set that has no pinned snapshot yet and cannot produce a
      CAID under version 4 until one is published. Deployments must update
      their registry and enum-snapshot pins before reporting validation under
      registry v4. Historical v3 decisions remain decisions under the
      historical registry and are not retroactively relabeled v4.</t>
      <t>Revision -03 does not change the action object, identifier syntax,
      digest suites, or mapping algorithm, and changes canonicalization only
      by making the unpaired-surrogate refusal explicit.</t>
    </section>
  </middle>
  <back>
    <references>
      <name>References</name>
      <references>
        <name>Normative References</name>
        <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.2119.xml"/>
        <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8174.xml"/>
        <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8785.xml"/>
        <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8949.xml"/>
        <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.6234.xml"/>
        <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.4648.xml"/>
        <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.3339.xml"/>
        <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.5234.xml"/>
        <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.7405.xml"/>
        <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.6901.xml"/>
        <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8259.xml"/>
        <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.3629.xml"/>
        <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.7493.xml"/>
        <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.3986.xml"/>
        <reference anchor="IEEE754" target="https://doi.org/10.1109/IEEESTD.2019.8766229">
          <front>
            <title>IEEE Standard for Floating-Point Arithmetic</title>
            <author><organization>IEEE</organization></author>
            <date year="2019" month="July"/>
          </front>
          <seriesInfo name="IEEE Std" value="754-2019"/>
          <seriesInfo name="DOI" value="10.1109/IEEESTD.2019.8766229"/>
        </reference>
        <reference anchor="CAID-REGISTRY" target="https://raw.githubusercontent.com/emiliaprotocol/emilia-protocol/cea10b85e96460a04bf55d683a1ebc34e8b2c9a6/caid/registry/action-types.json">
          <front>
            <title>CAID Reference Registry, Registry Version 5</title>
            <author><organization>EMILIA Protocol, Inc.</organization></author>
            <date year="2026" month="September"/>
          </front>
          <annotation>Registry version 5 is the file
          <tt>action-types.json</tt> at this fixed commit, whose octets
          the URL above serves. The CAID Action Types section of
          this document gives the SHA-256 digest of those octets. This
          reference covers that file alone. Beside it at the same commit,
          <tt>digests.json</tt> lists the definition_sha256 of every type,
          <tt>history/action-types.v4.json</tt> holds registry version
          4, and <tt>value-sets/</tt> holds the enum snapshots.</annotation>
        </reference>
      </references>
      <references>
        <name>Informative References</name>
        <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.7595.xml"/>
        <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.6920.xml"/>
        <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8141.xml"/>
        <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.7942.xml"/>
        <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8126.xml"/>
        <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8792.xml"/>
        <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.6838.xml"/>
        <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.7696.xml"/>
        <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.5730.xml"/>
        <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.5936.xml"/>
        <reference anchor="UTS39" target="https://www.unicode.org/reports/tr39/">
          <front>
            <title>Unicode Security Mechanisms</title>
            <author><organization>The Unicode Consortium</organization></author>
            <date/>
          </front>
          <seriesInfo name="Unicode Technical Standard" value="#39"/>
        </reference>
        <reference anchor="ICD-10-CM">
          <front>
            <title>ICD-10-CM Official Guidelines for Coding and Reporting</title>
            <author><organization>Centers for Medicare &amp; Medicaid Services and National Center for Health Statistics</organization></author>
            <date/>
          </front>
        </reference>
        <reference anchor="NDC">
          <front>
            <title>National Drug Code Directory</title>
            <author><organization>U.S. Food and Drug Administration</organization></author>
            <date/>
          </front>
        </reference>
        <reference anchor="CPT">
          <front>
            <title>Current Procedural Terminology (CPT)</title>
            <author><organization>American Medical Association</organization></author>
            <date/>
          </front>
        </reference>
        <reference anchor="HCPCS" target="https://www.cms.gov/medicare/coding-billing/healthcare-common-procedure-system">
          <front>
            <title>Healthcare Common Procedure Coding System (HCPCS)</title>
            <author><organization>Centers for Medicare &amp; Medicaid Services</organization></author>
            <date/>
          </front>
        </reference>
        <reference anchor="ISO3166-1">
          <front>
            <title>Codes for the representation of names of countries and their subdivisions, Part 1: Country code</title>
            <author><organization>International Organization for Standardization</organization></author>
            <date year="2020"/>
          </front>
          <seriesInfo name="ISO" value="3166-1:2020"/>
        </reference>
        <reference anchor="ISO3166-2">
          <front>
            <title>Codes for the representation of names of countries and their subdivisions, Part 2: Country subdivision code</title>
            <author><organization>International Organization for Standardization</organization></author>
            <date year="2020"/>
          </front>
          <seriesInfo name="ISO" value="3166-2:2020"/>
        </reference>
        <reference anchor="ISO4217">
          <front>
            <title>Codes for the representation of currencies</title>
            <author><organization>International Organization for Standardization</organization></author>
            <date year="2015"/>
          </front>
          <seriesInfo name="ISO" value="4217:2015"/>
        </reference>
        <reference anchor="ISO20022">
          <front>
            <title>ISO 20022 External Code Sets</title>
            <author><organization>ISO 20022 Registration Authority</organization></author>
            <date/>
          </front>
        </reference>
        <reference anchor="NACHA">
          <front>
            <title>Nacha Operating Rules</title>
            <author><organization>Nacha</organization></author>
            <date/>
          </front>
        </reference>
        <reference anchor="UNICODE" target="https://www.unicode.org/versions/latest/">
          <front>
            <title>The Unicode Standard</title>
            <author><organization>The Unicode Consortium</organization></author>
            <date/>
          </front>
        </reference>
        <reference anchor="I-D.schrock-ep-authorization-receipts">
          <front>
            <title>Authorization Receipts for High-Risk Agent Actions</title>
            <author fullname="Iman Schrock"><organization>EMILIA Protocol, Inc.</organization></author>
            <date year="2026" month="September" day="11"/>
          </front>
          <seriesInfo name="Internet-Draft" value="draft-schrock-ep-authorization-receipts-13"/>
        </reference>
        <reference anchor="I-D.schrock-action-evidence-boundary">
          <front>
            <title>The Action Evidence Boundary for Consequential Agent Effects</title>
            <author fullname="Iman Schrock"><organization>EMILIA Protocol, Inc.</organization></author>
            <date year="2026" month="September" day="25"/>
          </front>
          <seriesInfo name="Internet-Draft" value="draft-schrock-action-evidence-boundary-07"/>
        </reference>
        <reference anchor="I-D.schrock-ep-authorization-evidence-chain">
          <front>
            <title>Authorization Evidence Chains: Composing Heterogeneous Agent-Action Evidence (EP-AEC)</title>
            <author fullname="Iman Schrock"><organization>EMILIA Protocol, Inc.</organization></author>
            <date year="2026" month="September" day="6"/>
          </front>
          <seriesInfo name="Internet-Draft" value="draft-schrock-ep-authorization-evidence-chain-06"/>
        </reference>
        <reference anchor="I-D.thallapelly-oasnt-caid">
          <front>
            <title>OASNT-CAID: Canonical Action Identifier Derivation and the Named-Human Binding</title>
            <author fullname="A. Thallapelly"><organization>OmniArx</organization></author>
            <date year="2026" month="August" day="5"/>
          </front>
          <seriesInfo name="Internet-Draft" value="draft-thallapelly-oasnt-caid-01"/>
        </reference>
        <xi:include href="https://bib.ietf.org/public/rfc/bibxml3/reference.I-D.lee-orprg-permit-receipts.xml"/>
        <xi:include href="https://bib.ietf.org/public/rfc/bibxml3/reference.I-D.morrow-sogomonian-exec-outcome-attest.xml"/>
      </references>
    </references>
    <section anchor="appendix-abnf">
      <name>Collected ABNF</name>
      <t>This appendix collects every grammar of this document in the ABNF
      of <xref target="RFC5234"/>, with the case-sensitive string syntax of
      <xref target="RFC7405"/>. ALPHA, DIGIT, and HEXDIG are the core rules
      of <xref target="RFC5234"/>. Each rule matches a string as a whole.
      Part A.1 is the identifier and part A.2 the digest syntax of each
      suite. Part A.3 holds the lexical field types, and part A.4 the code
      formats that this document registers (<xref target="code-fields"/>),
      each named by its rule name. Part A.5 constrains definitions, part A.6 the mapping
      profile, and part A.7 accepts every reason of
      <xref target="appendix-reasons"/>, including nested forms such as
      mapped_action:missing_material_field:amount. A timestamp's day is
      further limited by the length of its month
      (<xref target="fieldtypes"/>).</t>
<sourcecode anchor="abnf-collected" type="abnf"><![CDATA[
; Collected ABNF [RFC5234] with case-sensitive strings [RFC7405].
; A string matches a rule only as a whole: nothing precedes or
; follows it, not even a final line feed.

; A.1 Identifier

caid          = %s"caid" ":" caid-version ":" action-type ":"
                suite ":" digest
                                 ; at most 1024 octets, and its
                                 ; action-type at most 512 (2.6)

caid-version  = "1"

action-type   = 1*( name-segment "." ) type-version
                                 ; at most 512 octets (2.6)
name-segment  = lower-char *( lower-char / DIGIT / "-" )
type-version  = pos-int
pos-int       = %x31-39 *DIGIT   ; positive integer, no leading zero

suite         = lower-char *( lower-char / DIGIT / "-" )

digest        = 1*b64url-char
b64url-char   = %x41-5A / %x61-7A / DIGIT / "-" / "_"
                                 ; A-Z / a-z / 0-9 / "-" / "_"

lower-char    = %x61-7A          ; a-z

; A.2 Digest syntax per suite
;
; A suite whose digest is n octets encodes it in c = ceil(8n/6)
; base64url characters. The final character carries u = 6c - 8n
; unused low bits, which are zero: of the 64 base64url characters,
; only those whose 6-bit value is a multiple of 2^u may end the
; digest. For n = 32 (jcs-sha256 and cbor-sha256), c = 43 and
; u = 2.

digest-256    = 42b64url-char b64url-z2
b64url-z2     = %x41 / %x45 / %x49 / %x4D / %x51 / %x55 / %x59
              / %x63 / %x67 / %x6B / %x6F / %x73 / %x77
              / %x30 / %x34 / %x38
                                 ; A E I M Q U Y c g k o s w 0 4 8

; A.3 Field types

amount-string = [ "-" ] int-part [ "." frac-part ]
int-part      = "0" / ( %x31-39 *DIGIT )  ; no leading zero
frac-part     = 1*DIGIT

digest-field  = %s"sha256:" 64hex-lower
hex-lower     = DIGIT / %x61-66  ; 0-9 / a-f

timestamp     = full-date %x54 utc-time %x5A   ; "T" and "Z"
full-date     = date-year "-" date-month "-" date-mday
date-year     = 4DIGIT
date-month    = "0" %x31-39 / "1" %x30-32      ; 01-12
date-mday     = "0" %x31-39 / %x31-32 DIGIT / "3" %x30-31
                                 ; 01-31, within the month
utc-time      = time-hour ":" time-minute ":" time-second
                [ time-fraction ]
time-hour     = %x30-31 DIGIT / "2" %x30-33    ; 00-23
time-minute   = %x30-35 DIGIT                  ; 00-59
time-second   = %x30-35 DIGIT                  ; 00-59, never 60
time-fraction = "." 1*DIGIT

; A.4 Code formats
;
; The rule name of each code format is its registered format name.
; A format fixes syntax only, never which codes exist.

icd-10-cm     = UALPHA 2UALNUM [ "." 1*4UALNUM ]
ndc-11        = 11DIGIT
ndc-10-hyphenated
              = 4DIGIT "-" 4DIGIT "-" 2DIGIT
              / 5DIGIT "-" 4DIGIT "-" 1DIGIT
              / 5DIGIT "-" 3DIGIT "-" 2DIGIT
cpt           = 4DIGIT ( DIGIT / UALPHA )
hcpcs-level-ii
              = UALPHA 4DIGIT
hcpcs         = cpt / hcpcs-level-ii
iso-3166-2    = 2UALPHA "-" 1*3UALNUM
iso20022-external-code
              = 1*4UALNUM
nacha-sec     = 3UALNUM

UALPHA        = %x41-5A          ; A-Z
UALNUM        = UALPHA / DIGIT

; A.5 Definitions

field-name    = 1*field-char
field-char    = %x00-39 / %x3B-D7FF / %xE000-10FFFF
                                 ; any scalar value except ":"; a
                                 ; field name is also a string of
                                 ; the data model (2.2), so it
                                 ; holds no noncharacter

format-name   = lower-char *( lower-char / DIGIT / "-" )
                                 ; the formats of this document: A.4

code-system   = uri-scheme ":" 1*uri-char
                                 ; a scheme, ":", and URI characters:
                                 ; no fragment and no IP-literal
                                 ; host; at most 2048 octets (2.6)
uri-scheme    = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
uri-char      = ALPHA / DIGIT / "-" / "." / "_" / "~"
              / "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+"
              / "," / ";" / "=" / ":" / "@" / "/" / "?"
              / pct-encoded
pct-encoded   = "%" HEXDIG HEXDIG

; A.6 Action-Mapping Profile

json-pointer  = *( "/" reference-token )       ; [RFC6901]
source-path   = "/" reference-token json-pointer
                                 ; a json-pointer other than ""
reference-token
              = *( unescaped / escaped )
unescaped     = %x00-2E / %x30-7D / %x7F-D7FF / %xE000-10FFFF
escaped       = "~" ( "0" / "1" )
array-index   = "0" / ( %x31-39 *DIGIT )
hex-sha256    = 64hex-lower

; A.7 Reasons

reason        = core-reason / mapping-reason / comparison-reason

core-reason   = compute-reason / core-only
core-only     = %s"malformed_json" / %s"malformed_caid"
              / %s"action_type_mismatch"
              / %s"definition_mismatch" / %s"digest_mismatch"
              / %s"invalid_object"
compute-reason
              = compute-bare / field-code ":" field-name
compute-bare  = %s"invalid_action_type" / %s"unknown_action_type"
              / %s"invalid_definition" / %s"unknown_suite"
              / %s"unsupported_number" / %s"unsupported_value"
field-code    = %s"missing_material_field" / %s"mistyped_field"
              / %s"invalid_amount" / %s"invalid_code"

mapping-reason
              = mapping-bare
              / %s"unmapped_material_field" ":" field-name
              / pointer-code ":" source-path
              / %s"mapped_action" ":" compute-reason
mapping-bare  = %s"invalid_mapping_profile"
              / %s"unknown_action_type" / %s"invalid_definition"
              / %s"native_verification_required"
              / %s"mapping_profile_unpinned"
              / %s"source_format_mismatch" / %s"source_not_object"
              / %s"source_not_canonicalizable"
              / %s"declared_source_semantic_loss"
pointer-code  = %s"invalid_source_path" / %s"missing_source_field"
              / %s"source_value_type_mismatch"
              / %s"source_value_not_canonicalizable"
              / %s"unknown_transform"

comparison-reason
              = ( %s"left" / %s"right" ) ":" mapping-reason
              / %s"target_action_type_mismatch"
              / %s"material_projection_mismatch"
]]></sourcecode>
    </section>
    <section anchor="appendix-reasons">
      <name>Reason Codes</name>
      <t>These tables list every reason. A reason with a parameter is the
      code, ":", and the parameter, which matches the ABNF rule named in the
      Parameter column. Computation and verification phases are those of
      Sections <xref target="computation" format="counter"/> and
      <xref target="verification" format="counter"/>; "(gate)" marks a phase
      that yields exactly one reason. Decoding and parsing are single steps,
      named without a phase. Mapping stages are those of
      <xref target="mapping-algorithm"/>, and comparison prefixes a failed
      mapping's reasons with "left:" or "right:". A reason that computation
      and mapping stage A share is listed once, in the first table. These
      tables are the
      initial contents of the CAID Reason Codes registry
      (<xref target="iana-reasons"/>).</t>
<table anchor="tab-core-reasons">
  <name>Core Reasons</name>
  <thead><tr><th>Reason</th><th>Parameter</th><th>Operations and phases</th></tr></thead>
  <tbody>
    <tr><td>malformed_json</td><td>none</td><td>decode; compute 0 (gate); verify 2 (gate)</td></tr>
    <tr><td>malformed_caid</td><td>none</td><td>parse; verify 1 (gate)</td></tr>
    <tr><td>unknown_suite</td><td>none</td><td>parse; compute 5; verify 1 (gate); verify 6</td></tr>
    <tr><td>invalid_action_type</td><td>none</td><td>compute 1 (gate)</td></tr>
    <tr><td>unknown_action_type</td><td>none</td><td>compute 2 (gate); mapping stage A</td></tr>
    <tr><td>invalid_definition</td><td>none</td><td>compute 2 (gate); mapping stage A</td></tr>
    <tr><td>definition_mismatch</td><td>none</td><td>verify 5</td></tr>
    <tr><td>missing_material_field</td><td>field-name</td><td>compute 3</td></tr>
    <tr><td>mistyped_field</td><td>field-name</td><td>compute 4</td></tr>
    <tr><td>invalid_amount</td><td>field-name</td><td>compute 4</td></tr>
    <tr><td>invalid_code</td><td>field-name</td><td>compute 4</td></tr>
    <tr><td>unsupported_number</td><td>none</td><td>compute 6</td></tr>
    <tr><td>unsupported_value</td><td>none</td><td>compute 7</td></tr>
    <tr><td>action_type_mismatch</td><td>none</td><td>verify 4</td></tr>
    <tr><td>digest_mismatch</td><td>none</td><td>verify 6</td></tr>
    <tr><td>invalid_object</td><td>none</td><td>verify 3 (gate); verify 7</td></tr>
  </tbody>
</table>
<table anchor="tab-mapping-reasons">
  <name>Mapping Reasons</name>
  <thead><tr><th>Reason</th><th>Parameter</th><th>Stage</th></tr></thead>
  <tbody>
    <tr><td>invalid_mapping_profile</td><td>none</td><td>A</td></tr>
    <tr><td>unmapped_material_field</td><td>field-name</td><td>A</td></tr>
    <tr><td>native_verification_required</td><td>none</td><td>B</td></tr>
    <tr><td>mapping_profile_unpinned</td><td>none</td><td>B</td></tr>
    <tr><td>source_format_mismatch</td><td>none</td><td>B</td></tr>
    <tr><td>source_not_object</td><td>none</td><td>B</td></tr>
    <tr><td>source_not_canonicalizable</td><td>none</td><td>B</td></tr>
    <tr><td>declared_source_semantic_loss</td><td>none</td><td>B</td></tr>
    <tr><td>invalid_source_path</td><td>source-path</td><td>C</td></tr>
    <tr><td>missing_source_field</td><td>source-path</td><td>C</td></tr>
    <tr><td>source_value_type_mismatch</td><td>source-path</td><td>C</td></tr>
    <tr><td>source_value_not_canonicalizable</td><td>source-path</td><td>C</td></tr>
    <tr><td>unknown_transform</td><td>source-path</td><td>C</td></tr>
    <tr><td>mapped_action</td><td>compute-reason</td><td>D</td></tr>
    <tr><td>target_action_type_mismatch</td><td>none</td><td>comparison</td></tr>
    <tr><td>material_projection_mismatch</td><td>none</td><td>comparison</td></tr>
  </tbody>
</table>
    </section>
    <section anchor="appendix-examples">
      <name>Worked Examples</name>
      <t>Every value in this appendix recomputes from the objects shown and
      the definitions of reference registry version 5
      <xref target="CAID-REGISTRY"/>, with the enum snapshots archived
      beside it at the same commit (<xref target="iana-action-types"/>).
      Long lines are folded as specified in <xref target="RFC8792"/>.</t>
      <section anchor="example-compute">
        <name>Computation</name>
        <t>This payment.release.1 action object:</t>
<sourcecode anchor="exc-payment-object" type="json"><![CDATA[
=============== NOTE: '\' line wrapping per RFC 8792 ================

{
  "action_type": "payment.release.1",
  "amount": "250.00",
  "currency": "EUR",
  "beneficiary_account": "sha256:9f86d081884c7d659a2feaa0c55ad015a3b\
  f4f1b2b0b822cd15d6c15b0f00a08",
  "payment_instruction_id": "pi-2026-000117",
  "memo": "invoice 4471"
}
]]></sourcecode>
        <t>has members in a different order from its canonical encoding,
        which sorts them. Its RFC 8785 encoding is 230 octets:</t>
<sourcecode anchor="exc-payment-canonical"><![CDATA[
=============== NOTE: '\' line wrapping per RFC 8792 ================

{"action_type":"payment.release.1","amount":"250.00","beneficiary_ac\
count":"sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6\
c15b0f00a08","currency":"EUR","memo":"invoice 4471","payment_instruc\
tion_id":"pi-2026-000117"}
]]></sourcecode>
        <t>Computation under jcs-sha256 returns the CAID, the SHA-256 digest
        of those octets, and the definition_sha256 of payment.release.1 in
        registry version 5:</t>
<sourcecode anchor="exc-payment-result" type="json"><![CDATA[
=============== NOTE: '\' line wrapping per RFC 8792 ================

{
  "caid": "caid:1:payment.release.1:jcs-sha256:liLG9pKgkLt3silrjf1wa\
  0xIHz5YFrBB9HI-arxrO1Y",
  "digest": "sha256:9622c6f692a090bb77b2296b8dfd706b4c481f3e5816b041\
  f4723e6abc6b3b56",
  "definition_sha256": "sha256:3a5ad4c0a3a8dbf7eb9ea5f4c3b2ceb07ba19\
  72fac49acc6006dcac64726ff12"
}
]]></sourcecode>
        <t>Under cbor-sha256, the core deterministic CBOR encoding of the
        same object is 207 octets. Its map keys sort by their encoded
        octets, so shorter keys come first and the members appear in the
        order memo, amount, currency, action_type, beneficiary_account, and
        payment_instruction_id, which differs from the RFC 8785 order. In
        hexadecimal, 32 octets to a line:</t>
<sourcecode anchor="exc-payment-cbor"><![CDATA[
a6646d656d6f6c696e766f696365203434373166616d6f756e74663235302e30
306863757272656e6379634555526b616374696f6e5f74797065717061796d65
6e742e72656c656173652e317362656e65666963696172795f6163636f756e74
78477368613235363a3966383664303831383834633764363539613266656161
3063353561643031356133626634663162326230623832326364313564366331
356230663030613038767061796d656e745f696e737472756374696f6e5f6964
6e70692d323032362d303030313137
]]></sourcecode>
        <t>Computation under cbor-sha256 returns this result; the
        definition_sha256 does not depend on the suite:</t>
<sourcecode anchor="exc-payment-cbor-result" type="json"><![CDATA[
=============== NOTE: '\' line wrapping per RFC 8792 ================

{
  "caid": "caid:1:payment.release.1:cbor-sha256:7bBO8giRaW3iBRR-C6cZ\
  FnqkRjAPTwTPMrvwd-200vY",
  "digest": "sha256:edb04ef20891696de205147e0ba719167aa446300f4f04cf\
  32bbf077edb4d2f6",
  "definition_sha256": "sha256:3a5ad4c0a3a8dbf7eb9ea5f4c3b2ceb07ba19\
  72fac49acc6006dcac64726ff12"
}
]]></sourcecode>
      </section>
      <section anchor="example-refusal">
        <name>Refusal and Reason Order</name>
        <t>This object lacks two required fields, carries an amount with a
        leading zero, and carries a fractional number in the optional memo
        field:</t>
<sourcecode anchor="exc-refusal-object" type="json"><![CDATA[
{
  "action_type": "payment.release.1",
  "amount": "01.50",
  "currency": "EUR",
  "memo": 7.5
}
]]></sourcecode>
        <t>Computation refuses it. The missing fields come first, in
        required_fields order; then the phase 4 reasons in field order,
        where amount is field 0 and memo, the first optional field, is field
        4; then unsupported_number for the fractional value:</t>
<sourcecode anchor="exc-refusal-result" type="json"><![CDATA[
{
  "refusals": [
    "missing_material_field:beneficiary_account",
    "missing_material_field:payment_instruction_id",
    "invalid_amount:amount",
    "mistyped_field:memo",
    "unsupported_number"
  ]
}
]]></sourcecode>
      </section>
      <section anchor="example-verify">
        <name>Verification Details</name>
        <t>Verifying the CAID of <xref target="example-compute"/> against the
        object of <xref target="example-refusal"/> yields invalid_object.
        The action types match, and no digest comparison is made because
        the object cannot be canonicalized. The details expand
        invalid_object into its computation reasons, and definition_sha256
        is reported because a conforming definition resolved:</t>
<sourcecode anchor="exc-verify-result" type="json"><![CDATA[
=============== NOTE: '\' line wrapping per RFC 8792 ================

{
  "valid": false,
  "reasons": [
    "invalid_object"
  ],
  "details": [
    {
      "reason": "missing_material_field:beneficiary_account",
      "field": "beneficiary_account",
      "rule": "required-field",
      "observed": "absent"
    },
    {
      "reason": "missing_material_field:payment_instruction_id",
      "field": "payment_instruction_id",
      "rule": "required-field",
      "observed": "absent"
    },
    {
      "reason": "invalid_amount:amount",
      "field": "amount",
      "rule": "amount-string",
      "observed": "string"
    },
    {
      "reason": "mistyped_field:memo",
      "field": "memo",
      "rule": "field-type",
      "observed": "number"
    },
    {
      "reason": "unsupported_number",
      "field": null,
      "rule": "number",
      "observed": null
    }
  ],
  "definition_sha256": "sha256:3a5ad4c0a3a8dbf7eb9ea5f4c3b2ceb07ba19\
  72fac49acc6006dcac64726ff12"
}
]]></sourcecode>
      </section>
      <section anchor="example-projection">
        <name>Definition Digest</name>
        <t>The validation projection of the tool.call.1 definition of
        <xref target="tool-call-type"/> keeps action_type, required_fields,
        and optional_fields, drops the definition's other members (status,
        risk_class, summary, digest_notes, and references), and drops the
        notes member of every field entry. Its RFC 8785 encoding is:</t>
<sourcecode anchor="exc-projection"><![CDATA[
=============== NOTE: '\' line wrapping per RFC 8792 ================

{"action_type":"tool.call.1","optional_fields":[{"name":"occurrence_\
id","type":"string"}],"required_fields":[{"name":"target","type":"st\
ring"},{"name":"tool","type":"string"},{"name":"args","type":"object\
"}]}
]]></sourcecode>
        <t>and its definition_sha256 is:</t>
<sourcecode anchor="exc-projection-digest"><![CDATA[
=============== NOTE: '\' line wrapping per RFC 8792 ================

sha256:c95e21136fd8b6df646be2957fe42fbf18935add20da6bc9569aa2d1a771a\
fa2
]]></sourcecode>
      </section>
      <section anchor="example-code">
        <name>Code Fields</name>
        <t>prior.auth.approve.2 carries a HCPCS code in service_code (format
        hcpcs) and an ICD-10-CM code in diagnosis_code (format icd-10-cm).
        This object computes:</t>
<sourcecode anchor="exc-code-object" type="json"><![CDATA[
=============== NOTE: '\' line wrapping per RFC 8792 ================

{
  "action_type": "prior.auth.approve.2",
  "patient_ref": "sha256:8d3148217a50cc7dc5c03c79a8932e5bf60dde17db0\
  b3af90c9fed46d0c47e76",
  "service_code": "E0601",
  "diagnosis_code": "G47.33",
  "authorization_number": "PA-2026-000418",
  "valid_from": "2026-10-01T00:00:00Z",
  "valid_until": "2026-12-31T23:59:59Z"
}
]]></sourcecode>
<sourcecode anchor="exc-code-result" type="json"><![CDATA[
=============== NOTE: '\' line wrapping per RFC 8792 ================

{
  "caid": "caid:1:prior.auth.approve.2:jcs-sha256:j7WskhX5l_V70KUTEf\
  d1ysXivWV5oFT1q-J1Tvra57U",
  "digest": "sha256:8fb5ac9215f997f57bd0a51311f775cac5e2bd6579a054f5\
  abe2754efadae7b5",
  "definition_sha256": "sha256:c25345a298c9b0ec96d019e4e2bcfd6ddd259\
  ad064a7cb75b581999eaaf10086"
}
]]></sourcecode>
        <t>The same object with the codes written "e0601" and "G4733" is
        refused, because no format folds case or inserts a dot:</t>
<sourcecode anchor="exc-code-refusal-object" type="json"><![CDATA[
=============== NOTE: '\' line wrapping per RFC 8792 ================

{
  "action_type": "prior.auth.approve.2",
  "patient_ref": "sha256:8d3148217a50cc7dc5c03c79a8932e5bf60dde17db0\
  b3af90c9fed46d0c47e76",
  "service_code": "e0601",
  "diagnosis_code": "G4733",
  "authorization_number": "PA-2026-000418",
  "valid_from": "2026-10-01T00:00:00Z",
  "valid_until": "2026-12-31T23:59:59Z"
}
]]></sourcecode>
<sourcecode anchor="exc-code-refusal-result" type="json"><![CDATA[
{
  "refusals": [
    "invalid_code:service_code",
    "invalid_code:diagnosis_code"
  ]
}
]]></sourcecode>
      </section>
      <section anchor="example-mapping">
        <name>Mapping</name>
        <t>Under the profile of <xref target="mapping-object"/>, with a
        native verification result of the boolean true, a source descriptor
        equal to
        the profile's source_format, and the profile digest pinned, this
        source:</t>
<sourcecode anchor="exc-map-source" type="json"><![CDATA[
{
  "checkout": {
    "order_id": "ord-7781",
    "merchant_id": "merchant-17",
    "total_amount": "129.95",
    "currency": "USD",
    "line_items": [
      {
        "sku": "A-1",
        "qty": 2
      }
    ],
    "customer_id": "cust-42",
    "fulfillment": {
      "method": "ship",
      "postal_code": "94107"
    }
  },
  "channel": "web"
}
]]></sourcecode>
        <t>projects to this order.place.1 action object. The channel member
        is not a material source path and is not mapped:</t>
<sourcecode anchor="exc-map-projected" type="json"><![CDATA[
=============== NOTE: '\' line wrapping per RFC 8792 ================

{
  "action_type": "order.place.1",
  "order_id": "ord-7781",
  "merchant_ref": "sha256:9a52791e954783da73f738762755102e10296f3cfd\
  07cebae3ed4fd540d82074",
  "total_amount": "129.95",
  "currency": "USD",
  "items_digest": "sha256:82cff441e6205b34ff18c69acdd583fe265b410b61\
  48f22c40bfcfbbcb117c75",
  "customer_ref": "sha256:8a3c5a67cad508582b5edf6b8352cea3ffbad7f448\
  12c1a736b4444c0f5746aa",
  "fulfillment_ref": "sha256:35a83b30c4e6d088acc77990cf683e55d8f101c\
  3d5570a8913528039cdb29f3c"
}
]]></sourcecode>
        <t>The mapping result carries these digests and this CAID:</t>
<sourcecode anchor="exc-map-result" type="json"><![CDATA[
=============== NOTE: '\' line wrapping per RFC 8792 ================

{
  "profile_digest": "sha256:ec833ebc5793db1cc25e917fb838856c048bedee\
  eb35ff7cb2d172943b0732fa",
  "source_digest": "sha256:371f6feb2f3d9767efe4190f25e0ba7b82208d9bc\
  916cf1114c84b0c396feaf9",
  "caid": "caid:1:order.place.1:jcs-sha256:UI-wYRrJp-P5iI5a2E2qKfT7_\
  -ijOogjNoN-wjwIEcg"
}
]]></sourcecode>
      </section>
    </section>
    <section anchor="appendix-action-types">
      <name>Action Types of Reference Registry Version 5</name>
      <t>This appendix lists the 62 type versions of registry version 5 of
      the reference registry <xref target="CAID-REGISTRY"/> in two parts:
      <xref target="appendix-action-types-initial"/>, the initial contents
      of the CAID Action Types registry (<xref target="iana-action-types"/>),
      and <xref target="appendix-action-types-reference-only"/>, the entries
      that IANA is not asked to register. Each entry is one line with the
      action type, the status, and, for a deprecated type, "successor" and
      the type that its superseded_by member names, followed by an
      indented line with the 64
      hexadecimal digits that follow "sha256:" in its definition_sha256
      (<xref target="definition-digest"/>). The definition of each entry is
      the entry with the same name in the registry file;
      <xref target="tool-call-type"/> reproduces the tool.call.1 entry
      member for member.</t>
      <section anchor="appendix-action-types-initial">
        <name>Initial IANA Entries</name>
        <t>These 54 entries, 45 active and 9 deprecated, are the initial
        contents of the CAID Action Types registry.</t>
<dl anchor="appendix-d1-types" newline="true" spacing="compact">
  <dt>payment.release.1 active</dt>
  <dd><tt>3a5ad4c0a3a8dbf7eb9ea5f4c3b2ceb07ba1972fac49acc6006dcac64726ff12</tt></dd>
  <dt>payment.refund.1 deprecated, successor payment.refund.2</dt>
  <dd><tt>4fd20a272ef42f027c832b3cab3500219d695f2516e030a1d9cb1c1402a17df3</tt></dd>
  <dt>payment.refund.2 active</dt>
  <dd><tt>9421a7b0166e9c4e69aa1d166c779b93cff1236ae4940ee883d75cb45d2bdb50</tt></dd>
  <dt>payout.batch.execute.1 active</dt>
  <dd><tt>f717a2a675fc94abf61cad351a6e7698da335b8bce18ece4f904cb3f3d873c3b</tt></dd>
  <dt>wire.transfer.1 active</dt>
  <dd><tt>29ae2cafd17694e2ca65096bfc7cbd86c8c309082e7e9fc8cf92b67928fdfef2</tt></dd>
  <dt>ach.debit.originate.1 deprecated, successor ach.debit.originate.2</dt>
  <dd><tt>b3875a1ee1855fd8ab9a8481578af72f13e151a8297c283ec3a68ea9c482b4ee</tt></dd>
  <dt>ach.debit.originate.2 active</dt>
  <dd><tt>2ac0e6c6cbd6c8c0acc5ac4b71f9aaeb0adb9ed7511b5b7d0bf11b90425b7aba</tt></dd>
  <dt>iam.role.grant.1 active</dt>
  <dd><tt>24950ca02a77db28221df4f2e2bb81b20162ac9c7f8c5cc75db306374606509a</tt></dd>
  <dt>iam.role.revoke.1 active</dt>
  <dd><tt>7ed8339092856720580669a5e2692cb4350f37ddafd97afad51672043e2163ea</tt></dd>
  <dt>iam.user.delete.1 active</dt>
  <dd><tt>f5365e3dc46b2a04b9e804d5921b5debc129a9eee0d1b916679fdf9232ce068f</tt></dd>
  <dt>key.create.1 deprecated, successor key.create.2</dt>
  <dd><tt>739b77a1dbf3fd164f2ed047368bd8cdc55757c3a840db9140f43dc923111778</tt></dd>
  <dt>key.create.2 active</dt>
  <dd><tt>a6fcdb0e1644ad65449ba2bfe48baea60cd97f8ed1063f15fb5510b1affe1c5c</tt></dd>
  <dt>key.delete.1 active</dt>
  <dd><tt>2840d845e32c5f09b3ba2a2b952a2ef495a2f28180a23e33bacf39a6d37ba3cd</tt></dd>
  <dt>key.rotate.1 deprecated, successor key.rotate.2</dt>
  <dd><tt>f2c43de398bc9d1bd62554f867fdec194cb07bb241415d6dc8165f860a32725d</tt></dd>
  <dt>key.rotate.2 active</dt>
  <dd><tt>d0aa8847da551efe214d27c3e5fe0a341654b8682b0dc03e30c64242142a24aa</tt></dd>
  <dt>mfa.disable.1 active</dt>
  <dd><tt>dc15633426de52ba4862948414a50182105ed839cc7c221ca46ac95913b19b8d</tt></dd>
  <dt>dns.record.delete.1 active</dt>
  <dd><tt>0b320a2b0e944df0820439683032e2ce216c6601300d71368cd6cbc2245cc9e4</tt></dd>
  <dt>instance.terminate.1 active</dt>
  <dd><tt>ebb2e0a621a000f7dced69226a60ffc0b034781b412fceb99fc147414de782c4</tt></dd>
  <dt>cluster.delete.1 active</dt>
  <dd><tt>25345b085c2bc02d92eeb5c909ec035d327eef33f0f1b0f56e890a0f26b9be29</tt></dd>
  <dt>firewall.rule.open.1 deprecated, successor firewall.rule.open.2</dt>
  <dd><tt>4a768f2ed30354b053c40f3b6ca0bfdd4dc29d78fc5b6d5558f8f6970e890e8a</tt></dd>
  <dt>firewall.rule.open.2 active</dt>
  <dd><tt>254b72b169a6675fed28ff2e5da97a10cb0332965ab222deccd3c48ffa8d2f74</tt></dd>
  <dt>storage.bucket.public.1 active</dt>
  <dd><tt>fab030e96ff68a3ccf2b9ce53a732ed95d8c2053d95f1a826b8da19a8b9e8aa1</tt></dd>
  <dt>dataset.delete.1 active</dt>
  <dd><tt>1caf662180cbfc278f9d8d4549481b22198ea77d72243bef0accebc48663f0bf</tt></dd>
  <dt>backup.delete.1 active</dt>
  <dd><tt>4cd79cec67565c65f7c99e14fc3b36a6ac18a352a9bf7d9f9475bd300f0b5d15</tt></dd>
  <dt>retention.policy.override.1 active</dt>
  <dd><tt>cbc581e8642f85425b300bef9c83c7ed86b04b998aaf0b62d72ebc2d3fbed508</tt></dd>
  <dt>pii.export.1 deprecated, successor pii.export.2</dt>
  <dd><tt>842fd0e6d0f7c7ec168e6c29fa992230dea8da1dcb8295e4b56e044eea6e1648</tt></dd>
  <dt>pii.export.2 active</dt>
  <dd><tt>fbef9a2810f87e8df07c84c0a71964f4f4606408df59a5d302dc22ca70556075</tt></dd>
  <dt>email.send.external.1 active</dt>
  <dd><tt>04c79261361a0db6caf4a2c69a19a3b9d19a39c5df7e3fb7ace8d29fe100d589</tt></dd>
  <dt>announcement.publish.1 active</dt>
  <dd><tt>ed2f14b052e7ac7ba84c58391cf360176a8084b37cca55cd86faba4f2c551890</tt></dd>
  <dt>social.post.publish.1 active</dt>
  <dd><tt>f56db5382d2a7ca5a7640664408778c1b6b4da8a632978a6337872ab08a16459</tt></dd>
  <dt>press.release.distribute.1 active</dt>
  <dd><tt>33b97769d9edbad183d13907468dbfaa85010629c305aaa70d8c0dc44814557a</tt></dd>
  <dt>package.publish.1 active</dt>
  <dd><tt>31af7ddad65e14e9b5577e812934db3098fe8c23e53468e3ac0476aac110818b</tt></dd>
  <dt>release.deploy.prod.1 active</dt>
  <dd><tt>103c8410093d6b0d15994a65e2cc3afbb725fc5c1db229178c743019a1448de7</tt></dd>
  <dt>secret.rotate.1 active</dt>
  <dd><tt>5244e9721e4d97321bc45e2512860949092a650de0693f6ef48d11bf4704e527</tt></dd>
  <dt>repo.delete.1 active</dt>
  <dd><tt>8a18c77f7a211bfc64e64014d9f3ee8ab6122406d440a26ad180f7820baafb1f</tt></dd>
  <dt>branch.protection.disable.1 active</dt>
  <dd><tt>6b0cf385a056e763c9a1a705ef96267af9c854ec0498e9e0828258a6daeb94a9</tt></dd>
  <dt>order.place.1 active</dt>
  <dd><tt>7ba6606177cad27ac3d12ac7875cf2b52e653229ccc3890097eb24129d0cac81</tt></dd>
  <dt>subscription.cancel.1 active</dt>
  <dd><tt>7ed8974c8f020de6aa6da1984f86a7feacbf4dcf4a859e170144d6143971e192</tt></dd>
  <dt>refund.issue.1 active</dt>
  <dd><tt>f5819f5e049731f3490d8a3d0a19b4079ebc629c8370cc51e16095da9a3d506c</tt></dd>
  <dt>listing.delist.1 active</dt>
  <dd><tt>8b14243a3c9cf02f6d92a4d725be08fd38f12e74be91c60a60291eb507aa4c73</tt></dd>
  <dt>contract.execute.1 active</dt>
  <dd><tt>468e056e3c1b3993af7cf0da05b7ab2c098421b25d631a792ac112ddb52fa250</tt></dd>
  <dt>contract.execute.2 active</dt>
  <dd><tt>d1f43cb28204cae2d330abb9a51a8e7934a966c15eea10695149f904083b4dbc</tt></dd>
  <dt>regulatory.filing.submit.1 active</dt>
  <dd><tt>4b57279dd56a3007fda65844f90c4ffd5271a884685f37c485154f00b1a16a73</tt></dd>
  <dt>legal.hold.release.1 active</dt>
  <dd><tt>9e8f90820e84ea12a51dac9ba678a66df2aaba3b64e1f77f53c14a1568cf0c0c</tt></dd>
  <dt>rx.dispense.1 deprecated, successor rx.dispense.2</dt>
  <dd><tt>54d81e6db3cb38b0e5b8a53d476100558f4c211a074c2543423eb6cde38338f7</tt></dd>
  <dt>rx.dispense.2 active</dt>
  <dd><tt>943609964f09155f5509b045c23a7a0dc1003aec09f2d3b833cdf4fdabb79012</tt></dd>
  <dt>prior.auth.approve.1 deprecated, successor prior.auth.approve.2</dt>
  <dd><tt>7b1f54c3dde91b1c7faa656859021a775e27f2d36bbe88cf6a1deafe6deb6d76</tt></dd>
  <dt>prior.auth.approve.2 active</dt>
  <dd><tt>c25345a298c9b0ec96d019e4e2bcfd6ddd259ad064a7cb75b581999eaaf10086</tt></dd>
  <dt>phi.disclose.1 deprecated, successor phi.disclose.2</dt>
  <dd><tt>bde03fd967ff8129af1b9ed23a6de6259ecc3dde0ac0a88b7ef06d74f28c8b69</tt></dd>
  <dt>phi.disclose.2 active</dt>
  <dd><tt>23beb6c5da8d75d8443b314ef59fd46459b9d1378d6356fbb721cbf6e985ef80</tt></dd>
  <dt>benefit.disburse.1 active</dt>
  <dd><tt>5b5fbca19b3c59a0fa3594b67f8321ed02b5f1473b2ab739b2359f8de589ef76</tt></dd>
  <dt>invoice.approve.1 active</dt>
  <dd><tt>2a5424eb4ac66ff7bdd1e10473c7c0384e5ea9d1b8645b8f2a022a30e77a05f3</tt></dd>
  <dt>vendor.onboard.1 active</dt>
  <dd><tt>716562ad88964db0c27e99594917e55a624565ccabb051ef293707984fde3dcc</tt></dd>
  <dt>tool.call.1 active</dt>
  <dd><tt>c95e21136fd8b6df646be2957fe42fbf18935add20da6bc9569aa2d1a771afa2</tt></dd>
</dl>
      </section>
      <section anchor="appendix-action-types-reference-only">
        <name>Reference-Registry Entries Not Requested of IANA</name>
        <t>These 8 entries, all active, stay in registry version 5 unchanged
        member for member (their RFC 8785 encodings are identical), so that
        an object valid under registry version 4, which carries them, stays
        valid (<xref target="names"/>), but IANA is not asked to register
        them. emilia.mobile.authorized-action.1 is named
        for a product of the author's organization and is defined by that
        organization's specification. agent.state.export.1,
        agent.state.import.1, agent.state.key-release.1, and
        agent.state.retire-source.1 are defined by another specification of
        the author's organization, science.bio.experiment.execute.1 by
        another Internet-Draft of the author, and travel.cancel-notify.1 by
        an Internet-Draft that the author did not write; this document
        defines none of them. dns.zone.transfer.1 defines a registrar
        transfer of a domain under the Extensible Provisioning Protocol
        <xref target="RFC5730"/>, not a DNS zone transfer
        <xref target="RFC5936"/>, and a registered name is never reassigned.
        Each of the seven types defined by other specifications may be
        registered under Specification Required
        (<xref target="iana-action-types"/>) with its own specification and
        change controller, and the type emilia.mobile.authorized-action.1,
        whose first segment names an organization, only with that
        organization as its change controller. dns.zone.transfer.1 is not to be
        registered: the
        path for the registrar-transfer type is a successor whose name
        describes it.</t>
<dl anchor="appendix-d2-types" newline="true" spacing="compact">
  <dt>dns.zone.transfer.1 active</dt>
  <dd><tt>b83fb16d90f9c61eedb802454b150cd5f2ee841b493935e5adcf2361b9575279</tt></dd>
  <dt>travel.cancel-notify.1 active</dt>
  <dd><tt>1599e98a6409c57ef3d022d586f4eb21bc7821a75f3316e2e6ae2a5e509d39c1</tt></dd>
  <dt>science.bio.experiment.execute.1 active</dt>
  <dd><tt>e80d210c9e009a1e1e1bd6ec4d2afa902d0620ac10eaab51d4e49c25e744a819</tt></dd>
  <dt>emilia.mobile.authorized-action.1 active</dt>
  <dd><tt>a3007f508e4d84e07a7c90a728496a5665f893919f2c7cde25de96c98d50fcb7</tt></dd>
  <dt>agent.state.export.1 active</dt>
  <dd><tt>057c9aee5a661416e510bc620f0bbb6efdf3870a92ca389d535bbf0064b67285</tt></dd>
  <dt>agent.state.import.1 active</dt>
  <dd><tt>e539901b9f14afe604952b0cd071337bb6269ab5d1d11ceee2a1292e46c9ab32</tt></dd>
  <dt>agent.state.key-release.1 active</dt>
  <dd><tt>939f6a2b8ccfb4fed835e6bac211681b7ec51032270761c19b711f349839386f</tt></dd>
  <dt>agent.state.retire-source.1 active</dt>
  <dd><tt>d95b4a14ab5b7989bbc0d0047acf564648b381e1f48e0cc1411d8d911018a365</tt></dd>
</dl>
      </section>
    </section>
    <section anchor="acknowledgments" numbered="false">
      <name>Acknowledgments</name>
      <t>The separation between cryptographic validity and authority in
      this document was sharpened by review from Eric Rescorla. Linda
      Dunbar's cross-administrative-domain Agent Gateway scenarios
      motivated the requirement for a reproducible action join across
      operator boundaries. Chris Hood's work on agent transport and
      composition helped expose the need to keep action identity
      independent from any one authorization artifact. These
      discussions also benefited from A. Thallapelly's OASNT-CAID profile
      and its explicit treatment of profile-local identifier comparison.
      These
      acknowledgments do not imply endorsement of this document.</t>
    </section>
  </back>
</rfc>
