<?xml version="1.0" encoding="UTF-8"?>
<rfc xmlns:xi="http://www.w3.org/2001/XInclude" category="std" docName="draft-hamr-oauth-agent-delegation-01" ipr="trust200902" submissionType="IETF" consensus="true" version="3">
  <front>
    <title abbrev="Agent Delegation Profile">An Attenuated Delegation Profile for Automated Agents</title>
    <seriesInfo name="Internet-Draft" value="draft-hamr-oauth-agent-delegation-01"/>
    <author initials="A." surname="Hassan" fullname="Amr Hassan">
      <organization>Independent</organization>
      <address>
        <postal>
          <city>San Francisco</city>
          <region>California</region>
          <country>United States of America</country>
        </postal>
        <email>avoidaccess@msn.com</email>
      </address>
    </author>
    <date/>
    <area>Security</area>
    <workgroup>Web Authorization Protocol</workgroup>
    <keyword>OAuth</keyword>
    <keyword>agent</keyword>
    <keyword>delegation</keyword>
    <keyword>attestation</keyword>
    <keyword>attenuation</keyword>
    <keyword>authorization</keyword>
    <abstract>
      <t>
        This document specifies a profile for delegating authorization to
        automated agents across administrative domains. It defines an
        HTTP header field, Agent-Delegation, that carries a chain of
        attenuated delegation links. Each link narrows the scope, tightens
        or holds a set of floor conditions, and shortens or holds the
        expiry of its parent. A verifier checks every link in the chain,
        not only the last, and rejects the chain if any link violates
        attenuation. The profile is deliberately agnostic to the
        credential format and to the nature of the entity that issues
        floor attestations; it specifies required properties, not a
        specific encoding or a specific kind of issuer. It composes with,
        and does not replace, existing work on agent credential
        provisioning and posture.
      </t>
    </abstract>
  </front>
  <middle>

    <section anchor="introduction" numbered="true" toc="default">
      <name>Introduction</name>
      <t>
        A person asks an automated agent to arrange a car rental. That
        agent does not do the work itself: it engages a second,
        specialized agent operated by a different company, and that
        second agent calls the rental service's API. The rental service
        now receives a request from software that no human has ever
        spoken to, two hops removed from the person who authorized
        anything, and operated by an organization the person has no
        relationship with.
      </t>
      <t>
        The rental service needs three things it cannot currently get:
        proof that the authority behind the request actually came from
        that person; assurance that nothing along the way granted itself
        more than it was given; and the ability to check both without
        calling back to any of the parties involved.
      </t>
      <t>
        Automated agents increasingly act as principals against network
        and application APIs on behalf of a human or an organization.
        Where such an agent's authorization is delegated from a human
        principal, and potentially re-delegated agent-to-agent across
        administrative domains, three properties are needed that existing
        OAuth mechanisms do not by themselves guarantee end to end: that
        each re-delegation can only narrow what came before it, that a
        verifier can check the entire chain rather than trusting the last
        hop, and that the conditions under which a delegation was granted
        travel with it in a form a verifier can check offline.
      </t>
      <t>
        This document specifies a profile that supplies those three
        properties. It does not define a new credential format, a new
        signature scheme, or a new agent identity system. It defines:
      </t>
      <t>
        an HTTP header field for carrying a delegation chain
        (<xref target="header"/>); a closed set of attenuation rules that
        every link in the chain must satisfy relative to its parent
        (<xref target="attenuation"/>); the required properties of a
        floor attestation, independent of its encoding
        (<xref target="attestation"/>); an ordered verification
        procedure a verifier MUST follow (<xref target="verification"/>);
        and a profile of the RFC 9421 signature parameters
        (<xref target="rfc9421-profile"/>).
      </t>
      <t>
        The profile is a composition layer. It assumes an underlying
        attestation issuer exists somewhere in the deployment and that a
        trust source can resolve that issuer's key; it says nothing about
        who or what that issuer is. <xref target="appendix-a"/> gives one
        concrete, non-normative instantiation to make the abstract
        properties concrete for a reader evaluating deployability; nothing
        in that appendix is required to implement this profile.
      </t>
    </section>

    <section anchor="conventions" numbered="true" toc="default">
      <name>Conventions and Terminology</name>
      <t>
        The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL
        NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED",
        "MAY", and "OPTIONAL" 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>
        This document defines the following terms:
      </t>
      <dl newline="false" spacing="normal">
        <dt>Attestation Issuer:</dt>
        <dd>
          An entity that can produce a signed, boolean, expiring statement
          about whether a subject satisfies a floor condition, without
          disclosing the underlying value that produced the answer. This
          document treats the Attestation Issuer abstractly; it may be
          any party a deployment trusts to make such a statement.
        </dd>
        <dt>Delegator:</dt>
        <dd>
          The principal that holds a delegation and grants a narrower one
          to the next link in the chain. The first Delegator in a chain
          is the human or organizational principal that originates the
          delegation.
        </dd>
        <dt>Delegate:</dt>
        <dd>
          The principal that receives a delegation link, whether it is an
          automated agent or a sub-agent.
        </dd>
        <dt>Relying Service:</dt>
        <dd>
          The service that receives a request bearing a delegation chain
          and must decide whether to honor it.
        </dd>
        <dt>Resource Owner:</dt>
        <dd>
          The party that owns the resource named by a request's target
          origin and that publishes and signs the declared menu
          (<xref target="declared-menu"/>) governing that origin's
          classSource declared value. A deployment commonly has the
          Resource Owner and the Relying Service be the same operator,
          but this document does not require it; the two are distinct
          roles, and only the Resource Owner's signing key and the
          menu's origin binding are constrained by this document, not
          the roles' organizational identity.
        </dd>
        <dt>Scope:</dt>
        <dd>
          The set of capabilities a link grants, expressed as a set of
          opaque strings. See <xref target="scope"/>.
        </dd>
        <dt>Floor:</dt>
        <dd>
          A named set of conditions a subject must satisfy, expressed as
          axis/value pairs, that a Relying Service or an intermediate
          Delegate requires before it will act. See
          <xref target="floors"/>. Each axis/value pair within that set
          is a constraint; a floor is the aggregate of the constraints
          it carries, at most one per axis.
        </dd>
        <dt>Link:</dt>
        <dd>
          One element of a delegation chain: a scope, a floor, an expiry,
          and the signature that binds them to their issuer and to their
          parent link.
        </dd>
      </dl>
    </section>

    <section anchor="motivation" numbered="true" toc="default">
      <name>Motivation</name>
      <t>
        A delegation chain that is only checked at its endpoint is not a
        chain; it is a single trust decision with extra steps. If an
        intermediate Delegate can widen scope, loosen a floor, or extend
        an expiry beyond what it was itself granted, then the guarantees
        made at the root of the chain do not survive to the Relying
        Service, regardless of how carefully the root delegation was
        constructed. This document's primary technical contribution is to
        make that failure structurally difficult: attenuation is defined
        precisely enough that a verifier can check it mechanically at
        every link, and <xref target="security"/> states plainly that a
        verifier which checks only the final link defeats the entire
        mechanism.
      </t>
      <t>
        A second, related problem is that authorization conditions are
        often expressed as raw attribute values (a date of birth, a
        tenure in days, an account balance) which a Relying Service does
        not need and should not receive. This document requires that
        floor conditions be evaluated by the Attestation Issuer and
        exposed to the chain only as a signed boolean result bound to a
        verifier's nonce and to an expiry, never as the underlying value.
        This is a disclosure-minimization requirement independent of the
        chaining requirement, and both apply together.
      </t>
    </section>

    <section anchor="layers" numbered="true" toc="default">
      <name>Position Among Delegation Layers</name>
      <t>
        This section is informational. It introduces no new requirement
        beyond those stated elsewhere in this document; it exists to
        place this document among neighboring work so a reader does not
        mistake the boundary this document draws for an oversight.
      </t>
      <t>
        Delegated agent authorization, read across the drafts active in
        this space, separates into three distinct layers:
      </t>
      <dl newline="false" spacing="normal">
        <dt>(a) Who may act on whose behalf:</dt>
        <dd>
          the delegation chain and the floor conditions that bound it, as
          it narrows from an originating principal down to the agent
          making a request.
        </dd>
        <dt>(b) What exactly may be done, per invocation:</dt>
        <dd>
          binding a specific action, tool name, or argument set to a
          grant, at the moment the action is about to occur.
        </dd>
        <dt>(c) What happened, once:</dt>
        <dd>
          the receipts and audit evidence that record that a given
          action was authorized, presented, and consumed.
        </dd>
      </dl>
      <t>
        This document occupies layer (a), plus floors. The chain model of
        <xref target="attenuation"/> and the floor axes of
        <xref target="floors"/>, including the extensible registry of
        <xref target="axis-registry"/>, bound the space of what an agent
        could invoke coarsely: an axis such as actionClass or writeBudget
        constrains a category of action or a cumulative budget across an
        entire chain, not the arguments of any single call. A floor is
        evaluated once, when a link is issued or verified, and it does
        not change per invocation.
      </t>
      <t>
        This document does not perform per-call argument binding, and it
        does not produce a receipt. <xref target="RFC9396"/> defines Rich
        Authorization Requests, which bind authorization detail at grant
        time. <xref target="I-D.das-agentic-tool-binding"/> binds a tool
        name and its arguments per call, at the moment a request is
        dispatched, after a model has already chosen what to invoke.
        <xref target="I-D.schrock-ep-authorization-receipts"/> addresses
        layer (c), the recorded evidence that an action occurred. Read
        together, the ordering runs: authorization detail is bound at
        grant time; floors of the kind this document specifies bound the
        space in between as a chain is attenuated hop to hop; and a
        per-call digest is bound after a specific choice has been made,
        with a receipt recording what happened afterward.
      </t>
      <t>
        One structural problem is shared across this layering and is not
        solved by any one layer alone: a parent credential remains valid
        after it has been attenuated into a narrower child, so a holder
        of the parent retains the broader authority the child was only
        ever a narrowing of. This problem sits in the composition
        boundary between layers, not inside any single token profile.
        <xref target="I-D.asor-wimse-agent-delegation-chain"/> Section 9.1
        lists mitigations for it (a short token lifetime, holder binding,
        and status lists). This document shares the same problem and
        offers no token-profile fix for it either; a deployment that
        needs to close it needs a mechanism this document does not
        supply.
      </t>
      <t>
        Implementation experience that informed where this document draws
        its boundary is summarized, non-normatively, in
        <xref target="appendix-a"/>.
      </t>
    </section>

    <section anchor="header" numbered="true" toc="default">
      <name>The Agent-Delegation Header Field</name>
      <t>
        This document defines a new HTTP field, Agent-Delegation, that
        carries a delegation chain from a Delegate to a Relying Service or
        to the next Delegate in the chain. Agent-Delegation is a
        Structured Field <xref target="RFC8941"/>, specifically a List
        whose members are Byte Sequences, each Byte Sequence carrying one
        opaque, encoded delegation link, ordered from the root link
        (index zero) to the leaf link presented by the immediate sender.
      </t>
      <t>
        The internal encoding of each link is determined by the
        credential format in use (<xref target="attestation"/>); this
        document does not mandate one. A verifier MUST be able to parse
        each Byte Sequence member into the fields required by
        <xref target="attenuation"/> and <xref target="attestation"/>
        before it can evaluate the chain.
      </t>
      <t>
        Agent-Delegation is intended to be covered by an RFC 9421
        <xref target="RFC9421"/> HTTP Message Signature applied by the
        immediate sender, binding the header's content to the request it
        accompanies. This document specifies the header field and its
        semantics; it does not define a new signature mechanism, relying
        on RFC 9421 for message-level signing of the request the header
        is attached to.
      </t>
      <t>
        Because Agent-Delegation is visible to any intermediary that can
        read HTTP headers, and is not encrypted by this profile, links
        MUST NOT carry personal data of the Delegator, the Delegate, or
        any subject the floor condition concerns. See
        <xref target="privacy"/>.
      </t>
    </section>

    <section anchor="rfc9421-profile" numbered="true" toc="default">
      <name>Profile of RFC 9421 Signature Parameters</name>
      <t>
        RFC 9421 <xref target="RFC9421"/> Section 2.3 defines a set of
        signature parameters, including <tt>created</tt>, <tt>expires</tt>,
        <tt>nonce</tt>, <tt>alg</tt>, <tt>keyid</tt>, and <tt>tag</tt>.
        This section profiles the use of those parameters for a signature
        applied over a request carrying an Agent-Delegation field; it does
        not define a new signature mechanism.
      </t>
      <t>
        A sender applying this profile MUST include the <tt>keyid</tt>,
        <tt>alg</tt>, <tt>created</tt>, <tt>expires</tt>, and <tt>nonce</tt>
        signature parameters, and MUST include the Agent-Delegation field
        among the signature's covered components.
      </t>
      <t>
        A sender MUST set the <tt>tag</tt> signature parameter to the
        string "agent-delegation", so a verifier can identify signatures
        made under this profile. RFC 9421 defines <tt>tag</tt> as "an
        application-specific tag for the signature as a String value" used
        "to help identify signatures relevant for specific applications or
        protocols," and tag values are application-specific strings
        requiring no registry. RFC 9421 Section 7.2.7 discusses the risk
        of tag collision between unrelated applications; this profile does
        not add any mechanism beyond that discussion.
      </t>
      <t>
        RFC 9421 defines the <tt>expires</tt> parameter, "expiration time
        as a UNIX timestamp value of type Integer," but leaves its
        enforcement to the application. This profile therefore requires
        it: a verifier MUST reject a request whose signature
        <tt>expires</tt> value is earlier than the time of verification.
        This is a requirement this profile adds; RFC 9421 itself does not
        impose it.
      </t>
      <t>
        RFC 9421 Section 7.2.2 describes the <tt>nonce</tt> parameter,
        "a random unique value generated for this signature as a String
        value," as allowing a verifier to detect replay of the signature
        itself, and describes a signer providing a creation timestamp and
        an expiration time to limit the utility of a captured signature
        value. It further states that a verifier wanting to trigger a new
        signature from a signer can send the Accept-Signature header field
        with a new nonce parameter, and that an attacker simply replaying
        a signature would not be able to generate a new signature with the
        chosen nonce value. A verifier under this profile that needs a
        fresh signature bound to a value of its own choosing SHOULD use
        the Accept-Signature header field carrying a <tt>nonce</tt>
        parameter, as described in RFC 9421 Section 7.2.2. This profile
        does not define a separate nonce-delivery mechanism, because
        RFC 9421 already provides one.
      </t>
      <t>
        RFC 9421's <tt>nonce</tt> signature parameter binds one HTTP
        message. The nonce carried inside a floor attestation
        (<xref target="attestation"/>) binds one attestation to one
        verifier's question. These are two distinct nonces at two distinct
        layers, and implementers MUST NOT conflate them.
      </t>
      <t>
        RFC 9421 defines message-level signing and provides no notion of
        delegated authority, sub-principals, or attenuation of scope. The
        chain model of <xref target="attenuation"/> therefore extends
        RFC 9421 rather than restating it.
      </t>
    </section>

    <section anchor="scope" numbered="true" toc="default">
      <name>Scope</name>
      <t>
        A scope is a set of zero or more capability strings. A capability
        string is OPAQUE to this profile: this document defines no
        syntax, no internal structure, and no namespace for it. Any
        structure a deployment gives it, for example a resource:action
        convention, is a deployment convention and MUST NOT be
        interpreted by a verifier implementing this profile.
      </t>
      <t>
        Comparison is by exact set containment over case-sensitive,
        octet-for-octet string equality. A scope S1 is contained in a
        scope S2 if and only if every member of S1 is octet-for-octet
        identical to some member of S2.
      </t>
      <t>
        A verifier MUST NOT apply any of the following when comparing
        scopes, because none is defined by this profile:
      </t>
      <ul spacing="normal">
        <li>wildcard or prefix matching;</li>
        <li>
          hierarchical or namespace containment (a verifier MUST NOT
          treat one capability string as containing another because of
          any shared prefix, separator, or apparent parent/child
          relation);
        </li>
        <li>case folding;</li>
        <li>Unicode normalisation;</li>
        <li>whitespace trimming; or</li>
        <li>any other canonicalisation.</li>
      </ul>
      <t>
        The presented bytes are compared as presented. A verifier that
        applies a matching rule this profile does not define can accept
        a chain another conforming verifier rejects, which makes
        attenuation unverifiable in exactly the way this profile exists
        to prevent.
      </t>
      <t>
        The empty set is a valid scope and is contained in every scope;
        a link granting the empty scope grants no capability and is not,
        by itself, an error.
      </t>
      <t>
        Wildcard, hierarchical, and pattern-based scope semantics are
        OUT OF SCOPE for this version of the profile and are future
        work; they are not defined here.
      </t>
    </section>

    <section anchor="attenuation" numbered="true" toc="default">
      <name>Attenuation Rules</name>
      <t>
        A delegation chain is an ordered sequence of links L(0), L(1), ...,
        L(n), where L(0) is the root delegation and L(n) is the link
        presented to the Relying Service. For every link L(i) with i &gt;
        0, relative to its parent L(i-1), all of the following MUST hold:
      </t>
      <ol spacing="normal" type="1">
        <li>
          <t>
            <strong>Scope containment.</strong> The scope granted by L(i) MUST be a
            subset of the scope granted by L(i-1), per <xref target="scope"/>.
            L(i) MUST NOT name a capability that L(i-1) did not itself hold.
          </t>
        </li>
        <li>
          <t>
            <strong>Floor non-relaxation.</strong> The floor carried by L(i) MUST be
            at least as tight as the floor carried by L(i-1) on every
            axis defined in <xref target="floors"/>. L(i) MUST NOT be
            looser than L(i-1) on any axis, whether by omitting an axis
            L(i-1) constrained, by widening an ordered axis's value, or
            by substituting a different value on an equality axis that
            L(i-1) did not itself permit.
          </t>
        </li>
        <li>
          <t>
            <strong>Expiry non-extension.</strong> The expiry carried by L(i) MUST
            NOT be later than the expiry carried by L(i-1).
          </t>
        </li>
      </ol>
      <t>
        These three rules apply to every link in the chain, not only to
        the leaf link. A verifier MUST validate rules 1 through 3 for
        every adjacent pair (L(i-1), L(i)) for i = 1 to n, in addition to
        validating L(0) against the root Attestation Issuer's published
        floor and the Delegator's own authority. A verifier MUST reject
        the entire chain if any single link violates any single rule; a
        partial acceptance of a chain up to the point of violation is not
        conforming.
      </t>
      <t>
        A verifier MUST support a configurable maximum chain depth and
        MUST reject a chain whose length exceeds that configured maximum,
        prior to evaluating any link's content. This bounds the
        verification cost of a chain and limits the depth to which
        authorization can be re-delegated across administrative domains
        in a single deployment.
      </t>
      <t>
        Widening a scope, a floor, or an expiry beyond what a chain
        currently carries is out of scope for this profile. Where a
        deployment needs to widen an existing grant, that MUST be
        performed as a distinct, explicit, consent-visible operation
        outside this delegation mechanism, producing a new root
        delegation rather than a modification of an existing chain.
      </t>
    </section>

    <section anchor="floors" numbered="true" toc="default">
      <name>Floor Axes</name>
      <t>
        A floor is a set of axis/value pairs. This document defines a
        closed set of axes for this version of the profile. Extending
        the axis set beyond this closed set is no longer future work as
        of this revision: <xref target="axis-registry"/> defines a
        registry mechanism for it. The closed set defined directly by
        this document is:
      </t>
      <table>
        <thead>
          <tr><th>Axis</th><th>Type</th><th>Comparison</th></tr>
        </thead>
        <tbody>
          <tr><td>subjectClass</td><td>enum</td><td>one_of (singleton)</td></tr>
          <tr><td>tenureMin</td><td>duration</td><td>min</td></tr>
          <tr><td>credentialAgeMin</td><td>duration</td><td>min</td></tr>
          <tr><td>accountClass</td><td>enum</td><td>one_of (singleton)</td></tr>
          <tr><td>partialPolicy</td><td>enum</td><td>one_of (singleton)</td></tr>
        </tbody>
      </table>
      <t>
        An axis name that does not appear in this table MUST cause a
        verifier to reject the floor, and therefore the link that carries
        it, outright. An unknown or misspelled axis name MUST be treated
        as a hard rejection; it MUST NOT be silently ignored or dropped
        from the comparison. This applies equally to a published floor
        and to a requested floor presented in a delegation link.
      </t>
      <t>
        For an enum-typed axis (subjectClass, accountClass,
        partialPolicy), the comparison is equality only; these axes are
        unordered and a value either matches the required value or it
        does not. For a duration-typed axis (tenureMin,
        credentialAgeMin), a larger value is strictly tighter than a
        smaller one.
      </t>
      <section anchor="axis-registry" numbered="true" toc="default">
        <name>Floor Axis Registry</name>
        <t>
          This document establishes a registry of floor axis names,
          the "HAMR Floor Axis Registry" (<xref target="iana"/>). What is
          registered is the axis NAME; a registration does not define new
          comparator semantics of its own. Each registered name is bound
          to exactly one comparator type, drawn from the following closed
          set of four comparators:
        </t>
        <dl newline="false" spacing="normal">
          <dt>min:</dt>
          <dd>
            an ordered value. A min constraint present on the parent
            MUST be present on the child, with the child's value greater
            than or equal to the parent's value: child.min &gt;=
            parent.min. This is the comparator already used, without
            this name, by every duration-typed axis in this section's
            closed set, per <xref target="monotone"/>.
          </dd>
          <dt>max:</dt>
          <dd>
            an ordered value. A max constraint present on the parent
            MUST be present on the child, with the child's value less
            than or equal to the parent's value: child.max &lt;=
            parent.max.
          </dd>
          <dt>rank:</dt>
          <dd>
            a position in a registered, totally ordered value list. A
            rank constraint present on the parent MUST be present on the
            child, with the child's rank less than or equal to the
            parent's rank: child.rank &lt;= parent.rank. Tightening on a
            rank axis therefore means lowering the rank, consistently
            with how this document's proof-of-concept treats an ordered
            axis whose values are r, w, and x with r &lt; w &lt; x, where
            a child link may only lower the value, never raise it.
          </dd>
          <dt>one_of:</dt>
          <dd>
            a set of values. A one_of constraint present on the parent
            MUST be present on the child, with the child's set a
            non-empty subset of the parent's set.
          </dd>
        </dl>
        <t>
          For every comparator in the set above, the constraint is
          non-droppable in the child: where the parent carries a
          constraint on a registered axis, the child MUST also carry a
          constraint on that axis, per the same non-relaxation-by-
          omission rule <xref target="attenuation"/> already states for
          rule 2. An axis name that is not registered, or a registration
          that names a comparator outside the closed set of four above,
          MUST be rejected by a verifier. This extends, to comparators,
          the same hard-rejection rule this section already states for
          an unregistered axis name: neither an unknown axis name nor an
          unknown comparator is ever silently ignored or dropped from the
          comparison.
        </t>
        <t>
          A registration in the HAMR Floor Axis Registry carries the
          following five fields:
        </t>
        <ol spacing="normal" type="1">
          <li><t><strong>Name.</strong> The axis name, an opaque
            registered string.</t></li>
          <li><t><strong>Comparator.</strong> Exactly one of min, max,
            rank, or one_of, as defined above.</t></li>
          <li><t><strong>Value domain.</strong> The set or type of
            values the axis may carry (for example, the duration grammar
            of <xref target="duration-grammar"/>, a non-negative
            integer, or a registered ordered value list).</t></li>
          <li><t><strong>Tightening direction.</strong> Which change to
            a value on this axis counts as tightening, per the
            comparator's definition above.</t></li>
          <li><t><strong>Omitted-axis rule.</strong> Two distinct cases
            apply, and this field states both rather than one. First,
            link-to-link within a chain: where the parent link L(i-1)
            carries a constraint on a registered axis and the child link
            L(i) omits it, that omission is non-relaxation-by-omission
            and the chain MUST be rejected, per rule 2 of
            <xref target="attenuation"/>. Second, link-to-published-floor:
            where no link in the chain up to and including the link under
            evaluation carries a constraint on a registered axis, the
            issuer's published floor for that axis applies unchanged.
            <tt>effective</tt> names the verifier's evaluated outcome for
            an axis under this second case; how, or whether, a verifier
            conveys that outcome to a caller is out of scope for this
            document. The second case is inheritance, not relaxation, and
            it is not a restatement of the first.</t></li>
        </ol>
        <t>
          The initial contents of the registry, established by this
          document, are:
        </t>
        <table>
          <thead>
            <tr><th>Name</th><th>Comparator</th><th>Value domain</th><th>Notes</th></tr>
          </thead>
          <tbody>
            <tr><td>subjectClass</td><td>one_of</td><td>exactly one value from the closed set <xref target="floors"/> already defines for it, encoded as the bare value (a singleton set in one_of terms)</td><td>tightening from a singleton is identity only; behaviour identical to -00's equality-only rule</td></tr>
            <tr><td>tenureMin</td><td>min</td><td>duration, <xref target="duration-grammar"/></td><td>larger is tighter</td></tr>
            <tr><td>credentialAgeMin</td><td>min</td><td>duration, <xref target="duration-grammar"/></td><td>larger is tighter</td></tr>
            <tr><td>accountClass</td><td>one_of</td><td>same singleton rule as subjectClass</td><td>same note</td></tr>
            <tr><td>partialPolicy</td><td>one_of</td><td>same singleton rule as subjectClass</td><td>same note</td></tr>
            <tr><td>actionClass</td><td>rank</td><td>ordered set r &lt; w &lt; x</td><td>semantics specified in <xref target="action-class"/></td></tr>
            <tr><td>classSource</td><td>rank</td><td>ordered set method &lt; declared</td><td>semantics specified in <xref target="action-class"/></td></tr>
            <tr><td>writeBudget</td><td>max</td><td>non-negative integer, cumulative per chain</td><td>semantics specified in <xref target="write-budget"/></td></tr>
          </tbody>
        </table>
        <t>
          For the three enum-typed axes (subjectClass, accountClass,
          partialPolicy), a multi-valued (set) encoding is out of scope
          for this revision; registering them as one_of records the
          comparator their equality-only rule already is, and changes
          nothing on the wire.
        </t>
        <t>
          The semantics of writeBudget, including the distinction between
          the limit carried in the chain and the count a verifier holds,
          and the derivation of the chain identifier that count is keyed
          by, are specified in <xref target="write-budget"/>. The
          semantics of actionClass and classSource, and the method by
          which each is assigned to a request, are specified in
          <xref target="action-class"/>.
        </t>
      </section>
      <section anchor="duration-grammar" numbered="true" toc="default">
        <name>Duration Grammar</name>
        <t>
          A duration-typed axis value MUST match exactly one of the two
          forms P&lt;n&gt;D or P&lt;n&gt;Y, where &lt;n&gt; is a
          non-negative integer. The integer &lt;n&gt; MUST be in the
          range 0 to 2^53 - 1 inclusive, and a value outside that range
          MUST be rejected. No other ISO 8601 duration form is accepted.
          In particular, a duration expressed in months MUST be
          rejected, because a month is a calendar-dependent unit and its
          length in days is ambiguous; accepting it would make the
          tightening comparison in <xref target="monotone"/> ill-defined.
          For the purpose of comparison, 1Y is defined as exactly 365D. A
          value that falls outside the permitted range, or that does not
          match either form, MUST be rejected.
        </t>
      </section>
      <section anchor="monotone" numbered="true" toc="default">
        <name>Monotone Tightening</name>
        <t>
          On every ordered (duration-typed) axis, a requested floor value
          MUST be greater than or equal to the corresponding published or
          parent floor value. If it is not, the request MUST be refused.
          Widening a floor value on an ordered axis MUST NOT occur
          implicitly as a side effect of any operation defined by this
          profile. As stated in <xref target="attenuation"/>, any
          widening is a distinct, explicit, consent-visible operation
          outside this profile's scope.
        </t>
      </section>
    </section>

    <section anchor="action-class" numbered="true" toc="default">
      <name>Action Class Floors</name>
      <t>
        This section specifies the semantics of the actionClass and
        classSource axes registered in <xref target="axis-registry"/>. It
        answers two separate questions: what is the maximum class of
        operation a delegation link permits (actionClass), and where a
        verifier is permitted to obtain a given request's class from
        (classSource).
      </t>
      <section anchor="action-class-values" numbered="true" toc="default">
        <name>actionClass</name>
        <t>
          actionClass is an ordered enumeration with three values, r, w,
          and x, ranked r &lt; w &lt; x per the rank comparator of
          <xref target="axis-registry"/>. A link's actionClass value
          states the maximum class of operation the agent presenting that
          link MAY perform; it is not a statement about any single
          operation, but a ceiling on the whole link. The three values
          are:
        </t>
        <dl newline="false" spacing="normal">
          <dt>r:</dt>
          <dd>a read-only operation: one that does not modify state.</dd>
          <dt>w:</dt>
          <dd>
            an idempotent write: an operation that modifies state but
            whose repetition has the same effect as performing it once.
          </dd>
          <dt>x:</dt>
          <dd>
            a consequential, non-idempotent action: an operation whose
            repetition is not guaranteed to have the same effect as
            performing it once.
          </dd>
        </dl>
        <t>
          Per the rank comparator, a child link's actionClass rank MUST
          be less than or equal to its parent's: a child link MUST NOT
          carry a higher actionClass value than its parent, and
          tightening on this axis means lowering the value (x to w, w to
          r, or x to r).
        </t>
      </section>
      <section anchor="class-source" numbered="true" toc="default">
        <name>classSource</name>
        <t>
          classSource is an ordered enumeration with two values, ranked
          method &lt; declared per the rank comparator of
          <xref target="axis-registry"/>, naming where a verifier is
          permitted to obtain a request's actionClass. Where no link in
          the chain constrains classSource, an omitting link's default
          value is method, per the link-to-published-floor case of the
          omitted-axis rule of <xref target="axis-registry"/>; method is
          also the lower-ranked, tighter value of the two, so the default
          and the tightest value coincide. Where a parent link does
          constrain classSource, a child link's omission of it is instead
          the link-to-link case of that same rule, and the chain MUST be
          rejected rather than defaulted.
        </t>
        <dl newline="false" spacing="normal">
          <dt>method:</dt>
          <dd>
            the verifier classifies a request from its HTTP method alone,
            per <xref target="classification"/>, and does not consult a
            menu.
          </dd>
          <dt>declared:</dt>
          <dd>
            the verifier additionally consults the Resource Owner's
            signed menu (<xref target="declared-menu"/>) and, where that
            menu verifies and names the operation, uses the menu's
            declared value in place of the method default.
          </dd>
        </dl>
        <t>
          method never extends trust to a value asserted by a party other
          than the verifier itself, while declared extends that trust to
          whatever the Resource Owner's menu asserts; method is
          therefore the tighter of the two values, and is ranked lower
          per <xref target="axis-registry"/>'s ordered set method &lt;
          declared. Per the rank comparator, a child link's classSource
          rank MUST be less than or equal to its parent's: a parent that
          carries method MUST NOT be followed by a child that carries
          declared, and the only permitted change on this axis is from
          declared down to method. This is the same comparator, applied
          in the same direction, as the actionClass axis of
          <xref target="action-class-values"/>: on both rank axes,
          tightening lowers the value, with no per-axis exception.
        </t>
        <t>
          The proof-of-concept accompanying this document names these
          same two values in the opposite written order internally
          (declared before method in a source-code table), with
          identical admission semantics to this section; a reader
          comparing the code against this text should not read that
          ordering as a disagreement about which value is tighter.
        </t>
      </section>
      <section anchor="classification" numbered="true" toc="default">
        <name>Classification</name>
        <t>
          Where a request's classSource is method, its actionClass is the
          default associated with its HTTP method: GET, HEAD, and OPTIONS
          default to r; PUT and DELETE default to w; POST and PATCH
          default to x. This default tracks the safe and idempotent
          method properties defined by <xref target="RFC9110"/>: GET,
          HEAD, and OPTIONS are safe methods, and PUT and DELETE are
          idempotent methods, in the terms <xref target="RFC9110"/> uses;
          POST and PATCH are neither.
        </t>
        <t>
          Where a request's classSource is declared, its actionClass is
          the value the Resource Owner's menu declares for that
          operation, provided the menu verifies per
          <xref target="declared-menu"/> and names the operation. On any
          failure of the menu: the menu is absent, its signature does
          not verify, the verifier has no key for the claimed owner, or
          the menu's issuer does not match the request's target as
          required by <xref target="declared-menu"/>; the verifier MUST
          fall back to the method default given above. A verifier MUST
          NOT compute the greater of, or otherwise combine, the method
          default and a declared value; where a valid, matching menu
          entry exists, the declared value alone governs, replacing the
          method default rather than being compared against it.
        </t>
        <t>
          The absence of any menu at all is a defined state, not a fault
          condition distinct from the failures listed above: it is
          handled identically to a menu that fails to verify, and the
          method default applies. A verifier MUST NOT construct or
          synthesize a menu entry, or a menu, on behalf of a resource
          owner that has not published one.
        </t>
      </section>
      <section anchor="declared-menu" numbered="true" toc="default">
        <name>The Declared Menu</name>
        <t>
          A declared menu is a JSON Web Signature (JWS)
          <xref target="RFC7515"/> whose payload is a JSON object with
          two members:
        </t>
        <dl newline="false" spacing="normal">
          <dt>iss:</dt>
          <dd>
            a string carrying the origin of the resource the menu
            applies to, serialized per <xref target="RFC6454"/>.
          </dd>
          <dt>menu:</dt>
          <dd>
            a JSON object mapping an operation key to an actionClass
            value (r, w, or x). An operation key has the form "METHOD
            path-template", an HTTP method in upper case, one space, and
            a path using OpenAPI path-template syntax, in which a
            brace-delimited segment such as {callId} stands for exactly
            one path segment supplied at request time.
          </dd>
        </dl>
        <t>
          A verifier matches a concrete request against the operation
          keys of a menu by the following rule, applied deterministically
          and without exception: the request's method matches the key's
          method exactly; the request's path and the key's path-template
          are split into slash-separated segments and are considered a
          match only where both have the same number of segments and,
          for every segment position, either the template segment is a
          literal that equals the request's segment exactly, or the
          template segment is a brace-delimited parameter that matches
          any single non-empty request segment. Where more than one
          operation key matches the same request under this rule, the key
          with the greater number of literal (non-parameter) segments
          governs. A menu MUST NOT contain two operation keys under the
          same method whose templates both match the same concrete
          request path with an equal number of literal segments; a
          verifier that encounters such a tie MUST treat the lookup as a
          miss rather than choosing between the tied keys by any other
          means, such as the order the keys happen to appear in the
          menu's JSON serialization. Where no operation key matches,
          including where the only matches available are tied in this
          way, the menu is treated, for that request, the same as a menu
          that does not name the operation, per
          <xref target="classification"/>, and the method default
          applies.
        </t>
        <t>
          A menu applies only to the resource that issued it. The menu's
          iss value is compared, octet-for-octet after serialization per
          <xref target="RFC6454"/>, against the origin of the request
          target; where the two do not match, the menu fails, exactly as
          if its signature had not verified, and the verifier MUST fall
          back to the method default. A verifier MUST NOT accept a menu
          whose iss value does not match the request target's origin,
          regardless of whether the menu's signature is otherwise valid.
        </t>
        <t>
          A menu MUST be verified against the Resource Owner's public
          key, obtained out of band or from a configured trust source; a
          verifier MUST NOT obtain that key from the menu itself,
          following the same rule <xref target="verification"/> already
          states for the root attestation's key. The menu's signature
          algorithm is EdDSA, using the Ed25519 curve; this document
          defines no algorithm negotiation or agility for the menu, and a
          menu using any other algorithm does not verify.
        </t>
      </section>
      <section anchor="menu-publication" numbered="true" toc="default">
        <name>Publication</name>
        <t>
          This section is non-normative. A Resource Owner may publish its
          menu through its API description; one way to do so is a
          per-operation extension in an OpenAPI document, accompanied by
          a detached JWS at a well-known location. The format of such a
          publication mechanism is out of scope for this document.
        </t>
      </section>
      <section anchor="action-class-verifier-placement" numbered="true" toc="default">
        <name>Verifier Placement</name>
        <t>
          Classification and admission under this section are performed
          by the verifier at the resource or credential boundary
          described in <xref target="layers"/>, not by any harness or
          orchestration layer upstream of that boundary. A harness that
          coordinates an agent's actions does not itself classify a
          request or admit it against an actionClass floor; an agent that
          declines to attempt an action it believes will be refused does
          not, by that restraint, satisfy this section. Admission is an
          act of the verifier refusing or permitting a request at the
          boundary, not an act of the harness or the agent abiding by a
          floor it was merely told about.
        </t>
      </section>
      <section anchor="action-class-limits" numbered="true" toc="default">
        <name>Limits</name>
        <t>
          The method default of <xref target="classification"/> is a
          reliable floor in one direction and a lossy signal in the
          other: a GET is never admitted as a write or a consequential
          action, but a POST is not always a consequential action either.
          In a survey of the CAMARA API catalogue conducted 2026-09-01
          (292 operations across 60 repositories, recorded in this
          repository's own proof-of-concept data), 57 of 138 POST
          operations are named as reads (retrieve-, check-, verify-, or
          status-prefixed operation identifiers) and are classed x under
          classSource method, notwithstanding their read-shaped names.
        </t>
        <t>
          The same survey's judgement of GET operations, by contrast, was
          templated rather than read per operation, so the absence of any
          GET classed x in that survey rests on a general design
          convention rather than on an individual reading of each GET
          operation; and the cost of the 57 read-named POST operations
          above defaulting to x was not itself reviewed for whether a
          Resource Owner would actually want to declare them down to r.
          Neither limitation is corrected by this document; a deployment
          relying on the survey's numbers should treat them as directional,
          not as an audited count.
        </t>
      </section>
    </section>

    <section anchor="write-budget" numbered="true" toc="default">
      <name>Write Budget</name>
      <t>
        This section specifies the semantics of the writeBudget axis
        registered in <xref target="axis-registry"/>. It answers three
        separate questions: what value a link carries (<xref
        target="write-budget-axis"/>); what a verifier holds as state
        separately from that value, and how a request is admitted against
        the two together (<xref target="write-budget-limit-count"/>); and
        how a verifier derives the identifier that state is keyed by
        (<xref target="write-budget-chain-identifier"/>).
      </t>
      <section anchor="write-budget-axis" numbered="true" toc="default">
        <name>writeBudget</name>
        <t>
          writeBudget is a non-negative integer, compared with the max
          comparator of <xref target="axis-registry"/>: it is the total
          number of w-class or x-class operations, per the actionClass
          values of <xref target="action-class-values"/>, that the chain
          carrying it may have admitted in aggregate. A child link MUST
          NOT carry a writeBudget value greater than its parent's; per the
          max comparator, tightening on this axis means lowering the
          value, and a child that raises it violates rule 2 of
          <xref target="attenuation"/>.
        </t>
        <t>
          Where no link in the chain constrains writeBudget, an omitting
          link inherits the issuer's published floor for writeBudget,
          which is zero unless the issuer's published floor for the
          chain states otherwise; this is the link-to-published-floor
          case of the omitted-axis rule of
          <xref target="axis-registry"/>, and omission is therefore never
          a widening, only ever an inheritance of whatever floor already
          applies. This is the same effective-zero outcome the
          proof-of-concept's own handling of an omitted writeBudget
          already produces. Where a parent link does constrain
          writeBudget, a child link's omission of it is instead the
          link-to-link case of that same rule, and the chain MUST be
          rejected rather than defaulted, per rule 2 of
          <xref target="attenuation"/>.
        </t>
      </section>
      <section anchor="write-budget-limit-count" numbered="true" toc="default">
        <name>Limit and Count</name>
        <t>
          Two distinct quantities are in play, and this document uses
          "limit" and "count" to keep them apart. The LIMIT is the
          writeBudget value carried in the chain, per
          <xref target="write-budget-axis"/>: it rides on the wire, on
          every link that carries the axis, and a verifier reads it the
          same way it reads any other floor value. The COUNT is the
          number already spent against that limit for a given chain; it
          is state the verifier holds, keyed by the chain identifier of
          <xref target="write-budget-chain-identifier"/>, and it is never
          carried in a link. A link MUST NOT be interpreted as carrying
          the count, and a verifier MUST NOT treat any field of a link as
          the count merely because it varies between requests.
        </t>
        <t>
          Admission proceeds as follows. A request classed r, per
          <xref target="classification"/>, never spends against
          writeBudget: it is admitted or refused on the actionClass rule
          of <xref target="action-class-values"/> alone, and the count is
          left unchanged. A request classed w or x is admitted only if
          the remaining count for the chain is at least one, and the
          count MUST be decremented as part of the same admission
          decision that admits the request, with no window in which two
          concurrent requests against the same chain can both observe the
          same remaining count before either decrement is applied; this
          is a requirement on the outcome, not on any particular locking
          or storage mechanism a verifier uses to achieve it. Where the
          remaining count is zero, a request classed w or x MUST be
          rejected, with the same uniform rejection outcome
          <xref target="verification"/> requires for any other failed
          check; the verifier does not disclose the remaining count in
          the rejection. <xref target="binding-not-replay"/>
          is why this count can only ever live in verifier-held state:
          anything carried on the wire can be re-presented, and a count
          that could be re-presented is not a count.
        </t>
      </section>
      <section anchor="write-budget-chain-identifier" numbered="true" toc="default">
        <name>Chain Identifier</name>
        <t>
          The chain identifier that keys the count of
          <xref target="write-budget-limit-count"/> MUST be derived by
          the verifier itself from the chain being verified, and MUST NOT
          be taken from a value the request supplies. A verifier that
          accepts a caller-supplied chain identifier does not conform to
          this section, regardless of what other checks it performs.
        </t>
        <t>
          The chain identifier is the SHA-256 <xref target="RFC6234"/>
          digest of the octet string that is the signature value of
          L(0), the root link of the chain, in whatever encoding that
          signature value is carried on the wire by the credential format
          in use, per <xref target="header"/> and <xref
          target="attestation"/>. This document defines no signature
          encoding of its own and needs none for this purpose: the digest
          is computed over the same exact bytes a verifier already
          extracts, and has already verified, as L(0)'s signature under
          item 1 of <xref target="attestation"/>. This document does not
          otherwise use a hash function; SHA-256 is adopted here as the
          digest for this one purpose.
        </t>
        <t>
          Every link in a chain, from L(0) to L(n), shares the single
          chain identifier derived from L(0)'s signature. A
          re-delegation, which produces a new child link L(i) with its
          own signature, does not change L(0) and therefore does not
          change the chain identifier; re-delegation MUST NOT mint a
          fresh budget, and a verifier MUST NOT derive a chain identifier
          from any link other than L(0).
        </t>
        <t>
          This rule is what case 22 of the proof-of-concept accompanying
          this document, recorded in <xref target="implementation-status"/>,
          now exercises: the code derives the chain identifier itself and
          pins that a caller-supplied identifier field has no effect,
          rather than refilling the budget when one is presented with the
          same chain.
        </t>
      </section>
      <section anchor="write-budget-limits" numbered="true" toc="default">
        <name>Limits</name>
        <t>
          The count of <xref target="write-budget-limit-count"/> is held
          per verifier, not shared across verifiers. Two verifiers
          holding no shared state do not share a count, so a single chain
          presented in parallel to N distinct verifiers can spend up to N
          times its writeBudget limit in aggregate, one full budget at
          each verifier, before any single verifier's own count reaches
          zero. A mechanism for verifiers to share a count is out of
          scope for this document; this limitation is stated here rather
          than hidden.
        </t>
        <t>
          The budget is cumulative per chain, counted across every
          admitted w-class or x-class request regardless of which
          operation each request invokes, and is deliberately not
          allocated per action or per operation: a per-action cap is
          defeated by splitting one action into many smaller ones, each
          within its own separate cap, so this document defines only one
          running count per chain.
        </t>
        <t>
          This document makes no claim about how many real transactions a
          given writeBudget value can accommodate. Economic scarcity is
          not measured here, and no writeBudget size is described in this
          document as practical, sufficient, or adequate for any
          deployment; a deployment choosing a value does so without
          guidance from this document beyond the mechanism itself.
        </t>
      </section>
    </section>

    <section anchor="attestation" numbered="true" toc="default">
      <name>Attestation Properties</name>
      <t>
        This document does not mandate a specific credential format for
        a floor attestation. A JSON Web Token, a CBOR Object Signing and
        Encryption (COSE) structure, or another signed data structure MAY
        be used, provided the resulting object satisfies every property
        in this section. A conforming attestation, regardless of its
        encoding, MUST:
      </t>
      <ol spacing="normal" type="1">
        <li>
          <t>
            be signed by the Attestation Issuer over the exact bytes
            presented to the verifier. A verifier MUST verify the
            signature over those exact bytes and MUST NOT re-serialize
            the object before or in place of that verification;
          </t>
        </li>
        <li>
          <t>
            carry the verifier's nonce, echoed back exactly as the
            verifier supplied it;
          </t>
        </li>
        <li>
          <t>
            carry an expiry. A missing expiry, or an expiry that is not a
            well-formed numeric timestamp, MUST be treated by the
            verifier as already expired; it MUST NOT be treated as "no
            deadline";
          </t>
        </li>
        <li>
          <t>
            carry a boolean result of the floor evaluation and MUST NOT
            carry the underlying value that produced that result. An
            attestation that discloses a raw date of birth, a raw tenure
            count, a raw account balance, or any other unrounded
            attribute in place of, or in addition to, the boolean result
            does not conform to this profile;
          </t>
        </li>
        <li>
          <t>
            be rejected by the verifier if its serialization contains a
            duplicate top-level key. A parser that resolves duplicate
            keys by a first-wins or last-wins rule is exposed to an
            ambiguity where the issuer and the verifier can disagree
            about which value was signed; this profile closes that
            ambiguity by requiring detection and rejection rather than a
            resolution rule.
          </t>
        </li>
      </ol>
      <section anchor="refusal" numbered="true" toc="default">
        <name>Signed Refusal</name>
        <t>
          Where an Attestation Issuer declines to attest that a subject
          meets a floor, it MUST return a signed refusal rather than
          silence, an unsigned error, or a bare protocol-level failure. A
          signed refusal MUST itself be signed by the Attestation Issuer,
          MUST carry the same nonce the verifier supplied for the
          corresponding request, and MUST carry an expiry, using the same
          rules as an accepted attestation. This prevents a refusal from
          being forged in the Attestation Issuer's name and prevents a
          genuine refusal from being stripped from the response without
          detection.
        </t>
        <t>
          A verifier MUST verify a signed refusal along a verification
          path independent of the path used to verify an accepted
          attestation, so that a defect in one path does not silently
          admit a forged instance of the other.
        </t>
      </section>
      <section anchor="binding-not-replay" numbered="true" toc="default">
        <name>Nonce Binding Is Not Replay Protection</name>
        <t>
          Echoing the verifier's nonce in a signed attestation or refusal
          binds that response to the specific request that carried the
          nonce; it does not, by itself, prevent that same response from
          being presented again. The same response, re-presented against
          the same expected nonce, verifies again for as long as the
          response's own expiry has not passed. Preventing such a
          replay (for example, by tracking nonces already consumed within
          their validity window) is a separate responsibility that falls
          to the verifier and is outside the scope of this document. This
          document does not claim that nonce binding, by itself, provides
          replay protection, and implementers MUST NOT assume that it
          does.
        </t>
      </section>
    </section>

    <section anchor="agent-identifier" numbered="true" toc="default">
      <name>Agent Identifier</name>
      <t>
        A Delegate that presents a delegation chain is identified to a
        Relying Service by an identifier whose only required property, in
        this profile, is: the identifier MUST be unlinkable across
        distinct Relying Services and MUST remain stable across separate
        interactions with the same Relying Service. This document does
        not specify how such an identifier is derived, what inputs
        contribute to it, its length, or its encoding; those are
        deployment choices left to the entity that issues or constructs
        the identifier.
      </t>
      <t>
        <xref target="appendix-b"/> records that this unlinkability
        requirement pulls in a different direction from a stability
        requirement found in related work, and treats that tension as an
        open, unresolved item rather than as settled by this document.
      </t>
    </section>

    <section anchor="verification" numbered="true" toc="default">
      <name>Verification Procedure</name>
      <t>
        A verifier processing a request that carries an Agent-Delegation
        field MUST perform the following steps, in the order given. A
        failure at any step MUST produce one uniform rejection outcome,
        indistinguishable from the outcome of a failure at any other
        step, so that the specific reason for rejection does not become
        available to an unauthenticated party as an oracle (see
        <xref target="security"/>).
      </t>
      <ol spacing="normal" type="1">
        <li><t>Parse the Agent-Delegation Structured Field List into its ordered member links.</t></li>
        <li><t>Compare the number of links against the verifier's configured maximum chain depth; reject if the chain exceeds it.</t></li>
        <li><t>Verify the RFC 9421 HTTP Message Signature applied by the immediate sender over the request, including the Agent-Delegation field among its covered components, per the profile of <xref target="rfc9421-profile"/>.</t></li>
        <li><t>Verify each link's own signature, per <xref target="attestation"/>, over its exact presented bytes.</t></li>
        <li><t>Verify the root attestation, L(0), against the Attestation Issuer's public key, where that key is obtained from a configured trust source and MUST NOT be obtained from the message itself.</t></li>
        <li><t>Verify the three attenuation rules of <xref target="attenuation"/> for every adjacent pair of links in the chain.</t></li>
        <li><t>Verify that every floor attestation carried by the chain echoes, exactly, the nonce the verifier issued for this exchange, and reject if any does not.</t></li>
        <li><t>Verify that no link in the chain has an expiry that has passed, evaluated at the time of verification.</t></li>
        <li><t>Classify the request's actionClass per <xref target="classification"/>, consulting the declared menu of <xref target="declared-menu"/> where the chain's classSource is declared, and admit or refuse the request against the writeBudget ledger of <xref target="write-budget"/>; per <xref target="action-class-verifier-placement"/>, this step is performed by the verifier at the resource or credential boundary, not by an upstream harness or orchestration layer.</t></li>
        <li><t>Only after every preceding step has succeeded, apply the Relying Service's authorization policy to the resulting, fully verified chain.</t></li>
      </ol>
      <t>
        A verifier that implements only a subset of these steps, or that
        implements them out of order such that a later step's success can
        mask an earlier step's failure, does not conform to this profile.
      </t>
    </section>

    <section anchor="example" numbered="true" toc="default">
      <name>A Worked Example</name>
      <t>
        This section is non-normative. It illustrates the rules of the
        preceding sections using a single chain that is built and then
        verified; where it appears to conflict with a normative section,
        the normative section governs.
      </t>
      <t>
        Recall the scenario from <xref target="introduction"/>: a person
        asks an automated agent to arrange a car rental. The parties in
        this example are the person, who is the root Delegator; Agent A,
        a general assistant; Agent B, a specialized booking agent operated
        by a different company; and the rental service, which is both the
        Relying Service and the verifier.
      </t>
      <t>
        Link L(0) is the root delegation, created on the person's device:
      </t>
      <table>
        <thead>
          <tr><th>Field</th><th>Value</th></tr>
        </thead>
        <tbody>
          <tr><td>scope</td><td>booking:read, booking:create, payment:authorize</td></tr>
          <tr><td>floor: subjectClass</td><td>interactive</td></tr>
          <tr><td>floor: tenureMin</td><td>P2Y</td></tr>
          <tr><td>floor: credentialAgeMin</td><td>P90D</td></tr>
          <tr><td>expiry</td><td>2026-11-01T12:00:00Z</td></tr>
        </tbody>
      </table>
      <t>
        Link L(1) is Agent A's re-delegation to Agent B:
      </t>
      <table>
        <thead>
          <tr><th>Field</th><th>Value</th></tr>
        </thead>
        <tbody>
          <tr><td>scope</td><td>booking:read, booking:create</td></tr>
          <tr><td>floor: subjectClass</td><td>interactive</td></tr>
          <tr><td>floor: tenureMin</td><td>P2Y</td></tr>
          <tr><td>floor: credentialAgeMin</td><td>P180D</td></tr>
          <tr><td>expiry</td><td>2026-11-01T11:00:00Z</td></tr>
        </tbody>
      </table>
      <t>
        Agent A drops payment:authorize from the scope it grants to
        Agent B. Dropping a capability is always permitted, because rule 1
        of <xref target="attenuation"/> requires only that the child's
        scope be a subset of the parent's.
      </t>
      <t>
        On the wire, Agent B presents both links to the rental service as
        an Agent-Delegation Structured Field List:
      </t>
      <artwork>
Agent-Delegation: :BASE64-ENCODED-L0:, :BASE64-ENCODED-L1:
      </artwork>
      <t>
        Each member of the list is a Byte Sequence per RFC 8941
        <xref target="RFC8941"/>. The base64 content is elided here for
        readability; the decoded fields are shown in the tables above.
      </t>
      <t>
        The expiry values in the tables above are written in a
        human-readable form for readability only. The on-the-wire
        encoding of a link is determined by the credential format in
        use, as stated in <xref target="header"/>, and this document
        does not mandate one. A link's expiry is distinct from the
        expiry of a floor attestation carried by the chain
        (<xref target="attestation"/>), and both are distinct from the
        RFC 9421 <tt>expires</tt> signature parameter profiled in
        <xref target="rfc9421-profile"/>, which covers the HTTP message
        rather than the delegation.
      </t>
      <t>
        The rental service verifies the chain following
        <xref target="verification"/>. For the adjacent pair (L(0), L(1)),
        the three attenuation rules of <xref target="attenuation"/> are
        checked as follows:
      </t>
      <ul spacing="normal">
        <li><t>Rule 1, scope containment: {booking:read, booking:create} is a subset of {booking:read, booking:create, payment:authorize}. Holds.</t></li>
        <li><t>Rule 2, floor non-relaxation: subjectClass is equal on both links, so the equality axis holds. For tenureMin, P2Y is not less than P2Y, so it holds. For credentialAgeMin, P180D is 180 days and P90D is 90 days; 180 is greater than 90, so L(1) is tighter. Holds.</t></li>
        <li><t>Rule 3, expiry non-extension: 2026-11-01T11:00:00Z is earlier than 2026-11-01T12:00:00Z. Holds.</t></li>
      </ul>
      <t>
        Every link in the chain verifies, so the chain is accepted, and
        the rental service applies its own authorization policy to a
        scope of booking:read and booking:create only. It will not honor
        a payment request on this chain, because no link in it carries
        that capability.
      </t>
      <t>
        Had L(1) instead carried credentialAgeMin="P30D", that value would
        be looser than the parent's P90D, and rule 2 would require the
        verifier to reject the entire chain.
      </t>
    </section>

    <section anchor="privacy" numbered="true" toc="default">
      <name>Privacy Considerations</name>
      <t>
        This profile is built around boolean-only disclosure: a floor
        attestation states whether a subject meets a condition and MUST
        NOT carry the underlying value. This bound holds throughout the
        chain; an intermediate Delegate that re-derives or forwards a raw
        value defeats the disclosure minimization this profile exists to
        provide, even where every attenuation rule in
        <xref target="attenuation"/> is otherwise satisfied.
      </t>
      <t>
        The agent identifier requirement in
        <xref target="agent-identifier"/> requires unlinkability across
        Relying Services specifically so that two Relying Services
        receiving requests from the same underlying agent cannot, from
        the identifier alone, determine that the requests originated from
        the same principal.
      </t>
      <t>
        This profile does not eliminate the Attestation Issuer's own
        visibility into the queries it answers. The Attestation Issuer
        necessarily observes that some verifier asked whether some
        subject meets some floor, even though the verifier itself learns
        only a boolean result. Where the query pattern itself is
        sensitive, this residual, issuer-side query log is a real and
        unsolved limitation of this profile, not an oversight to be
        corrected by better protocol design; deployments that need to
        eliminate it need a mechanism outside this document's scope.
      </t>
      <t>
        Because the Agent-Delegation field is visible to any intermediary
        able to read HTTP headers, and this document defines no
        confidentiality mechanism for it, links in the chain MUST NOT
        carry personal data belonging to the Delegator, any intermediate
        Delegate, or any subject the floor condition concerns.
      </t>
    </section>

    <section anchor="related-work" numbered="true" toc="default">
      <name>Relationship to Existing Work</name>
      <t>
        The OAuth Working Group charter <xref target="OAUTH-CHARTER"/>, as updated 2026-06-04, includes
        the following work item, quoted in full: "Developing new
        mechanisms or/and extensions for authorization of automated
        agents working on behalf of users, including addressing scenarios
        where automated agents act across multiple administrative
        domains." This document targets that work item directly: it
        addresses cross-administrative-domain agent authorization with an
        attenuation mechanism a verifier can check at every hop.
      </t>
      <t>
        <xref target="I-D.klrc-aiagent-auth"/>, submitted 6 July 2026 and
        expiring 7 January 2027 (version -03 is the latest published
        version; this document was current as of 2026-08-28), is an
        individual submission and has not been adopted by the Working
        Group. Its Section 8 describes a credential-provisioning and
        posture-attestation stack for agents, and its Section 10.6
        defines an Identity Assertion JWT Authorization Grant. This
        document composes with that draft at both points: the attenuated
        chain this document specifies can carry, at any link, a floor
        attestation produced by a provisioning and posture stack of the
        kind that draft describes, and this document's chain can be
        presented alongside, or as an input to, the grant type that draft
        defines. This document does not compete with or attempt to
        replace <xref target="I-D.klrc-aiagent-auth"/>; it fills two
        extension points that draft leaves open.
      </t>
      <t>
        <xref target="I-D.klrc-aiagent-auth"/>'s Section 11 states that a
        participant MAY subscribe to change notifications using
        mechanisms such as the OpenID Shared Signals Framework; it does
        not require such a subscription. This document specifies no
        revocation-notification mechanism at all and instead relies on
        short-lived expiry, per <xref target="attestation"/> and
        <xref target="security"/>. Both documents are, in this sense,
        revocation-light: one permits an optional richer revocation path
        that this document does not require or preclude, and this
        document specifies none. Neither position is presented here as
        superior to the other.
      </t>
      <t>
        <xref target="I-D.klrc-aiagent-auth"/>'s Section 6 wants an
        identifier that remains stable for the lifetime of a workload
        identity, to support audit. This document's
        <xref target="agent-identifier"/> wants an identifier unlinkable
        across Relying Services. These two goals pull in opposite
        directions, and this document does not resolve that tension; see
        <xref target="appendix-b"/>.
      </t>
      <t>
        Three further individual Internet-Drafts entered adjacent space
        recently and are cited here so that this document does not appear
        unaware of its neighbors: <xref target="I-D.asor-wimse-agent-delegation-chain"/>,
        <xref target="I-D.reece-wimse-cross-org-delegation"/>, and
        <xref target="I-D.sweeney-wimse-credential-delegation"/>. This
        document does not attempt a detailed comparison against each; it
        notes their existence as evidence of active, converging interest
        in attenuated agent delegation across administrative domains, a
        problem this document addresses from the OAuth Working Group
        side.
      </t>
      <t>
        <xref target="I-D.asor-wimse-agent-delegation-chain"/> Section 10
        requests a new "Agent Delegation Constraint Types" registry, with
        initial entries max, one_of, not_one_of, prefix, and rank, and
        its Section 4.1 requires a verifier that encounters an unknown
        constraint type to deny the action, never to treat it as
        unconstrained. That draft's registry, as posted, has no entry
        named min: every constraint that draft's Section 4.2 subsumption
        rules define narrows a ceiling (child.max &lt;= parent.max,
        child.one_of a subset of parent.one_of, child.rank &lt;=
        parent.rank), where this document's duration-typed axes are all
        floors tightened upward instead. That draft's registry names
        comparator TYPES and leaves the constrained quantity to a
        profile-level naming agreement; the registry defined in
        <xref target="axis-registry"/> takes the complementary approach
        of naming axes, each bound to one comparator from a closed set.
        The comparator vocabulary is therefore the bridge between the two
        registries, not a shared set of names: rank in that draft's
        registry and the rank comparator of
        <xref target="axis-registry"/> are the same comparator, and
        actionClass in this document's registry uses it. A mirrored min
        comparator, matching this document's min, has been stated as
        intended for a future revision of that draft; it is not present
        in <xref target="I-D.asor-wimse-agent-delegation-chain"/> as
        posted, and this document does not describe it as present.
      </t>
      <t>
        A companion document, <xref target="CAMARA-PROPOSAL"/>, is an
        open, unreviewed API proposal filed to a separate standards
        body's API backlog; it has not been reviewed, accepted, or
        adopted by that body. It proposes the operator/attestation side
        of the same overall design, on the premise that an Attestation
        Issuer of the kind this document treats abstractly can, in one
        concrete instantiation, be a telecommunications operator. The
        two documents meet only at the RFC 9421 header defined in
        <xref target="header"/>; neither depends on the other's
        approval, and this document remains fully specified without the
        companion proposal existing at all.
      </t>
    </section>

    <section anchor="implementation-status" numbered="true" toc="default">
      <name>Implementation Status</name>
      <t>
        This section records the status of a known implementation of this
        profile, in accordance with <xref target="RFC7942"/>. The
        information provided is believed to be accurate at the time of
        writing, has not been independently verified, and does not
        constitute an endorsement of this profile by any party. The
        provided implementation is a single-author, open-source
        proof-of-concept, written in zero-dependency Node.js and
        available at
        <eref target="https://github.com/hamr0/justabit"/>. It has not
        undergone external review and has not been adopted by any
        organization; no Attestation Issuer has reviewed or validated
        this profile.
      </t>
      <t>
        The following elements of this profile are implemented and
        exercised by automated tests in that proof-of-concept:
      </t>
      <ul spacing="normal">
        <li>the attestation object and exact-bytes Ed25519 signature verification described in <xref target="attestation"/>;</li>
        <li>duplicate-top-level-key rejection;</li>
        <li>nonce binding, as distinct from replay protection;</li>
        <li>expiry enforcement, including the missing/non-numeric-expiry-is-expired rule;</li>
        <li>the signed-refusal shape of <xref target="refusal"/> and its independent verification path;</li>
        <li>the closed floor axis set of <xref target="floors"/>, the duration grammar of <xref target="duration-grammar"/>, and the monotone tightening comparison of <xref target="monotone"/>;</li>
        <li>the actionClass and classSource classification and admission rules of <xref target="action-class"/>, exercised by 27 automated cases in the proof-of-concept: the classification procedure; the deterministic path-template rule for matching menu operation keys, per <xref target="declared-menu"/>; and the binding of a menu's issuer to the request's target origin that <xref target="declared-menu"/> requires.</li>
        <li>the writeBudget ledger of <xref target="write-budget"/>: reserve-then-decrement admission against a stateful, per-chain count, and an actionClass r request never spending against it. This shares the same proof-of-concept and the same case count as the previous bullet, and includes the chain identifier derived by the verifier as the SHA-256 digest of L(0)'s signature value, per <xref target="write-budget-chain-identifier"/>, rather than taken from a caller-supplied request field.</li>
      </ul>
      <t>
        The following elements of this profile are NOT implemented in the
        proof-of-concept, and this is stated here without qualification:
      </t>
      <ul spacing="normal">
        <li>RFC 9421 HTTP Message Signature presentment is not implemented; the proof-of-concept has no HTTP transport layer between the parties at all;</li>
        <li>the multi-hop delegation chain of <xref target="attenuation"/> is not implemented; the proof-of-concept exercises only a two-party exchange between one Delegator and one Attestation Issuer;</li>
        <li>the per-Relying-Service unlinkable agent identifier of <xref target="agent-identifier"/> is not implemented.</li>
      </ul>
      <t>
        The catalogue survey behind the honest-limit paragraph of
        <xref target="action-class-limits"/> is included in this same
        repository, alongside its underlying data.
      </t>
    </section>

    <section anchor="security" numbered="true" toc="default">
      <name>Security Considerations</name>
      <t>
        <strong>Lazy verification is the primary risk this profile is designed
        against.</strong> A verifier that checks only the final link of a
        delegation chain, rather than every link per
        <xref target="verification"/>, defeats the entire mechanism: an
        intermediate Delegate can present a leaf link that is internally
        well-formed while the chain that produced it silently widened
        scope, loosened a floor, or extended an expiry at an earlier hop.
        Conformance to this profile requires whole-chain verification;
        there is no partial-conformance mode that checks only the leaf.
      </t>
      <t>
        <strong>Nonce echo does not prevent replay.</strong> As stated in
        <xref target="binding-not-replay"/>, a verifier that treats nonce
        presence as sufficient replay protection can be presented with
        the same attestation more than once within its expiry window. A
        conforming deployment needs its own replay defense, such as
        tracking consumed nonces within their validity window; this
        document does not supply that defense.
      </t>
      <t>
        <strong>Cost-based floors price resets; they do not create
        uniqueness.</strong> A floor expressed in terms of tenure or
        credential age raises the cost of obtaining a fresh credential
        that satisfies it, but it does not establish that the underlying
        subscription or account is held by a unique human, or that one
        subject cannot back multiple agents. A deployment that needs a
        uniqueness guarantee needs a mechanism this profile does not
        provide.
      </t>
      <t>
        <strong>This profile defines no revocation mechanism.</strong> Once an
        attestation or a delegation link is issued, this profile provides
        no way to invalidate it before its stated expiry. The only
        mitigation this profile offers is short expiry; a deployment's
        exposure window is bounded by how short its issuers set expiries,
        not by any revocation capability.
      </t>
      <t>
        <strong>Key distribution is a centralization point.</strong> Verification
        of the root attestation depends on a trust source that resolves
        an Attestation Issuer's public key, per step 5 of
        <xref target="verification"/>. That trust source is, by
        construction, a point every verifier in a deployment must trust
        and a point whose compromise or unavailability affects every
        verification that depends on it.
      </t>
      <t>
        <strong>Rejection MUST be uniform.</strong> As stated in
        <xref target="verification"/>, a verifier MUST NOT return
        different, distinguishable outcomes for different verification
        failures (an expired link versus a bad signature versus a
        loosened floor versus a depth overflow). A verifier that leaks
        which step failed hands an unauthenticated party an oracle it can
        use to probe the boundaries of a valid chain without ever
        constructing one.
      </t>
      <t>
        <strong>An Attestation Issuer's query log is a residual disclosure
        channel even though the verifier learns only a boolean.</strong> This
        is restated here as a security consideration, not only a privacy
        one, because a party able to observe or compel disclosure of that
        query log gains information the wire protocol itself was designed
        to withhold.
      </t>
      <t>
        <strong>An unforgeable chain identifier is what makes a write
        budget a cap rather than a suggestion.</strong> The derivation of
        <xref target="write-budget-chain-identifier"/>, from L(0)'s own
        signature rather than from any value the request supplies, is
        what prevents the presenter of a chain from choosing its own
        identifier and thereby choosing its own remaining count. A
        verifier that accepts a presenter-supplied chain identifier
        converts the hard cap of <xref target="write-budget"/> into
        something the presenter can reset at will, simply by supplying a
        different value on the next request; <xref target="vectors"/>'s
        V11 exists to catch exactly that failure. Per-verifier counting,
        by contrast, per <xref target="write-budget-limits"/>, is a
        stated limitation of this document, not a defect to be concealed:
        a deployment that needs a single shared count across verifiers
        needs a mechanism this document does not supply.
      </t>
      <t>
        <strong>A declared menu is an owner-signed downgrade surface.</strong>
        classSource declared lets the Resource Owner's menu lower a
        request's actionClass below its method default, for example
        declaring a POST as r. The origin-binding rule and the
        out-of-band key requirement of <xref target="declared-menu"/> are
        what keep a third party from supplying that downgrade for a
        resource it does not own: without both checks, a verifier that
        resolves one key for more than one Resource Owner could be
        handed a validly-signed menu for the wrong resource and apply its
        declared classes to a request it was never meant to cover. A
        verifier that accepts a menu without checking both the
        signature and the origin match does not conform to this
        document.
      </t>
    </section>

    <section anchor="iana" numbered="true" toc="default">
      <name>IANA Considerations</name>
      <t>
        This document registers the following entry in the "Hypertext
        Transfer Protocol (HTTP) Field Name Registry" defined by
        <xref target="RFC9110"/>:
      </t>
      <table>
        <thead>
          <tr><th>Field Name</th><th>Status</th><th>Structured Type</th><th>Reference</th></tr>
        </thead>
        <tbody>
          <tr><td>Agent-Delegation</td><td>permanent</td><td>List</td><td>This document, <xref target="header"/></td></tr>
        </tbody>
      </table>
      <t>
        This document requests IANA create the "HAMR Floor Axis
        Registry", referenced from <xref target="axis-registry"/>.
        Registration policy for this registry is Specification Required
        <xref target="RFC8126"/>. The registration template is the five
        fields defined in <xref target="axis-registry"/>: Name,
        Comparator, Value Domain, Tightening Direction, and Omitted-Axis
        Rule. The Comparator field of a registration MUST be exactly one
        of min, max, rank, or one_of; a registration naming any other
        comparator is not valid. The initial contents of the registry
        are the eight entries given in the table in
        <xref target="axis-registry"/>: subjectClass, tenureMin,
        credentialAgeMin, accountClass, partialPolicy, actionClass,
        classSource, and writeBudget.
      </t>
      <t>
        No other IANA actions are required by this document.
      </t>
    </section>

  </middle>

  <back>
    <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.8941.xml"/>
      <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.9421.xml"/>
      <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.9110.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.7515.xml"/>
      <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.6454.xml"/>
      <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.6234.xml"/>
    </references>
    <references>
      <name>Informative References</name>
      <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.9396.xml"/>
      <reference anchor="I-D.das-agentic-tool-binding" target="https://datatracker.ietf.org/doc/html/draft-das-agentic-tool-binding-02">
        <front>
          <title>tool_use Is Not invoke(): Binding Execution-Finality to Agentic Tool-Call Interfaces and MCP</title>
          <author fullname="Sangam Das" initials="S." surname="Das">
            <organization>Independent Inventor</organization>
          </author>
          <date day="31" month="August" year="2026"/>
        </front>
        <seriesInfo name="Internet-Draft" value="draft-das-agentic-tool-binding-02"/>
      </reference>
      <reference anchor="I-D.schrock-ep-authorization-receipts" target="https://datatracker.ietf.org/doc/html/draft-schrock-ep-authorization-receipts-12">
        <front>
          <title>Authorization Receipts for High-Risk Agent Actions</title>
          <author fullname="Iman Schrock" initials="I." surname="Schrock">
            <organization>EMILIA Protocol, Inc.</organization>
          </author>
          <date day="16" month="August" year="2026"/>
        </front>
        <seriesInfo name="Internet-Draft" value="draft-schrock-ep-authorization-receipts-12"/>
      </reference>
      <reference anchor="I-D.klrc-aiagent-auth" target="https://datatracker.ietf.org/doc/draft-klrc-aiagent-auth/">
        <front>
          <title>AI Agent Authentication and Authorization</title>
          <author initials="P." surname="Kasselman"><organization>Defakto Security</organization></author>
          <author initials="J." surname="Lombardo"><organization>AWS</organization></author>
          <author initials="Y." surname="Rosomakho"><organization>Zscaler</organization></author>
          <author initials="B." surname="Campbell"><organization>Ping Identity</organization></author>
          <author initials="N." surname="Steele"><organization>OpenAI</organization></author>
          <author initials="A." surname="Parecki"><organization>Okta</organization></author>
          <date month="July" day="6" year="2026"/>
        </front>
        <seriesInfo name="Internet-Draft" value="draft-klrc-aiagent-auth-03"/>
      </reference>
      <reference anchor="I-D.asor-wimse-agent-delegation-chain" target="https://datatracker.ietf.org/doc/html/draft-asor-wimse-agent-delegation-chain-00">
        <front>
          <title>Verifiable Attenuated Delegation for AI Agent Chains</title>
          <author fullname="Rafael Asor" initials="R." surname="Asor">
            <organization>Attenu</organization>
          </author>
          <date day="27" month="August" year="2026"/>
        </front>
        <seriesInfo name="Internet-Draft" value="draft-asor-wimse-agent-delegation-chain-00"/>
      </reference>
      <reference anchor="I-D.reece-wimse-cross-org-delegation" target="https://datatracker.ietf.org/doc/draft-reece-wimse-cross-org-delegation/">
        <front>
          <title>Cross-Organizational Delegation for Workload and Agent Identity: Problem Statement and Requirements</title>
          <author initials="M." surname="Reece"><organization>TowerGuardian Consulting</organization></author>
          <date month="August" day="31" year="2026"/>
        </front>
        <seriesInfo name="Internet-Draft" value="draft-reece-wimse-cross-org-delegation-02"/>
      </reference>
      <reference anchor="I-D.sweeney-wimse-credential-delegation" target="https://datatracker.ietf.org/doc/draft-sweeney-wimse-credential-delegation/">
        <front>
          <title>Credential Delegation Protocol for AI Agents in Multi-System Environments</title>
          <author initials="K." surname="Sweeney"/>
          <date month="July" day="27" year="2026"/>
        </front>
        <seriesInfo name="Internet-Draft" value="draft-sweeney-wimse-credential-delegation-00"/>
      </reference>
      <reference anchor="CAMARA-PROPOSAL" target="https://github.com/camaraproject/APIBacklog/issues/330">
        <front>
          <title>CarrierAttestation: An API Proposal for Attested Windowed Disclosure</title>
          <author initials="A." surname="Hassan"><organization>Independent</organization></author>
          <date year="2026" month="August" day="28"/>
        </front>
      </reference>
      <reference anchor="OAUTH-CHARTER" target="https://datatracker.ietf.org/wg/oauth/about/">
        <front>
          <title>Web Authorization Protocol (oauth) Working Group Charter</title>
          <author><organization>IETF</organization></author>
          <date year="2026" month="June" day="4"/>
        </front>
      </reference>
      <reference anchor="I-D.google-cfrg-libzk" target="https://datatracker.ietf.org/doc/draft-google-cfrg-libzk/">
        <front>
          <title>Longfellow ZK</title>
          <author initials="M." surname="Frigo"><organization>Google</organization></author>
          <author initials="A." surname="shelat"><organization>Google</organization></author>
          <date month="July" day="22" year="2026"/>
        </front>
        <seriesInfo name="Internet-Draft" value="draft-google-cfrg-libzk-02"/>
      </reference>
      <reference anchor="ISO18013-5" target="https://www.iso.org/standard/69084.html">
        <front>
          <title>ISO/IEC 18013-5: Personal identification - ISO-compliant driving licence - Part 5: Mobile driving licence (mDL) application</title>
          <author><organization>International Organization for Standardization</organization></author>
          <date year="2021"/>
        </front>
      </reference>
      <reference anchor="ICAO9303">
        <front>
          <title>ICAO Doc 9303, Machine Readable Travel Documents, Eighth Edition</title>
          <author><organization>International Civil Aviation Organization</organization></author>
          <date year="2021"/>
        </front>
      </reference>
    </references>

    <section anchor="appendix-a" numbered="true" toc="default">
      <name>Non-Normative Instantiations</name>
      <t>
        This appendix is entirely non-normative. It describes concrete
        ways to satisfy the abstract requirements of the body of this
        document, to help a reader evaluate the profile's deployability.
        Nothing in this appendix constrains a conforming implementation;
        a deployment satisfying the normative sections above by any other
        means is equally conforming.
      </t>
      <t>
        Three directions are sketched below. They differ in what makes
        the underlying credential scarce; none is required, preferred, or
        assumed by this profile.
      </t>
      <t>
        <strong>Direction 1: subscription attestation.</strong> A mobile
        network operator can act as the Attestation Issuer described in
        <xref target="attestation"/>. In such an instantiation, a
        subscriber identity module credential grounds the Delegator's
        identity, and the operator attests floor conditions about the
        line associated with that credential without disclosing the
        line's underlying attributes. The floor axes named abstractly in
        <xref target="floors"/> map, in this instantiation, to concrete
        network-observable attributes as follows: subjectClass maps to
        the line's service type (for example, voice-and-data versus
        machine-to-machine); tenureMin maps to the line's subscription
        tenure; credentialAgeMin maps to the elapsed time since the
        credential (for example, the SIM) was last swapped; accountClass
        maps to a billing relationship category (for example, postpaid
        versus prepaid); partialPolicy maps to how the operator's
        attestation service handles a query for which it holds incomplete
        data. This direction's scarcity is economic: obtaining many
        qualifying credentials costs money over time. Economic cost does
        not establish uniqueness. A companion document,
        <xref target="CAMARA-PROPOSAL"/>, is an open, unreviewed API
        proposal that proposes a horizontal profile to a
        telecommunications standards body along these lines,
        independently of this document and without either document
        depending on the other's adoption; nothing about it has been
        approved, accepted, endorsed, reviewed, or adopted.
      </t>
      <t>
        <strong>Direction 2: a government-issued document credential
        proved in zero knowledge.</strong> A credential in the ISO/IEC
        18013-5 <xref target="ISO18013-5"/> mobile document (mdoc) format,
        held in a wallet, can be used to prove a predicate over the
        credential in zero knowledge, rather than to disclose the
        credential's contents. The verifier learns one bit and learns
        nothing else, and separate presentations are unlinkable. This
        direction's scarcity is cryptographic: it is rooted in a document
        issued by a government authority rather than in a purchasable
        subscription. Work on this class of scheme is in progress in the
        IETF; see <xref target="I-D.google-cfrg-libzk"/>. This appendix
        does not state that any particular implementation of this
        direction exists or has been demonstrated.
      </t>
      <t>
        <strong>Direction 3: a document chip signature with accompanying
        evidence.</strong> A holder's device can read the signature on a
        government-issued document's chip and verify it against the
        issuing authority's public-key infrastructure, a process known as
        passive authentication and specified in ICAO Doc 9303
        <xref target="ICAO9303"/>. This establishes that the document is
        genuine and unaltered. On its own, the chip-signature check says
        nothing about who presented the document or about the software
        that performed the read, so deployments of this class pair it
        with additional evidence, and what that evidence is varies: an
        attestation from the device platform that unmodified software
        performed the read; a signature from a party the verifier
        trusts, vouching for the value reported; a zero-knowledge proof
        of the predicate itself; or no accompanying evidence at all.
      </t>
      <t>
        The trust model differs by evidence type, and it matters which
        one a deployment picks. Where the accompanying evidence is an
        attestation, the verifier does not check a proof; it checks that
        trustworthy code ran, and then relies on the value that code
        reported, so breaking the attestation collapses the claim. Where
        the accompanying evidence is a zero-knowledge proof, the verifier
        checks the proof itself, and breaking a platform attestation buys
        an attacker nothing, because the mathematics still has to hold.
        Where there is no accompanying evidence, the claim rests on the
        chip signature alone. A deployment describing this direction
        needs to state which evidence it uses, because the strength of
        the claim is not a property of the document root. One limit does
        not change regardless of which evidence is paired with it:
        passive authentication proves the document is genuine and
        unaltered; it does NOT bind the presenter to the document. This
        direction therefore bounds the number of identities a holder can
        obtain to the number of documents held; it does NOT establish one
        identity per human, and must not be described as doing so.
      </t>
      <t>
        All three directions satisfy the same abstract Attestation Issuer
        role defined in the body of this document; they differ in what
        makes a credential scarce. A deployment may use any of them, or
        another mechanism entirely. This profile does not require,
        prefer, or depend on any of them.
      </t>
      <t>
        <strong>Direction 4: harness-side experience.</strong> These are
        three open-source, single-author experiments, available at
        <eref target="https://github.com/hamr0/bareguard"/>,
        <eref target="https://github.com/hamr0/bareloop"/>, and
        <eref target="https://github.com/hamr0/bareagent"/>, that exercise
        the boundary drawn in <xref target="layers"/>; they are not
        implementations of this profile, which is why they are not listed
        in <xref target="implementation-status"/>. Non-normative, like the
        rest of this appendix.
      </t>
      <t>
        <strong>bareguard</strong> is one chokepoint between an agent and
        the world: every action passes through a single gate and comes
        back allow, deny, or ask a human.
      </t>
      <ul spacing="normal">
        <li>a floor gate decides before the action runs, plus a separate detector after the result that annotates and never blocks alone; the split maps onto layers (a) and (c) of <xref target="layers"/>;</li>
        <li>capability presets may only narrow the floor, never widen it, so a wrong preset is not a safety hole;</li>
        <li>quantitative limits are enforced as a running cumulative total, because a per-action cap is defeated by splitting one action into many; only two comparator kinds were needed in practice, set membership and an ordered-enum threshold.</li>
      </ul>
      <t>
        <strong>bareloop</strong> has an agent author its own workflow
        scaffolding as a constrained, validated config, with every run
        executing under an outer gate the agent cannot reach or argue
        with.
      </t>
      <ul spacing="normal">
        <li>the agent authors its workflow and never its arbiter; closes, budgets, and caps live outside the authored part;</li>
        <li>a predicate decides a pass, a judge never renders the verdict, and a judged verdict class needs a pre-scored calibration set before it may gate anything;</li>
        <li>an omitted cap reads as an explicit choice, never a silent default, because a defaulted cap is an unadvertised second ceiling.</li>
      </ul>
      <t>
        <strong>bareagent</strong> is the think, act, observe loop: a goal
        goes in and coordinated actions come out.
      </t>
      <ul spacing="normal">
        <li>a policy chokepoint inside the loop forwards every action to an external gate that decides and never runs it;</li>
        <li>a lock on a check's code does not protect the check's semantics; a stateful function defeated an unsatisfiable check across repeated invocations;</li>
        <li>an incomplete result is returned honestly rather than as a faked pass.</li>
      </ul>
      <t>
        In each case the point of control sat at the credential boundary
        or the resource, never in the harness, which is the placement
        <xref target="layers"/> assumes.
      </t>
    </section>

    <section anchor="appendix-b" numbered="true" toc="default">
      <name>Open Reconciliation Item: Identifier Stability Versus Unlinkability</name>
      <t>
        This appendix records an unresolved tension rather than a
        solution. <xref target="I-D.klrc-aiagent-auth"/>'s Section 6
        wants an agent identifier that is stable for the lifetime of a
        workload identity, so that audit records can be correlated over
        time. This document's <xref target="agent-identifier"/> wants an
        identifier that is unlinkable across distinct Relying Services,
        so that no two Relying Services can correlate requests from the
        same underlying agent by identifier alone.
      </t>
      <t>
        These two properties are in tension: an identifier stable enough
        to support long-lived audit correlation at one Relying Service is,
        by that same stability, a stronger correlation handle if it is
        reused, or is derivable in a reused form, across Relying Services.
        A per-Relying-Service unlinkable identifier, taken to its logical
        conclusion, complicates the kind of long-lived, cross-request
        audit trail Section 6 of that draft wants.
      </t>
      <t>
        This document does not resolve this tension. It is recorded here
        as an open item for the Working Group's consideration, not
        presented as solved by either document.
      </t>
    </section>

    <section anchor="vectors" numbered="true" toc="default">
      <name>Test Vectors</name>
      <t>
        This appendix is non-normative. The vectors below are an aid to
        implementers checking their own understanding of the attenuation
        rules in <xref target="attenuation"/> against a common set of
        examples; they are not an additional requirement, and they do not
        modify or extend the normative requirements stated in the body of
        this document. Where a vector appears to conflict with a normative
        section, the normative section governs.
      </t>
      <t>
        Each vector is a delegation chain: an ordered sequence of links,
        each carrying a scope (<xref target="scope"/>), a floor, and an
        expiry, together with the outcome a conforming verifier is expected
        to reach and, where that outcome is rejection, which rule of
        <xref target="attenuation"/> the chain violates. An implementation
        checking itself against this appendix is expected to reproduce
        every expected outcome listed below, using the scope and floor
        values shown.
      </t>
      <t>
        In every vector, subjectClass is interactive on every link, and
        accountClass and partialPolicy are not exercised and are omitted
        from every link; a floor is a set of axis/value pairs and is not
        required to name every axis in <xref target="floors"/>. Only
        scope, tenureMin, credentialAgeMin, and expiry vary below, and
        those are what the tables show.
      </t>
      <table>
        <thead>
          <tr><th>Link</th><th>Scope</th></tr>
        </thead>
        <tbody>
          <tr><td>V1 L(0)</td><td>booking:read, booking:create, payment:authorize</td></tr>
          <tr><td>V1 L(1)</td><td>booking:read, booking:create</td></tr>
          <tr><td>V2 L(0)</td><td>booking:read</td></tr>
          <tr><td>V2 L(1)</td><td>booking:read, booking:create</td></tr>
          <tr><td>V3 L(0)</td><td>booking:read</td></tr>
          <tr><td>V3 L(1)</td><td>booking:read</td></tr>
          <tr><td>V4 L(0)</td><td>booking:read</td></tr>
          <tr><td>V4 L(1)</td><td>booking:read</td></tr>
          <tr><td>V5 L(0)</td><td>booking:read</td></tr>
          <tr><td>V5 L(1)</td><td>booking:read</td></tr>
          <tr><td>V6 L(0)</td><td>booking:read</td></tr>
          <tr><td>V6 L(1)</td><td>booking:read, booking:create</td></tr>
          <tr><td>V6 L(2)</td><td>booking:read</td></tr>
        </tbody>
      </table>
      <t>
        The floor and expiry for the same links follow.
      </t>
      <table>
        <thead>
          <tr><th>Link</th><th>tenureMin</th><th>credentialAgeMin</th><th>Expiry</th></tr>
        </thead>
        <tbody>
          <tr><td>V1 L(0)</td><td>P1Y</td><td>P90D</td><td>2026-12-01T00:00:00Z</td></tr>
          <tr><td>V1 L(1)</td><td>P1Y</td><td>P180D</td><td>2026-11-30T00:00:00Z</td></tr>
          <tr><td>V2 L(0)</td><td>P1Y</td><td>P90D</td><td>2026-12-01T00:00:00Z</td></tr>
          <tr><td>V2 L(1)</td><td>P1Y</td><td>P90D</td><td>2026-11-30T00:00:00Z</td></tr>
          <tr><td>V3 L(0)</td><td>P2Y</td><td>P180D</td><td>2026-12-01T00:00:00Z</td></tr>
          <tr><td>V3 L(1)</td><td>P1Y</td><td>P180D</td><td>2026-11-30T00:00:00Z</td></tr>
          <tr><td>V4 L(0)</td><td>P2Y</td><td>P180D</td><td>2026-12-01T00:00:00Z</td></tr>
          <tr><td>V4 L(1)</td><td>P2Y</td><td>(omitted)</td><td>2026-11-30T00:00:00Z</td></tr>
          <tr><td>V5 L(0)</td><td>P1Y</td><td>P90D</td><td>2026-11-01T12:00:00Z</td></tr>
          <tr><td>V5 L(1)</td><td>P1Y</td><td>P90D</td><td>2026-11-01T13:00:00Z</td></tr>
          <tr><td>V6 L(0)</td><td>P2Y</td><td>P180D</td><td>2026-12-01T00:00:00Z</td></tr>
          <tr><td>V6 L(1)</td><td>P2Y</td><td>P180D</td><td>2026-11-30T00:00:00Z</td></tr>
          <tr><td>V6 L(2)</td><td>P2Y</td><td>P180D</td><td>2026-11-29T00:00:00Z</td></tr>
        </tbody>
      </table>
      <table>
        <thead>
          <tr><th>Vector</th><th>Expected outcome</th><th>Rule violated</th></tr>
        </thead>
        <tbody>
          <tr><td>V1</td><td>accept</td><td>n/a - chain tightens correctly on all three rules</td></tr>
          <tr><td>V2</td><td>reject</td><td>Rule 1 (scope containment): L(1) names booking:create, which L(0) did not hold</td></tr>
          <tr><td>V3</td><td>reject</td><td>Rule 2 (floor non-relaxation): L(1)'s tenureMin of P1Y is looser than L(0)'s P2Y</td></tr>
          <tr><td>V4</td><td>reject</td><td>Rule 2 (floor non-relaxation): L(1) omits credentialAgeMin, an axis L(0) constrained</td></tr>
          <tr><td>V5</td><td>reject</td><td>Rule 3 (expiry non-extension): L(1)'s expiry is later than L(0)'s</td></tr>
          <tr><td>V6</td><td>reject</td><td>Rule 1 (scope containment), violated at the interior pair (L(0), L(1)); the pair (L(1), L(2)) is correctly attenuated</td></tr>
        </tbody>
      </table>
      <t>
        V4 is a distinct and easily missed failure mode from V3: a floor
        can be relaxed either by widening a value already present on an
        axis, as in V3, or by dropping the axis from the link entirely, as
        in V4. Rule 2 in <xref target="attenuation"/> treats both as the
        same violation, and an implementation that checks only for a
        looser value on an axis both links carry, without also checking
        for an axis the parent link carried and the child link dropped,
        does not detect V4.
      </t>
      <t>
        V6 is the negative control. The violation is not at the leaf link:
        the pair (L(1), L(2)) attenuates correctly by every rule, and only
        the interior pair (L(0), L(1)) violates rule 1. A verifier that
        checks only the final link, or only the pair adjacent to the leaf,
        accepts this chain; such a verifier does not conform to
        <xref target="verification"/>, which requires every adjacent pair
        in the chain to be checked. This vector exists specifically to
        detect that failure.
      </t>
      <t>
        Vectors V7 through V9 below extend this appendix to the
        actionClass and classSource axes of <xref target="action-class"/>.
        In all three, subjectClass is interactive, and scope, tenureMin,
        and credentialAgeMin are omitted and not exercised, following the
        same convention stated above for V1 through V6. V7 is a
        two-link delegation chain, checked the same way as V1 through V6.
        V8 and V9 each involve a single link and one incoming request,
        together with, where noted, one menu; they exercise
        <xref target="classification"/> and
        <xref target="declared-menu"/> rather than the three attenuation
        rules, so no parent link is shown for them.
      </t>
      <table>
        <thead>
          <tr><th>Link</th><th>actionClass</th><th>classSource</th></tr>
        </thead>
        <tbody>
          <tr><td>V7 L(0)</td><td>x</td><td>method</td></tr>
          <tr><td>V7 L(1)</td><td>w</td><td>method</td></tr>
          <tr><td>V8 L(0)</td><td>r</td><td>declared</td></tr>
          <tr><td>V9 L(0)</td><td>r</td><td>declared</td></tr>
        </tbody>
      </table>
      <t>
        V8 and V9 each present a request "POST /check" against a link
        whose actionClass is r. Both are accompanied by a menu, signed by
        the Resource Owner's key, declaring "POST /check" as r. In V8 the
        menu's iss value is the origin of the request target,
        https://api.example.com, matching it exactly. In V9 the menu
        carries the same declared entry and the same valid signature, but
        its iss value is https://attacker.example.com, an origin
        different from the request target.
      </t>
      <table>
        <thead>
          <tr><th>Vector</th><th>Expected outcome</th><th>Basis</th></tr>
        </thead>
        <tbody>
          <tr><td>V7</td><td>accept; effective actionClass is w</td><td>n/a - actionClass lowered from x to w, the direction <xref target="action-class-values"/> permits</td></tr>
          <tr><td>V8</td><td>the request classifies as r; admitted against the actionClass r floor</td><td><xref target="declared-menu"/>: the menu verifies and its iss matches the request target, so the declared value governs</td></tr>
          <tr><td>V9</td><td>the request classifies as x, exceeding the actionClass r floor; refused</td><td><xref target="declared-menu"/>: the menu's iss does not match the request target, so the menu fails and the method default for POST, x, applies instead of the menu's declared r</td></tr>
        </tbody>
      </table>
      <t>
        V9 is the negative control for the origin-binding rule of
        <xref target="declared-menu"/>. A verifier that checks the menu's
        signature but skips the comparison between iss and the request
        target's origin reaches the same outcome as V8 - it accepts the
        declared value r - and so admits a request that a verifier
        applying the origin-binding rule correctly refuses. The two
        vectors present an identical menu and an identical requested
        actionClass floor and differ only in the menu's iss value, so any
        difference in outcome between an implementation and this table is
        attributable to that one comparison.
      </t>
      <t>
        More generally, a suite composed only of chains expected to be
        accepted cannot distinguish a verifier that correctly implements
        the rules of <xref target="attenuation"/> from one that accepts
        every chain unconditionally; both pass such a suite identically.
        At least one vector expected to be rejected is therefore required
        for a suite to have any diagnostic value at all, and V6 in
        particular is required to detect a verifier that checks only the
        leaf of the chain.
      </t>
      <t>
        Vectors V10 and V11 below extend this appendix to the writeBudget
        axis of <xref target="write-budget"/>. Both present the same
        single-link chain, L(0) with actionClass x and writeBudget 2,
        against a series of x-class requests; the chain identifier is
        whatever <xref target="write-budget-chain-identifier"/> derives
        from L(0)'s signature, and is the same value across every request
        in both vectors, since both present the same L(0).
      </t>
      <table>
        <thead>
          <tr><th>Step</th><th>Request</th><th>Vector</th><th>Expected outcome</th><th>Remaining count after step</th></tr>
        </thead>
        <tbody>
          <tr><td>1</td><td>x-class request 1</td><td>V10</td><td>admitted</td><td>1</td></tr>
          <tr><td>2</td><td>x-class request 2</td><td>V10</td><td>admitted</td><td>0</td></tr>
          <tr><td>3</td><td>x-class request 3</td><td>V10</td><td>refused, budget exhausted</td><td>0</td></tr>
          <tr><td>4</td><td>x-class request 4, presented with a different, caller-supplied chain identifier value</td><td>V11</td><td>refused, budget exhausted</td><td>0</td></tr>
        </tbody>
      </table>
      <t>
        V10 is the positive case: two successive x-class requests against
        the chain are admitted, dropping the remaining count from 2 to 1
        to 0, and a third is refused because the remaining count is
        already 0, per the admission rule of
        <xref target="write-budget-limit-count"/>.
      </t>
      <t>
        V11 is the negative control. It re-presents the identical chain
        used in V10, after its budget is already exhausted, but the
        fourth request carries a different chain identifier value of the
        caller's own choosing rather than one the verifier derived from
        L(0). Because <xref target="write-budget-chain-identifier"/>
        requires the verifier to derive the chain identifier itself and
        forbids taking one from the request, the count is not refilled
        and step 4 is refused on the same exhausted count as step 3. A
        verifier that instead took the chain identifier from the request
        would treat the fourth request as belonging to a fresh chain with
        a full budget of 2, and would wrongly admit it; V11 exists
        specifically to detect that failure.
      </t>
      <t>
        These vectors are illustrative and not exhaustive. Passing them
        does not establish conformance to this document as a whole: V1
        through V6 cover the three attenuation rules of
        <xref target="attenuation"/>, V7 through V9 cover the
        actionClass tightening rule, the declared-value substitution
        rule, and the menu origin-binding rule of
        <xref target="action-class"/>, and V10 through V11 cover the
        writeBudget admission rule and the chain-identifier-derivation
        rule of <xref target="write-budget"/>; together they do not
        exercise signature verification of a delegation link itself,
        nonce binding, expiry evaluation against wall-clock time, or the
        header field encoding described in <xref target="header"/> and
        <xref target="rfc9421-profile"/>. These vectors have not been
        executed against any implementation by anyone, including the
        author; they were derived by hand from the rules in
        <xref target="attenuation"/>, <xref target="action-class"/>, and
        <xref target="write-budget"/>.
      </t>
    </section>

    <section anchor="changes-since-00" numbered="true" toc="default">
      <name>Changes since -00</name>
      <t>
        This section is non-normative and is expected to be removed
        before this document leaves individual submission status.
      </t>
      <ul spacing="normal">
        <li>
          <t>
            Added the Floor Axis Registry
            (<xref target="axis-registry"/>): axis names are now
            extensible through an IANA registry, Specification Required,
            rather than fixed to the closed set this document defines
            directly. Each registered name is bound to exactly one
            comparator from a closed set of four (min, max, rank,
            one_of); an unregistered axis name or an unregistered
            comparator is a hard rejection, extending the -00 rule that
            already applied to axis names alone. Eight initial entries
            are registered: the five axes <xref target="floors"/> already
            defines (subjectClass, tenureMin, credentialAgeMin,
            accountClass, partialPolicy) are now registered with explicit
            comparators (one_of for the three enum axes, treating -00's
            equality-only rule as a singleton set; min for the two
            duration axes); and three new names, actionClass, classSource,
            and writeBudget, are registered with their comparators, but
            their full semantics are reserved for a later item of this
            revision and are not yet specified. Added the
            corresponding IANA Considerations request
            (<xref target="iana"/>) and a paragraph in
            <xref target="related-work"/> comparing this registry's
            approach against the constraint-type registry of
            <xref target="I-D.asor-wimse-agent-delegation-chain"/>.
          </t>
        </li>
        <li>
          <t>
            Added <xref target="layers"/>, a new, purely informational
            section placed after <xref target="motivation"/> and before
            <xref target="header"/>. It positions this document among
            three delegation layers (who may act, what exactly may be
            done per invocation, and what happened once), states that
            this document occupies layer (a) plus floors, and
            distinguishes it from <xref target="RFC9396"/> (grant-time
            binding), <xref target="I-D.das-agentic-tool-binding"/>
            (per-call tool-name-and-argument binding), and
            <xref target="I-D.schrock-ep-authorization-receipts"/>
            (layer (c) receipts). It also names, non-normatively, the
            shared structural problem that a parent credential remains
            valid after attenuation, citing
            <xref target="I-D.asor-wimse-agent-delegation-chain"/>
            Section 9.1 for mitigations this document does not itself
            supply.
          </t>
        </li>
        <li>
          <t>
            Added Direction 4 to <xref target="appendix-a"/>: three
            single-author, open-source harness experiments (bareguard,
            bareloop, bareagent) that exercise the boundary drawn in
            <xref target="layers"/> without implementing this profile,
            and are therefore not listed in
            <xref target="implementation-status"/>.
          </t>
        </li>
        <li>
          <t>
            Added <xref target="action-class"/>, a new normative section
            placed after <xref target="floors"/>, specifying the
            actionClass and classSource axes reserved but not yet
            specified by the Floor Axis Registry addition above: the
            actionClass values r, w, and x and their rank tightening
            rule; the classSource values method and declared, ranked
            method &lt; declared with method the tighter, default value,
            and the rule that a child link moves only from declared to
            method; the classification procedure
            (HTTP-method default per <xref target="RFC9110"/>, or a
            verified, resource-bound menu when classSource is declared,
            falling back to the method default on any menu failure and
            never combining the two); the declared menu itself, a JWS
            (<xref target="RFC7515"/>) whose payload names the resource's
            origin (<xref target="RFC6454"/>) and a map from
            operation key to actionClass value, including a deterministic
            path-template matching rule and an origin-binding requirement
            on the menu's issuer; verifier placement at the resource or
            credential boundary; and an honest-limits paragraph, backed
            by a committed catalogue survey, that a POST is not always
            classed correctly by method alone. Added a corresponding
            paragraph to <xref target="security"/>, three test vectors
            (V7 through V9, the last a negative control for the
            origin-binding rule) to <xref target="vectors"/>, and a bullet
            to <xref target="implementation-status"/> recording the
            proof-of-concept's case count against this section's
            requirements. Replaced the two Floor Axis
            Registry table cells that deferred actionClass's and
            classSource's semantics, and the standalone marker comment
            for this item, with a cross-reference to the new section.
          </t>
        </li>
        <li>
          <t>
            Added <xref target="write-budget"/>, a new normative section
            placed after <xref target="action-class"/>, specifying the
            writeBudget axis reserved but not yet specified by the Floor
            Axis Registry addition above: the axis as a non-negative,
            max-comparator, cumulative-per-chain integer with an
            omitted-axis floor of zero; the distinction between the
            limit carried in the chain and the count a verifier holds as
            its own state, keyed by a chain identifier and never carried
            in a link, with reserve-then-decrement admission and an
            actionClass r request never spending; and the chain
            identifier itself, derived by the verifier as the SHA-256
            digest of the root link L(0)'s signature value, never taken
            from the request, which resolves case 22 of the
            proof-of-concept. Added a corresponding paragraph to
            <xref target="security"/>, two test vectors (V10, a positive
            three-request sequence, and V11, a negative control re-using
            an exhausted chain under a caller-supplied identifier) to
            <xref target="vectors"/>, and a bullet to
            <xref target="implementation-status"/> recording that the
            proof-of-concept now derives the chain identifier as this
            section requires. Replaced the writeBudget row's deferred-semantics note in
            <xref target="axis-registry"/>'s table, and the standalone
            marker comment for this item, with a cross-reference to the
            new section, and rewrote the paragraph after that table so it
            no longer describes writeBudget's semantics as unspecified.
          </t>
        </li>
        <li>
          <t>
            Updated three sections that already existed in -00. Added a
            Resource Owner entry to the Conventions and Terminology list
            (<xref target="conventions"/>), and a clause to the Floor
            definition in that same list making explicit that a floor is
            the aggregate of its per-axis constraints, at most one per
            axis. Added a step to the ordered Verification Procedure
            (<xref target="verification"/>) placing actionClass
            classification, declared-menu consultation, and writeBudget
            admission after chain and attenuation validation and before
            the Relying Service's authorization-policy step. Restated the
            Floor Axis Registry's Omitted-axis rule
            (<xref target="axis-registry"/>) as two distinct cases,
            link-to-link omission of an axis the parent constrained
            (a rejection per rule 2 of <xref target="attenuation"/>) and
            link-to-published-floor inheritance where no link in the
            chain constrains the axis, replacing an earlier statement
            that conflated the two.
          </t>
        </li>
      </ul>
    </section>
  </back>
</rfc>
