<?xml version="1.0" encoding="utf-8"?>
<rfc xmlns:xi="http://www.w3.org/2001/XInclude" version="3"
     docName="draft-jackson-wimse-evaluation-02" category="info"
     ipr="trust200902" xml:lang="en">
  <front>
    <title abbrev="WIMSE Verifier Evaluation Semantics">Verifier-Side Evaluation Semantics for Delegated Authority Chains</title>
    <author fullname="Wes Jackson">
      <address>
        <email>c.wesjackson@gmail.com</email>
      </address>
    </author>
    <date day="29" month="September" year="2026"/>
    <area>sec</area>
    <workgroup>wimse</workgroup>
    <keyword>workload identity</keyword>
    <keyword>delegation</keyword>
    <keyword>verifier</keyword>
    <keyword>evaluation</keyword>
    <abstract>
      <t>Delegation chain specifications describe the shape of conveyed
      authority. They leave the verifier's half of the exchange
      underdetermined. Two verifiers can check the same chain, both report
      success, and enforce different policy. This document states what a
      verifier must do: the explicit inputs evaluation depends on, and four
      rules that keep evaluation fail-closed. The rules are drawn from the
      Grant &amp; Autonomy Lifecycle (GAL) and Provenance &amp; Trust Context
      (PTC) specifications and from a public reference implementation.</t>
    </abstract>
  </front>
  <middle>
    <section anchor="sec-intro" numbered="true" toc="default">
      <name>Introduction</name>
      <t>A delegation chain is a claim about authority. A verifier turns that
      claim into a decision. Chain formats standardize the claim. This
      document standardizes the decision.</t>
      <t>The failure this prevents is silent divergence. A verifier that drops
      an authorization entry it cannot parse and still approves has enforced
      nothing while reporting success. A verifier that derives "now" from the
      records it is judging keeps expired authority alive during quiet
      periods. A verifier that lets one broken path poison a valid one hands
      any attacker a veto over legitimate authority. Each of these was
      observed in running code during WIMSE implementation work. Each is
      fixed here with a stated rule.</t>
      <t>This document does not define a chain format, a token envelope, or a
      policy language. It defines the evaluation function those formats are
      judged by. It is complementary to chain-format documents such as
      <xref target="DELEGATION-CHAIN"/> and <xref target="CONNECTED-FLIGHT"/>:
      those define what is conveyed, this defines how the receiver judges
      it.</t>
      <t><xref target="CONNECTED-FLIGHT"/> Section 4.1 maps its credentials
      onto the inputs in <xref target="sec-inputs"/> and the rules in
      <xref target="sec-rules"/>. It records the consumption rule of
      <xref target="sec-consumption"/> as only partially addressed by those
      credentials, since scope and expiry bound a credential's validity
      without making it single-use. This document does not restate those
      profiles, which are that document's contribution.</t>
      <t>This document is the verifier-side counterpart to executor-side
      work. <xref target="AEB"/> defines the boundary at which an executor
      admits, consumes authority for, and classifies the outcome of a
      consequential action, and <xref target="CAID"/> defines how two
      representations of one action are compared. Where a rule here needs
      those mechanisms, it states the property and points to them rather
      than defining its own.</t>
      <t>Two of the rules in <xref target="sec-rules"/> are exercised in the
      public reference implementation <xref target="RI"/>: consumption keyed to
      the frozen call, and verification under role-separated keys. The other
      two are not. That implementation consumes no
      <xref target="RFC9396"/> authorization_details entries, and it has no
      derived-grant concept, so no call reaches it by a path; the lifecycle
      half of the per-path rule rests on GAL-39, which <xref target="GAL"/>
      marks normative and not yet implemented there. A rule's force comes from
      the specification that states it, and these notes record what has been
      exercised. The key-bootstrapping
      mechanism discussed in <xref target="sec-security"/> is the known open
      item; it is named as a gap rather than specified.</t>
    </section>
    <section anchor="sec-terminology" numbered="true" toc="default">
      <name>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><em>Frozen call:</em> the exact action a human was shown and
      approved: capability, arguments, recipient, principal, and the
      authority the call was evaluated under, as presented at approval
      time.</t>
      <t><em>Authorization instance:</em> one approval bound to one frozen
      call, from the moment the call is held until a terminal disposition
      closes it.</t>
      <t><em>Refuse:</em> what a verifier does to a token or record that
      fails evaluation under <xref target="sec-rules"/>. A refusal is the
      verifier's decision and involves no human.</t>
      <t><em>Reject:</em> what an approver does to a held frozen call as a
      terminal disposition. A rejection closes the authorization instance
      without executing the call.</t>
      <t><em>Evaluation instant:</em> the instant against which validity,
      including expiry, is judged.</t>
      <t><em>On-behalf-of principal:</em> the principal the chain acts under,
      distinct from the agent acting at each hop.</t>
      <t><em>Principal:</em> the identity tuple a grant is issued to: agent
      identity, skill, user, and trust tier. The unit of authority is the
      (principal, action class) pair. Those four attributes and the action
      class together name who acts, in what capacity, on whose behalf, at what trust, and over what
      class of action. The semantics of the trust tier are
      deployment-defined; this document standardizes the tier's position in
      the tuple, not its values.</t>
      <t><em>Issuer key:</em> the key that signs authority-raising
      records.</t>
      <t><em>Evaluator key:</em> the key that signs authority-lowering
      records, held by a deliberately separate identity.</t>
      <t><em>Delegation path:</em> one chain of delegations from a root of
      trust to the acting agent.</t>
    </section>
    <section anchor="sec-inputs" numbered="true" toc="default">
      <name>Evaluation Inputs</name>
      <t>A verifier's decision MUST be a function of explicit inputs. Four
      inputs are required. Anything the verifier needs that is not in this
      list MUST be supplied explicitly; the verifier does not guess.</t>
      <section anchor="sec-frozen-call" numbered="true" toc="default">
        <name>The Frozen Call</name>
        <t>The frozen call is the exact action the human was shown and
        approved. Evaluation and consumption bind to that call as presented,
        not to a re-serialization, a paraphrase, or an identifier that names
        it. (GAL-36, GAL Section 4.1)</t>
        <t>"As presented" needs a basis for comparison once the same action
        can arrive in more than one representation; otherwise two artifacts
        describing one action carry digests that cannot be compared without
        guessing. A verifier MUST compare a candidate call to the frozen call
        over the material fields declared for the action's type, under a
        canonicalization or mapping profile pinned by the relying party. It
        MUST NOT infer equivalence from field names, descriptions, or
        identifiers, and a comparison the pinned profile cannot make is a
        mismatch. <xref target="CAID"/> supplies both halves: action types
        that declare their material fields (Section 4.2), and an
        Action-Mapping Profile that the relying party pins and that yields
        INDETERMINATE, never a match, when the mapping would lose or cannot
        cover a material field (Section 8).
        This document requires the property and does not define a
        canonicalization of its own.</t>
        <t>The authority a call runs under is part of what the approver
        approved. An approval covers the visible coordinates of the call
        under the authority shown at approval time, so two calls with the
        same visible fields under different authority are different calls. A
        release that runs under a different delegation than the one shown
        breaks what-you-see-is-what-you-execute even when every other
        coordinate matches. A verifier MUST be able to verify that the
        authority under which a call is released is equivalent to the
        authority approved. This document does not prescribe whether that
        equivalence is carried explicitly with the approval or reconstructed
        from immutable records of the frozen call.</t>
      </section>
      <section anchor="sec-instant" numbered="true" toc="default">
        <name>The Evaluation Instant</name>
        <t>The instant against which validity, including expiry, is judged is
        an explicit input to evaluation. It MUST NOT be derived from the
        timestamps of the records under evaluation. Deriving "now" from the
        latest record keeps expired authority alive through quiet periods,
        because time passes without producing records. (GAL-34)</t>
      </section>
      <section anchor="sec-principal" numbered="true" toc="default">
        <name>The On-Behalf-Of Principal</name>
        <t>Conveyed evaluation material MUST include the on-behalf-of
        principal. A verifier that does not share the issuer's log cannot
        recover the principal from the action chain, so material that omits
        it authenticates an action without saying whom it was taken for.
        (<xref target="PTC"/> Section 6.6)</t>
        <t>Evaluation is against the whole tuple, never the agent identity
        alone: a verifier that matches on agent identity while ignoring
        skill, user, or tier has evaluated a different grant. (GAL-36, <xref target="GAL"/>
        Section 5.1)</t>
      </section>
      <section anchor="sec-keys" numbered="true" toc="default">
        <name>Issuer and Evaluator Keys</name>
        <t>Authority-raising records (issuance, promotion, tightening) are
        signed by the issuer key. Authority-lowering records (demotion,
        lapse) are written by a deliberately separate evaluator identity and
        signed by the evaluator key. An identity MUST NOT hold both roles'
        signing keys. The separation is structural, not conventional: a
        grant-store write the agent can reach is a promotion bypass.
        (GAL-37, <xref target="GAL"/> Section 6.7.2, <xref target="GAL"/> Section 6.10)</t>
      </section>
    </section>
    <section anchor="sec-rules" numbered="true" toc="default">
      <name>Evaluation Rules</name>
      <section anchor="sec-every-entry" numbered="true" toc="default">
        <name>Process Every Entry or Refuse</name>
        <t>A verifier MUST process every authorization_details entry
        <xref target="RFC9396"/> presented or refuse the token. An entry of a type the verifier cannot
        evaluate is an entry it cannot process, and the token MUST be
        refused. A verifier that silently drops an entry enforces an
        incomplete policy while reporting success. That is fail-open.
        (A verifier advertises the types it supports with
        authorization_details_types_supported <xref target="RFC9728"/>.)</t>
        <t>Such a refusal is permanent for the presented token: no retry of
        the same token can succeed, because the caller cannot change which
        types the verifier supports. What the caller is told is stated in
        <xref target="sec-security"/>.</t>
      </section>
      <section anchor="sec-fail-closed-path" numbered="true" toc="default">
        <name>Fail Closed Per Path</name>
        <t>Where several delegation paths reach the same agent, the verifier
        MUST evaluate each path independently along its whole length. One
        fully valid path suffices for authority. A broken path MUST NOT
        neutralize a valid one, and a valid path MUST NOT excuse a broken
        one. Where no presented path is fully valid, the token confers no
        authority. Discovering which paths exist is the delegation
        mechanism's work; judging each presented path is the verifier's.</t>
        <t>The lifecycle half of this rule is stated normatively in
        <xref target="GAL"/> as GAL-39: a derived grant does not outlive or
        out-rank the grant it derives from, and where a grant is demoted or
        lapses, every derived grant descending from it ceases to confer
        authority from that evaluation instant, whether or not a record of the
        change has been written. <xref target="GAL"/> Section 1.3 separates
        that half, which the grant standard owns, from path resolution, which
        it does not. The scope half, that one fully valid path suffices and a
        broken path never neutralizes a valid one, is this document's.</t>
      </section>
      <section anchor="sec-consumption" numbered="true" toc="default">
        <name>Consumption Keyed to the Frozen Call</name>
        <t>An approval MUST be consumed only by release or rejection of the
        frozen call it binds, by the whole principal the call was frozen
        for. Consumption MUST NOT be inferred from the approval's identifier
        appearing in any record. Otherwise any party able to write a record
        can burn another party's approval without using it. The release
        executes the stored call and nothing re-sent. (GAL-36, <xref target="GAL"/>
        Section 4.1)</t>
        <t>Rejection here means the approver's terminal disposition, the one
        that closes the authorization instance. A non-terminal disposition,
        such as a deferral or a request for changes, is neither release nor
        rejection: the approval stays pending and nothing is consumed. Each
        authorization instance has at most one consumption event, and it is
        the release or the rejection of its frozen call.</t>
        <t>Consumption keys on the closure of the authorization instance,
        never on the outcome of an execution. Whether a released call
        executed, failed, or ended in an indeterminate state is a separate
        dimension, which executor-side documents classify
        (<xref target="AEB"/> Section 5.13). Once a release has begun
        execution, an indeterminate outcome MUST NOT return the approval to
        pending, because a retry under it could duplicate an effect that did
        occur. <xref target="AEB"/> Section 5.11 describes the executor-side
        counterpart of this rule, an atomic consume-or-reserve before
        invocation.</t>
        <t>This document does not standardize approval interaction. It
        standardizes what the verifier must check about consumption.</t>
      </section>
      <section anchor="sec-role-keys" numbered="true" toc="default">
        <name>Verify Records Under Role-Separated Keys</name>
        <t>A verifier MUST select the acceptable signing keys from the record
        type, MUST refuse a record signed by the other role's key, and MUST
        refuse a key resolvable under both roles. The key that grants
        authority is never the key that judges it. (GAL-37)</t>
      </section>
    </section>
    <section anchor="sec-security" numbered="true" toc="default">
      <name>Security Considerations</name>
      <t>Clock skew: the evaluation instant is supplied by the evaluating
      party as an explicit input. When two parties do not share a clock, the
      party evaluating supplies the instant. The clock source and the skew
      bound are deployment details, and a
      deployment MUST document which clock supplies the evaluation instant
      and the maximum skew it tolerates. This document sets no default
      bound.</t>
      <t>Key bootstrapping across boundaries: a receiving verifier needs the
      sending boundary's issuer key before any rule in <xref target="sec-rules"/>
      can run.</t>
      <t>Open issue: this document does not specify how the verifier comes to
      hold the sending boundary's issuer key. That is three questions, and
      they are separable:</t>
      <ol>
        <li>how candidate key material is obtained;</li>
        <li>how that material is bound to the organization it is claimed
        for; and</li>
        <li>whether the relying party chooses to trust that binding.</li>
      </ol>
      <t>A discovery mechanism can answer the first without answering the
      second, and a binding that answers the second still leaves the third
      to the relying party's own policy. The reference implementation
      answers all three at once by provisioning keys out of band, which
      requires a prior arrangement with each peer. This document requires
      only that the verifier hold a key it has decided to trust before any
      rule in <xref target="sec-rules"/> runs; the mechanism for each
      question is left for the working group.</t>
      <t>Refusals: when a verifier refuses a token under the rules in
      <xref target="sec-rules"/>, the refusal SHOULD be distinguishable by
      the caller as permanent for the presented token, so that the caller
      does not retry a token that cannot succeed. A refusal that surfaces as
      a generic failure gets retried, often at once and at length, which
      costs both parties availability. Where the transport already defines
      a code with that meaning, that code is the one to use: <xref target="RFC9396"/>
      Section 5 defines invalid_authorization_details for an unknown
      authorization details type at the authorization server, and a
      resource server using bearer tokens has invalid_token
      <xref target="RFC6750"/>. This document defines no new code and no
      response format.</t>
      <t>The refusal MUST NOT disclose which authorization details entry,
      delegation path, or grant failed evaluation, beyond what the verifier
      already publishes, such as its supported authorization details types.
      A verifier consumes tokens from another trust domain, and at that
      boundary an informative error is an oracle: naming the path that broke,
      or the parent grant that lapsed, lets the caller map the delegation
      graph and enumerate grant state it cannot otherwise see. The rule is
      to disclose properties of the verifier, which are public, and never
      the evaluated state of the caller's chain. The detail belongs in the
      verifier's audit record, where the operator reads it. A caller may
      still believe it holds authority after a grant above it has lapsed;
      the verifier does not owe it a correction.</t>
      <t>Structural separation: the agent MUST NOT hold signing keys and MUST NOT
      have write access to the grant store. Verification authenticates
      lineage; it does not clean taint and does not substitute for the
      receiver's own trust map. (<xref target="GAL"/> Section 6.7.2, <xref target="PTC"/> Section 6.6,
      <xref target="PTC"/> Section 6.7)</t>
      <t>Misconfigured verification, such as a configured but unusable key
      source, MUST fail closed loudly and MUST NOT silently degrade to no
      verification. (<xref target="PTC"/> Section 6.7)</t>
    </section>
    <section anchor="sec-iana" numbered="true" toc="default">
      <name>IANA Considerations</name>
      <t>This document makes no request of IANA.</t>
    </section>
  </middle>
  <back>
    <references>
      <name>References</name>
      <references>
        <name>Normative References</name>
        <reference anchor="RFC2119">
          <front>
            <title>Key words for use in RFCs to Indicate Requirement Levels</title>
            <author fullname="S. Bradner"/>
            <date month="March" year="1997"/>
          </front>
          <seriesInfo name="BCP" value="14"/>
          <seriesInfo name="RFC" value="2119"/>
          <seriesInfo name="DOI" value="10.17487/RFC2119"/>
        </reference>
        <reference anchor="RFC8174">
          <front>
            <title>Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words</title>
            <author fullname="B. Leiba"/>
            <date month="May" year="2017"/>
          </front>
          <seriesInfo name="BCP" value="14"/>
          <seriesInfo name="RFC" value="8174"/>
          <seriesInfo name="DOI" value="10.17487/RFC8174"/>
        </reference>
        <reference anchor="RFC9396">
          <front>
            <title>OAuth 2.0 Rich Authorization Requests</title>
            <author fullname="T. Lodderstedt"/>
            <author fullname="J. Richer"/>
            <author fullname="B. Campbell"/>
            <date month="September" year="2023"/>
          </front>
          <seriesInfo name="RFC" value="9396"/>
          <seriesInfo name="DOI" value="10.17487/RFC9396"/>
        </reference>
        <reference anchor="RFC9728">
          <front>
            <title>OAuth 2.0 Protected Resource Metadata</title>
            <author fullname="M. Jones"/>
            <author fullname="T. Lodderstedt"/>
            <date month="October" year="2024"/>
          </front>
          <seriesInfo name="RFC" value="9728"/>
          <seriesInfo name="DOI" value="10.17487/RFC9728"/>
        </reference>
      </references>
      <references>
        <name>Informative References</name>
        <reference anchor="GAL" target="https://github.com/wjatx/ptc-gal-standards/blob/main/GAL-SPEC.md">
          <front>
            <title>GAL: Grant &amp; Autonomy Lifecycle, Specification</title>
            <author fullname="W. Jackson"/>
            <date year="2026"/>
          </front>
          <refcontent>version 0.2.9-draft</refcontent>
        </reference>
        <reference anchor="PTC" target="https://github.com/wjatx/ptc-gal-standards/blob/main/PTC-SPEC.md">
          <front>
            <title>PTC: Provenance &amp; Trust Context, Specification</title>
            <author fullname="W. Jackson"/>
            <date year="2026"/>
          </front>
          <refcontent>version 0.2.7-draft</refcontent>
        </reference>
        <reference anchor="RI" target="https://github.com/wjatx/ptc-gal-reference">
          <front>
            <title>ptc-gal-reference</title>
            <author>
              <organization>wjatx</organization>
            </author>
          </front>
          <refcontent>Public reference implementation of GAL and PTC; the code this document's rules are drawn from</refcontent>
        </reference>
        <reference anchor="DELEGATION-CHAIN">
          <front>
            <title>Verifiable Attenuated Delegation Chains for AI Agents</title>
            <author fullname="R. Asor"/>
          </front>
          <seriesInfo name="Internet-Draft" value="draft-asor-wimse-agent-delegation-chain-01"/>
        </reference>
        <reference anchor="CONNECTED-FLIGHT">
          <front>
            <title>Zero Trust Fabric Layer Agent-to-Agent Chained Trust on a Connected Flight</title>
            <author fullname="E. Seymour"/>
            <date day="26" month="September" year="2026"/>
          </front>
          <seriesInfo name="Internet-Draft" value="draft-seymour-wimse-connected-flight-05"/>
        </reference>
        <reference anchor="AEB">
          <front>
            <title>The Action Evidence Boundary for Consequential Agent Effects</title>
            <author fullname="I. Schrock"/>
            <date day="25" month="September" year="2026"/>
          </front>
          <seriesInfo name="Internet-Draft" value="draft-schrock-action-evidence-boundary-07"/>
        </reference>
        <reference anchor="CAID">
          <front>
            <title>The Canonical Action Identifier (CAID)</title>
            <author fullname="I. Schrock"/>
            <date day="28" month="September" year="2026"/>
          </front>
          <seriesInfo name="Internet-Draft" value="draft-schrock-canonical-action-identifier-04"/>
        </reference>
        <reference anchor="RFC6750">
          <front>
            <title>The OAuth 2.0 Authorization Framework: Bearer Token Usage</title>
            <author fullname="M. Jones"/>
            <author fullname="D. Hardt"/>
            <date month="October" year="2012"/>
          </front>
          <seriesInfo name="RFC" value="6750"/>
          <seriesInfo name="DOI" value="10.17487/RFC6750"/>
        </reference>
      </references>
    </references>
    <section anchor="acknowledgements" numbered="false" toc="default">
      <name>Acknowledgements</name>
      <t>Theo Adam contributed the test vector for the consumption rule and
      the argument that the authority a call runs under belongs in the
      frozen call, and separated closure of an authorization instance from
      the outcome of its execution. Iman Schrock raised the terminal
      meaning of rejection, the comparison basis for "as presented", and
      the three-way split of key bootstrapping. Girish Konda raised what a
      refused caller is told and the collision between refusal and
      rejection.</t>
      <t>This document was prepared with AI assistance for drafting, source
      verification and editorial review. The technical positions are the
      author's.</t>
    </section>
  </back>
</rfc>
