<?xml version="1.0" encoding="UTF-8"?>
<rfc docName="draft-nelson-agent-delegation-receipts-07"
     ipr="trust200902"
     submissionType="independent"
     category="info"
     xml:lang="en"
     version="3">

  <front>
    <title abbrev="Agent Delegation Receipts">Delegation Receipt Protocol for AI Agent Authorization</title>

    <author fullname="Ryan Nelson" initials="R." surname="Nelson">
      <organization>Authproof</organization>
      <address>
        <postal>
          <city>Clinton</city>
          <region>Oklahoma</region>
          <country>United States of America</country>
        </postal>
        <email>ryan@authproof.dev</email>
        <uri>https://authproof.dev</uri>
      </address>
    </author>

    <date day="13" month="May" year="2026"/>

    <area>Security</area>
    <workgroup>Network Working Group</workgroup>

    <keyword>AI agent</keyword>
    <keyword>delegation</keyword>
    <keyword>authorization</keyword>
    <keyword>receipt</keyword>
    <keyword>cryptographic</keyword>
    <keyword>append-only log</keyword>

    <abstract>
      <t>This document defines the Delegation Receipt Protocol (DRP), a
      cryptographic authorization primitive for AI agent deployments.
      Before any agent action executes, the authorizing user signs an
      Authorization Object containing scope boundaries, time window,
      operator instruction hash, and model state commitment.  This signed
      receipt is published to an append-only log before the agent runtime
      receives control.  The protocol removes the operator as a trusted
      third party by making the user's private key the sole signing
      authority over the delegation record.</t>
    </abstract>
  </front>

  <middle>

    <section anchor="intro" numbered="true" toc="default">
      <name>Introduction</name>
      <t>Agentic AI systems execute actions on behalf of human principals
      using natural language instructions as their primary authorization
      artifact.  This creates a structural gap between the authorization a
      user believes they granted and the instructions an operator delivers
      to the agent at runtime.  No existing cryptographic mechanism makes
      that gap detectable.</t>

      <t>This document specifies the Delegation Receipt Protocol (DRP), a
      cryptographic authorization primitive that addresses this gap.  DRP
      requires every agent action to be preceded by a user-signed
      Authorization Object -- the Delegation Receipt -- anchored to a
      tamper-evident append-only log.  The receipt commits the user's
      authorized scope, operational boundaries, validity window, and a
      cryptographic hash of the operator's stated instructions.  Any
      deviation by the operator from those instructions is provable from
      the public log without additional trust assumptions.</t>

      <t>DRP is not a replacement for existing IETF agent authorization work.
      WIMSE, AIP, and OAuth 2.0 Token Exchange <xref target="RFC8693"/> address service-
      to-agent trust.  DRP addresses the upstream layer: user-to-operator
      trust.  In a complete agentic trust stack, these layers are
      complementary.</t>

      <t>A reference implementation of this protocol is available as an
      open-source SDK at https://github.com/Commonguy25/authproof-sdk
      under the MIT License.  A hosted service implementing the protocol
      is available at https://cloud.authproof.dev with a free tier
      requiring no credit card.</t>

      <section anchor="novel-contributions" numbered="true" toc="default">
        <name>Novel Contributions</name>
        <t>This document introduces three cryptographic primitives that do not
        appear in existing agent authorization frameworks or IETF drafts:</t>

        <t><strong>Model State Attestation (<xref target="model-state-attestation"/>):</strong></t>
        <t>The delegation receipt is bound to a cryptographic measurement
        of the model state at authorization time.  If the operator
        substitutes a different model after the user signs the receipt,
        the measurement changes and execution is blocked.  This closes
        the operator model substitution attack vector that existing
        frameworks do not address.  The protocol distinguishes between
        malicious substitution (always blocked) and provider updates
        (requires reauthorization) using the ProviderUpdate vs
        MaliciousSubstitution classification defined in <xref target="malicious-substitution-detection"/>.</t>

        <t><strong>Scope Discovery Protocol (<xref target="scope-discovery"/>):</strong></t>
        <t>Before authorization, the agent runs in a sandboxed observation
        mode with no real resource access.  It simulates the intended
        task and records every resource it attempts to access.  This
        produces a draft ScopeSchema grounded in actual agent behavior
        rather than operator-specified assumptions.  The user reviews a
        plain-language summary and signs only what they explicitly
        approve.  This closes the upstream design-time gap where users
        cannot accurately specify scope before understanding agent
        behavior.</t>

        <t><strong>Session State and Adaptive Authorization (<xref target="session-state"/>):</strong></t>
        <t>A continuously updated trust score tracks behavioral anomalies
        across the session lifetime.  Trust decays on anomaly detection
        and recovers slowly on clean behavior.  Decision thresholds
        tighten automatically as trust degrades.  Sessions suspend when
        trust falls below a configurable floor, requiring explicit user
        reauthorization.  This extends the static pre-execution
        authorization model to cover dynamic session-level risk that
        cannot be captured at delegation time.</t>
      </section>
    </section>

    <section anchor="terminology" numbered="true" toc="default">
      <name>Terminology</name>
      <t>The key words "<strong>MUST</strong>", "<strong>MUST NOT</strong>",
      "<strong>REQUIRED</strong>", "<strong>SHALL</strong>",
      "<strong>SHALL NOT</strong>", "<strong>SHOULD</strong>",
      "<strong>SHOULD NOT</strong>", "<strong>RECOMMENDED</strong>",
      "<strong>NOT RECOMMENDED</strong>", "<strong>MAY</strong>", and
      "<strong>OPTIONAL</strong>" 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>The following terms are used throughout this document:</t>

      <dl newline="true" spacing="normal">
        <dt>Delegation Receipt:</dt>
        <dd>A signed Authorization Object produced by the User prior to any
        agent action.  Contains scope, boundaries, time window, and
        operator instruction hash.  <strong>MUST</strong> be anchored to an append-only log
        before the agent runtime receives control.</dd>

        <dt>Authorization Object:</dt>
        <dd>The canonical JSON body that is signed to produce a Delegation
        Receipt.  The receipt ID is the SHA-256 hash of this body in its
        canonical serialization.</dd>

        <dt>User:</dt>
        <dd>The human principal whose resources and authority are being
        delegated.  The User's private key is the sole signing authority
        for Delegation Receipts.</dd>

        <dt>Operator:</dt>
        <dd>The developer or organization that builds and deploys the agent.
        The Operator provides instructions to the agent and is bound by
        the instruction hash committed in the receipt.</dd>

        <dt>Agent:</dt>
        <dd>The AI system taking actions on behalf of the User.  The Agent
        <strong>MUST</strong> verify a valid Delegation Receipt before executing any
        action.</dd>

        <dt>Append-Only Log:</dt>
        <dd>A tamper-evident ledger to which Delegation Receipts are anchored
        prior to execution.  Implementations <strong>SHOULD</strong> use a decentralized
        transparency log following the Certificate Transparency model.</dd>

        <dt>Log Anchor:</dt>
        <dd>An inclusion proof returned by the append-only log after a receipt
        is submitted.  The log anchor establishes the authoritative
        issuance timestamp.</dd>

        <dt>Scope:</dt>
        <dd>An explicit allowlist of permitted operations embedded in a
        Delegation Receipt.  Operations are classified as reads, writes,
        deletes, or executes.  All operations not listed are denied by
        default.</dd>

        <dt>Boundaries:</dt>
        <dd>Explicit prohibitions embedded in a Delegation Receipt that
        survive any subsequent Operator instruction.  Boundaries <strong>MUST NOT</strong>
        be waived or overridden by the Operator.</dd>

        <dt>Instruction Hash:</dt>
        <dd>The SHA-256 hash of the Operator's stated instructions at
        delegation time.  Any change to the Operator's instructions after
        receipt issuance is detectable by recomputing this hash.</dd>

        <dt>Micro-Receipt:</dt>
        <dd>A minimal Delegation Receipt covering a single action not included
        in the parent receipt's scope.  <strong>MUST</strong> reference the parent receipt
        hash.</dd>

        <dt>Model State Commitment:</dt>
        <dd>A cryptographic measurement binding a specific model identity,
        version, system prompt hash, and runtime configuration hash to a
        Delegation Receipt.</dd>

        <dt>Scope Discovery:</dt>
        <dd>A protocol that derives authorized scope from sandboxed
        observation of agent behavior rather than upfront user
        specification.</dd>

        <dt>Session State:</dt>
        <dd>A live, stateful risk evaluation layer that tracks trust decay,
        sensitivity classification, and behavioral anomalies across the
        lifetime of an agent session.</dd>
      </dl>
    </section>

    <section anchor="problem-statement" numbered="true" toc="default">
      <name>Problem Statement</name>

      <section anchor="agentic-delegation-chain" numbered="true" toc="default">
        <name>The Agentic Delegation Chain</name>
        <t>Agentic AI systems involve at minimum three principals:</t>
        <ul spacing="normal">
          <li>User -- the human whose resources and authority are delegated.</li>
          <li>Operator -- the developer or company that builds and deploys the agent.</li>
          <li>Agent -- the AI system taking actions on the User's behalf.</li>
        </ul>
        <t>The delegation chain is:</t>
        <artwork name="" type="" align="left" alt=""><![CDATA[
   User --> Operator --> Agent --> Services
]]></artwork>
        <t>The User grants authority to the Operator.  The Operator translates
        that authority into instructions for the Agent.  The Agent acts on
        downstream services.  At each step, fidelity to the User's original
        intent depends entirely on the honesty and competence of the
        intermediate party.</t>
      </section>

      <section anchor="missing-cryptographic-anchor" numbered="true" toc="default">
        <name>The Missing Cryptographic Anchor</name>
        <t>In current agentic deployments, the User's authorization is captured
        in natural language -- a chat message, a consent checkbox, a terms-
        of-service agreement.  None of these produce a cryptographically
        verifiable record of what the User actually authorized at the moment
        of delegation.</t>

        <t>This creates three compounding problems:</t>

        <dl newline="true" spacing="normal">
          <dt>The repudiation problem:</dt>
          <dd>If an agent takes an action the User did
          not authorize, there is no cryptographic evidence of what the User
          did authorize.  The Operator's account of the authorization is the
          only record, and it is unverifiable.</dd>

          <dt>The drift problem:</dt>
          <dd>Operators may update system prompts, change agent
          behavior, or respond to external pressure in ways that diverge
          from the User's original authorization.  Nothing in the current
          architecture makes this divergence detectable.</dd>

          <dt>The audit problem:</dt>
          <dd>Regulators auditing agentic behavior have no
          evidence chain connecting agent actions to original user consent.
          The Operator's logs are the only source of truth, controlled by
          the party whose conduct is under scrutiny.</dd>
        </dl>
      </section>

      <section anchor="ietf-framework-analysis" numbered="true" toc="default">
        <name>IETF Framework Analysis</name>
        <t>Several IETF working groups have produced or are producing
        specifications for agent identity and authorization.  Each addresses
        a different trust boundary; none addresses user-to-operator trust.</t>

        <t>WIMSE (Workload Identity in Multi-System Environments) addresses
        service-to-service authentication: can service B verify that a
        request came from legitimate workload A?  It does not address whether
        the workload was authorized by the User to make that request in the
        first place.</t>

        <t>AIP (Agent Identity Protocol) defines credential structures for agent
        principals and addresses how agents present identity to services they
        call.  Like WIMSE, its trust model is downstream of the Operator --
        it assumes the Operator has correctly represented the User's
        authorization.</t>

        <t>draft-klrc-aiagent-auth addresses OAuth-style authorization flows for
        AI agents, allowing agents to obtain access tokens for downstream
        APIs.  It solves the service authorization problem -- whether the
        agent can call an API -- but not the delegation integrity problem --
        whether the Operator's instructions faithfully represent the User's
        authorization.</t>

        <t>OAuth 2.0 Token Exchange <xref target="RFC8693"/> and Rich Authorization Requests
        <xref target="RFC9396"/> provide mechanisms for scoped token issuance and delegation
        chains between services but operate at the service layer.  The User's
        intent is represented by the OAuth grant, which is under Operator
        control.</t>

        <t>The gap is consistent across all existing frameworks: user-to-
        operator trust is taken as a precondition.  DRP addresses that
        precondition directly.</t>
      </section>
    </section>

    <section anchor="delegation-receipt" numbered="true" toc="default">
      <name>The Delegation Receipt</name>

      <section anchor="receipt-structure" numbered="true" toc="default">
        <name>Receipt Structure</name>
        <t>A Delegation Receipt is a JSON object with the following <strong>REQUIRED</strong>
        fields:</t>

        <dl newline="true" spacing="normal">
          <dt><tt>delegationId</tt>:</dt>
          <dd>The SHA-256 hash of the canonical serialization of the
          Authorization Object body (all fields except <tt>delegationId</tt> and
          <tt>signature</tt>).  Encoded as the string <tt>"sha256:"</tt> followed by the
          lowercase hex digest.</dd>

          <dt><tt>version</tt>:</dt>
          <dd>Protocol version string.  This document defines version <tt>"1"</tt>.</dd>

          <dt><tt>scope</tt>:</dt>
          <dd>An object with four keys: <tt>"reads"</tt>, <tt>"writes"</tt>, <tt>"deletes"</tt>, and
          <tt>"executes"</tt>, each containing an array of permitted
          <tt>resource:operation</tt> strings.  The <tt>"executes"</tt> array <strong>MUST</strong> contain
          SHA-256 hashes of the static capability DAG of each authorized
          program; program names or URIs <strong>MUST NOT</strong> be used in the <tt>"executes"</tt>
          array.  Natural language <strong>MUST NOT</strong> appear in any scope field.</dd>

          <dt><tt>boundaries</tt>:</dt>
          <dd>An array of prohibition strings that <strong>MUST</strong> be enforced regardless
          of Operator instruction.  The array <strong>MUST NOT</strong> be empty;
          implementations with no explicit prohibitions <strong>SHOULD</strong> populate a
          conservative default.</dd>

          <dt><tt>timeWindow</tt>:</dt>
          <dd>An object with <tt>"notBefore"</tt> and <tt>"notAfter"</tt> fields, each an ISO 8601
          timestamp.  The authoritative time reference is the log timestamp
          (see <xref target="timestamp-authority"/>), not the client clock.</dd>

          <dt><tt>instructionHash</tt>:</dt>
          <dd>The SHA-256 hash of the Operator's stated instructions at
          delegation time, encoded as <tt>"sha256:"</tt> followed by the lowercase
          hex digest.</dd>

          <dt><tt>operatorInstructions</tt>:</dt>
          <dd>The plaintext instruction string whose SHA-256 hash is recorded in
          <tt>instructionHash</tt>.</dd>

          <dt><tt>signerPublicKey</tt>:</dt>
          <dd>The User's public key as a JSON Web Key <xref target="RFC7517"/>.
          Implementations <strong>SHOULD</strong> use ECDSA P-256 (<tt>crv: "P-256"</tt>) <xref target="RFC7518"/>
          keys.</dd>

          <dt><tt>signature</tt>:</dt>
          <dd>The ECDSA P-256 signature over the canonical serialization of the
          Authorization Object body, encoded as base64url.</dd>
        </dl>

        <t>The following <strong>OPTIONAL</strong> fields are defined by this document:</t>

        <dl newline="true" spacing="normal">
          <dt><tt>teeMeasurement</tt>:</dt>
          <dd>Model state commitment object binding the receipt to a specific
          TEE enclave measurement.  See <xref target="model-state-attestation"/>.</dd>

          <dt><tt>scopeSchema</tt>:</dt>
          <dd>Machine-readable structured allowlist and denylist derived from
          the Scope Discovery Protocol.  See <xref target="scope-discovery"/>.</dd>
        </dl>

        <t>The complete structure is illustrated below:</t>

        <artwork name="" type="json" align="left" alt=""><![CDATA[
{
  "delegationId":  "<sha256-of-canonical-body>",
  "version":       "1",
  "scope": {
    "reads":    ["<resource>:<operation>"],
    "writes":   ["<resource>:<operation>"],
    "deletes":  ["<resource>:<operation>"],
    "executes": ["sha256:<capability-dag-hash>"]
  },
  "boundaries": ["<prohibition-string>"],
  "timeWindow": {
    "notBefore": "<ISO-8601-timestamp>",
    "notAfter":  "<ISO-8601-timestamp>"
  },
  "instructionHash":      "sha256:<hex-digest>",
  "operatorInstructions": "<operator-instruction-text>",
  "signerPublicKey":      { "<JWK per RFC 7517>" },
  "signature":            "<base64url-ecdsa-p256-signature>"
}
]]></artwork>
      </section>

      <section anchor="canonical-serialization" numbered="true" toc="default">
        <name>Canonical Serialization</name>
        <t>The canonical serialization of a receipt body is defined as follows:</t>
        <ol spacing="normal" type="1">
          <li>Serialize the Authorization Object as JSON with keys sorted in
          lexicographic ascending order at every nesting level.</li>
          <li>Remove all insignificant whitespace (no spaces, no newlines
          outside of string values).</li>
          <li>Encode the result as UTF-8.</li>
        </ol>

        <t>The <tt>delegationId</tt> is computed as:</t>
        <artwork name="" type="" align="left" alt=""><![CDATA[
delegationId = "sha256:" ||
               lowercase_hex(SHA-256(canonical_body))
]]></artwork>

        <t>Implementations <strong>MUST</strong> compute the <tt>delegationId</tt> over the body before
        the signature field is added.  The signature field <strong>MUST NOT</strong> be
        included in the data that is signed.</t>
      </section>

      <section anchor="signing-procedure" numbered="true" toc="default">
        <name>Signing Procedure</name>
        <t>Receipt issuance <strong>MUST</strong> follow this sequence:</t>
        <ol spacing="normal" type="1">
          <li>The Operator presents their intended instructions to the User,
          along with the proposed scope, boundaries, and time window.</li>
          <li>The User reviews the scope, boundaries, time window, and Operator
          instructions.</li>
          <li>The User signs the canonical Authorization Object body using
          their private key via the WebAuthn/FIDO2 API <xref target="W3C-WebAuthn"/>
          <xref target="FIDO2"/>.  Hardware key custody (Trusted Platform Module or device
          secure enclave) is <strong>RECOMMENDED</strong>.</li>
          <li>The signed receipt is submitted to a decentralized append-only
          log.</li>
          <li>The log assigns a timestamp and returns a log anchor (inclusion
          proof).</li>
          <li>No agent action <strong>MAY</strong> begin until the log anchor is confirmed.</li>
        </ol>

        <t>The log timestamp established in step 5 is the authoritative issuance
        time.  Client clocks <strong>MUST NOT</strong> be used as the time reference for
        receipt validation.</t>
      </section>
    </section>

    <section anchor="append-only-log" numbered="true" toc="default">
      <name>The Append-Only Log</name>

      <section anchor="log-entry-structure" numbered="true" toc="default">
        <name>Log Entry Structure</name>
        <t>Each entry in the append-only log <strong>MUST</strong> contain:</t>
        <ul spacing="normal">
          <li>The Delegation Receipt hash (<tt>delegationId</tt>).</li>
          <li>The SHA-256 hash of the preceding log entry (for chain linking;
          see <xref target="chain-linking"/>).</li>
          <li>A trusted timestamp conforming to <xref target="RFC3161"/>.</li>
          <li>The submitter's public key hash.</li>
          <li>A monotonically increasing entry sequence number.</li>
        </ul>

        <t>Implementations <strong>SHOULD</strong> use a log format compatible with Certificate
        Transparency <xref target="RFC6962"/> to enable standard log consistency
        verification.</t>

        <t>Action log entries produced during agent execution follow the same
        structure.  Each action log entry <strong>MUST</strong> include:</t>
        <ul spacing="normal">
          <li>The receipt hash authorizing the action.</li>
          <li>The action type, payload hash, and destination.</li>
          <li>The SHA-256 hash of the preceding action log entry.</li>
          <li>An RFC 3161 timestamp and the agent's ECDSA P-256 signature over
          the entry body.</li>
        </ul>
      </section>

      <section anchor="chain-linking" numbered="true" toc="default">
        <name>Chain Linking</name>
        <t>Each log entry <strong>MUST</strong> include the SHA-256 hash of the immediately
        preceding entry.  This chain structure guarantees:</t>
        <ol spacing="normal" type="1">
          <li>Log entries cannot be inserted retroactively without producing a
          detectable chain break.</li>
          <li>Log entries cannot be deleted without invalidating the chain hash
          of the subsequent entry.</li>
          <li>Any two parties holding the same entry hash can verify
          independently that they share the same log view up to that entry.</li>
        </ol>
        <t>The chain structure makes it impossible to insert or delete
        individual action records without producing a detectable
        inconsistency that any log monitor can identify.</t>
      </section>

      <section anchor="timestamp-authority" numbered="true" toc="default">
        <name>Timestamp Authority</name>
        <t>Implementations <strong>MUST</strong> use an RFC 3161 <xref target="RFC3161"/> Time-Stamp Authority
        (TSA) to produce the authoritative timestamp for each Delegation
        Receipt anchored to the log.  The TSA timestamp:</t>
        <ol spacing="normal" type="1">
          <li>Establishes the authoritative <tt>notBefore</tt> time for the associated
          Delegation Receipt.</li>
          <li>Is used in lieu of the client clock for all time window
          validation (see <xref target="verification-checks"/>).</li>
          <li>Is included in the log anchor returned to the submitter.</li>
        </ol>

        <t>If the TSA is unreachable, implementations <strong>MAY</strong> record a local-clock
        timestamp marked <tt>"UNVERIFIED_TIMESTAMP"</tt>.  An agent verifier <strong>MUST</strong>
        treat <tt>UNVERIFIED_TIMESTAMP</tt> as insufficient evidence of authorization
        time in production deployments.</t>
      </section>

      <section anchor="denied-call-logging" numbered="true" toc="default">
        <name>Denied Call Logging</name>
        <t>Implementations <strong>MUST</strong> log all verification decisions including
        those that result in a DENY outcome.  Logging only PERMIT
        decisions creates a blind spot for detecting prompt injection
        and model drift.</t>

        <t>The distribution of denied calls over time is a leading
        indicator of adversarial activity.  A model being prompt-
        injected will generate denied calls with novel action classes
        and scope edge probing that differs detectably from normal
        operation.  Post-hoc analysis of the deny path is the primary
        forensic signal for incident reconstruction.</t>

        <t>Denied call log entries <strong>MUST</strong> include the full call context,
        the specific denial reason code, and the session risk score
        at the time of denial.  Implementations <strong>SHOULD</strong> expose denied
        call distribution analytics to enable real-time anomaly
        detection.</t>
      </section>
    </section>

    <section anchor="pre-execution-verification" numbered="true" toc="default">
      <name>Pre-Execution Verification</name>

      <section anchor="verification-checks" numbered="true" toc="default">
        <name>Verification Checks</name>
        <t>Before executing any action, the Agent <strong>MUST</strong> perform all of the
        following checks in order.  All checks <strong>MUST</strong> pass; any single failure
        <strong>MUST</strong> abort the action without partial execution.</t>

        <t>The complete verification procedure is:</t>
        <artwork name="" type="" align="left" alt=""><![CDATA[
Verify(receipt, action):
  (1) if Revoked(receipt.delegationId)
                                      -> fail
  (2) if not VerifySig(receipt.signature,
                       canonical(receipt.body),
                       receipt.signerPublicKey)
                                      -> fail
  (3) if not InTimeWindow(receipt.timeWindow,
                          logTimestamp)
                                      -> fail
  (4) if not InScope(action, receipt.scope)
                                      -> fail
  (5) if ViolatesBoundary(action, receipt.boundaries)
                                      -> fail
  (6) if action.type == EXECUTE and
         Hash(SafescriptDAG(program))
         != receipt.scope.executes[n]
                                      -> fail
  (7) if Hash(currentOperatorInstructions)
         != receipt.instructionHash
                                      -> fail
  return true
]]></artwork>

        <t>The revocation pre-check (step 1) <strong>MUST</strong> be performed before any other
        check.  A revoked receipt <strong>MUST</strong> fail immediately regardless of whether
        other checks would pass.</t>
      </section>

      <section anchor="check-ordering" numbered="true" toc="default">
        <name>Check Ordering</name>
        <t>The check ordering reflects distinct security properties; each step
        eliminates a distinct attack surface.</t>

        <dl newline="true" spacing="normal">
          <dt>Revocation check (1):</dt>
          <dd>Ensures a receipt explicitly invalidated by
          the User cannot authorize further actions, regardless of its
          cryptographic validity.</dd>

          <dt>Signature check (2):</dt>
          <dd>Confirms the receipt was signed by the holder
          of the User's private key and has not been altered since signing.
          Any tampering with the receipt body invalidates the signature
          under ECDSA P-256.</dd>

          <dt>Time window check (3):</dt>
          <dd>Validates the action against the log-assigned
          TSA timestamp, not the client clock.  Prevents time manipulation
          attacks in which an agent extends its own authorization window by
          adjusting local time.</dd>

          <dt>Scope check (4):</dt>
          <dd>Enforces the deny-by-default allowlist.  If the
          action is not explicitly listed, it <strong>MUST</strong> fail regardless of
          Operator instruction.</dd>

          <dt>Boundary check (5):</dt>
          <dd>Enforces the User's hard limits, which survive
          any subsequent Operator instruction or override.</dd>

          <dt>Execution hash check (6):</dt>
          <dd>Computes the static capability signature
          of the actual program the agent has been given and compares it to
          the hash committed in the <tt>"executes"</tt> scope field.  Substituting a
          different program after the receipt is signed is detectable
          without runtime introspection.</dd>

          <dt>Instruction hash check (7):</dt>
          <dd>Compares the SHA-256 hash of the
          Operator's current instructions against the hash committed at
          delegation time.  If the Operator has changed its instructions
          since the receipt was issued, the mismatch is immediately
          detectable from the log entry, with no reliance on the Operator's
          own account.</dd>
        </dl>
      </section>

      <section anchor="failure-handling" numbered="true" toc="default">
        <name>Failure Handling</name>
        <t>When any verification check fails, the Agent <strong>MUST</strong>:</t>
        <ol spacing="normal" type="1">
          <li>Abort the action immediately.  No partial execution is permitted.</li>
          <li>Record the failure in the action log, including the specific
          check that failed and the reason string.</li>
          <li>Not fall back to Operator instruction.  A failed verification
          check <strong>MUST NOT</strong> be overridden by any runtime parameter,
          environment variable, or Operator-supplied flag.</li>
          <li>Surface the failure to the User when the failing check is one of:
          revocation (1), instruction hash mismatch (7), or execution hash
          mismatch (6).  These failures indicate possible Operator
          deviation from the committed authorization and <strong>SHOULD</strong> be
          escalated.</li>
        </ol>

        <t>When a scope check (4) fails because an action is outside the current
        receipt's scope, the Agent <strong>MAY</strong> pause execution and request a Micro-
        Receipt from the User covering the specific action.  The Micro-
        Receipt <strong>MUST</strong> reference the parent receipt hash and <strong>MUST</strong> be anchored
        to the append-only log before the action is attempted.</t>

        <t>Implementations <strong>MUST</strong> always make a safe fallback action available
        when execution is blocked.  The designated safe fallback action is
        <tt>NO_OP_WITH_LOG</tt>: it performs no operation and writes a full audit log
        entry containing the denial reason, a snapshot of the session state
        at the time of denial, and a timestamp.  <tt>NO_OP_WITH_LOG</tt> is
        unconditionally available regardless of verification state or session
        trust level.  Every DENY decision returned by the gate <strong>MUST</strong> include a
        <tt>safeAlternative</tt> field set to <tt>NO_OP_WITH_LOG</tt>, providing callers with a
        guaranteed safe path that preserves the audit record without
        executing any agent action.</t>
      </section>

      <section anchor="verification-algorithm" numbered="true" toc="default">
        <name>Verification Algorithm</name>
        <t>The following pseudocode specifies the complete seven-check
        verification algorithm as a formal function:</t>
        <artwork name="" type="" align="left" alt=""><![CDATA[
FUNCTION VerifyReceipt(receipt, action, operatorInstructions,
                       sessionState):

  INPUT:
    receipt             : signed delegation receipt object
    action              : the agent action being requested
    operatorInstructions: current operator instruction string
    sessionState        : current session state object (optional)

  OUTPUT:
    PERMIT or DENY with reason code

  CHECK 1: Signature Verification
    IF NOT VerifySignature(receipt.signature,
                           receipt.canonicalPayload,
                           receipt.publicKey) THEN
      RETURN DENY, "INVALID_SIGNATURE"

  CHECK 2: Revocation Status
    IF revocationRegistry.isRevoked(receipt.receiptId) THEN
      RETURN DENY, "RECEIPT_REVOKED"

  CHECK 3: Time Window
    IF receipt.expiresAt < NOW() THEN
      RETURN DENY, "RECEIPT_EXPIRED"
    IF receipt.createdAt > NOW() THEN
      RETURN DENY, "RECEIPT_NOT_YET_VALID"

  CHECK 4: Scope Validation
    IF action.operation NOT IN receipt.scope.allowedActions THEN
      RETURN DENY, "ACTION_NOT_IN_SCOPE"
    IF action.operation IN receipt.scope.deniedActions THEN
      RETURN DENY, "ACTION_EXPLICITLY_DENIED"

  CHECK 5: Operator Instruction Hash
    currentHash = SHA-256(canonicalize(operatorInstructions))
    IF currentHash != receipt.operatorInstructionsHash THEN
      RETURN DENY, "OPERATOR_INSTRUCTIONS_MISMATCH"

  CHECK 6: Model State Attestation
    IF receipt.modelCommitment IS PRESENT THEN
      currentMeasurement = measureModelState()
      IF currentMeasurement != receipt.modelCommitment THEN
        IF modelSubstitutionDetected(receipt,
                                     currentMeasurement) THEN
          RETURN DENY, "MALICIOUS_MODEL_SUBSTITUTION"
        ELSE
          RETURN DENY, "PROVIDER_UPDATE_REQUIRES_REAUTH"

  CHECK 7: Session Risk Evaluation (if sessionState present)
    IF sessionState IS PRESENT THEN
      riskResult = evaluateSessionRisk(action, sessionState)
      IF riskResult.decision == "BLOCK" THEN
        RETURN DENY, "SESSION_RISK_THRESHOLD_EXCEEDED"
      IF riskResult.decision == "REQUIRE_APPROVAL" THEN
        RETURN REQUIRE_APPROVAL, riskResult.reasons

  CHECK 8: Tool Schema Integrity (if toolSchemaHash present)
    IF receipt.toolSchemaHash IS PRESENT THEN
      currentHash = SHA-256(canonicalize(currentToolSchema))
      IF currentHash != receipt.toolSchemaHash THEN
        RETURN DENY, "TOOL_SCHEMA_DRIFT"

  RETURN PERMIT

END FUNCTION
]]></artwork>
      </section>

      <section anchor="denial-reason-codes" numbered="true" toc="default">
        <name>Denial Reason Codes</name>
        <t>When <tt>VerifyReceipt</tt> returns DENY, implementations <strong>MUST</strong> include one of
        the following reason codes in the structured failure response:</t>

        <table align="left">
          <thead>
            <tr>
              <th>Reason Code</th>
              <th>Description</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td><tt>INVALID_SIGNATURE</tt></td>
              <td>Receipt signature verification failed</td>
            </tr>
            <tr>
              <td><tt>RECEIPT_REVOKED</tt></td>
              <td>Receipt has been explicitly revoked</td>
            </tr>
            <tr>
              <td><tt>RECEIPT_EXPIRED</tt></td>
              <td>Receipt time window has elapsed</td>
            </tr>
            <tr>
              <td><tt>RECEIPT_NOT_YET_VALID</tt></td>
              <td>Receipt creation time is in the future</td>
            </tr>
            <tr>
              <td><tt>ACTION_NOT_IN_SCOPE</tt></td>
              <td>Requested action not in allow list</td>
            </tr>
            <tr>
              <td><tt>ACTION_EXPLICITLY_DENIED</tt></td>
              <td>Requested action in deny list</td>
            </tr>
            <tr>
              <td><tt>OPERATOR_INSTRUCTIONS_MISMATCH</tt></td>
              <td>Operator instructions hash does not match receipt commitment</td>
            </tr>
            <tr>
              <td><tt>MALICIOUS_MODEL_SUBSTITUTION</tt></td>
              <td>Model identity changed after receipt was signed</td>
            </tr>
            <tr>
              <td><tt>PROVIDER_UPDATE_REQUIRES_REAUTH</tt></td>
              <td>Model version updated by provider; reauthorization required</td>
            </tr>
            <tr>
              <td><tt>SESSION_RISK_THRESHOLD_EXCEEDED</tt></td>
              <td>Session trust score below block threshold</td>
            </tr>
            <tr>
              <td><tt>REPLAY_DETECTED</tt></td>
              <td>Receipt presented more than once concurrently</td>
            </tr>
            <tr>
              <td><tt>TOOL_SCHEMA_DRIFT</tt></td>
              <td>Tool schema hash at execution time does not match hash committed at receipt issuance time.  Tool specification has changed since authorization was granted.</td>
            </tr>
            <tr>
              <td><tt>TAU_SESSION_EXHAUSTED</tt></td>
              <td>Session anomaly capacity exhausted: <tt>tauSession</tt> has fallen to or below <tt>tauMin</tt>.  Execution blocked regardless of <tt>trustScore</tt>.  Not resettable by reauthorization.</td>
            </tr>
          </tbody>
        </table>
      </section>
    </section>

    <section anchor="model-state-attestation" numbered="true" toc="default">
      <name>Model State Attestation</name>

      <section anchor="commitment-binding" numbered="true" toc="default">
        <name>Commitment Binding</name>
        <t>A valid Delegation Receipt proves that a User authorized an Agent to
        act within defined scope.  It does not prove that the model executing
        the receipt is the model the User authorized.  An Operator could
        silently substitute a fine-tuned model variant after the receipt is
        signed; all verification checks would pass because the receipt itself
        is genuine.</t>

        <t>Model State Attestation closes this gap with a two-phase
        cryptographic protocol that binds the receipt to a measurement of
        model state at both delegation time and execution time.</t>

        <t><strong>Phase 1 -- Commitment (at delegation time):</strong></t>

        <t>The Operator commits to the exact model state that will execute.  The
        commitment is a SHA-256 measurement of five components concatenated
        in canonical order:</t>

        <artwork name="" type="" align="left" alt=""><![CDATA[
modelMeasurement = SHA-256(
  normalize(modelId)       ||
  normalize(modelVersion)  ||
  systemPromptHash         ||
  runtimeConfigHash        ||
  receiptHash
)
]]></artwork>

        <t>Including <tt>receiptHash</tt> as the fifth component binds the model
        measurement to the specific delegation.  The same model with the same
        system prompt but a different receipt produces a different
        measurement.  A commitment <strong>MUST NOT</strong> be reused across delegations.</t>

        <t>The commitment is signed by the Operator's ECDSA P-256 key and
        attested by the TEE runtime, producing a sealed artifact that
        includes <tt>modelId</tt>, <tt>modelVersion</tt>, <tt>systemPromptHash</tt>, <tt>runtimeConfigHash</tt>,
        <tt>committedAt</tt>, the Operator's signature, and a TEE attestation quote.</t>

        <t><strong>Phase 2 -- Verification (at execution time):</strong></t>

        <t>Immediately before the agent function executes, the current model
        state is measured using the same five-component computation.  The
        resulting measurement <strong>MUST</strong> equal the committed measurement.  If the
        two measurements differ for any reason, execution <strong>MUST</strong> be blocked
        with a <tt>ModelDriftDetected</tt> error identifying exactly which components
        changed.</t>

        <t>With Model State Attestation in place, the complete verifiable chain
        of accountability is:</t>

        <artwork name="" type="" align="left" alt=""><![CDATA[
   +---------------------------+
   |    Delegation Receipt     |  <-- User signed
   +---------------------------+
              |
   +---------------------------+
   |  Model State Commitment   |  <-- Hardware measured
   +---------------------------+
              |
   +---------------------------+
   |  Execution Attestation    |  <-- TEE verified
   +---------------------------+
              |
   +---------------------------+
   |     Action Log Entry      |  <-- Chain linked
   +---------------------------+
              |
   +---------------------------+
   |    Data Flow Receipt      |  <-- Output policy
   +---------------------------+
]]></artwork>

        <t>An auditor presented with a chain proof can verify each layer
        independently and confirm that a logged action was taken by the model
        the User authorized, acting within the defined scope, under
        conditions unaltered since authorization was granted.</t>
      </section>

      <section anchor="provider-update-handling" numbered="true" toc="default">
        <name>Provider Update Handling</name>
        <t>Hosted model providers may silently update the underlying model
        behind a versioned alias without Operator action.  Treating this
        identically to a deliberate substitution attack is too blunt: it
        would block legitimate executions whenever a provider retires a model
        version, forcing operators to recommit on every provider maintenance
        cycle.</t>

        <t>Model State Attestation distinguishes two categories of measurement
        mismatch:</t>

        <dl newline="true" spacing="normal">
          <dt><tt>MaliciousSubstitution</tt>:</dt>
          <dd><t>The Operator explicitly changed the model identifier, system
          prompt, or runtime configuration after the commitment was signed.
          This <strong>MUST</strong> always be a hard block.  Indicators are any of:</t>
          <ul spacing="normal">
            <li><tt>currentModelId != committedModelId</tt>, OR</li>
            <li><tt>currentSystemPromptHash != committedSystemPromptHash</tt>, OR</li>
            <li><tt>currentRuntimeConfigHash != committedRuntimeConfigHash</tt></li>
          </ul>
          </dd>

          <dt><tt>ProviderUpdate</tt>:</dt>
          <dd><t>The model version changed, but the Operator's configured <tt>modelId</tt>
          is unchanged.  The provider updated the model behind a stable
          alias.  Indicators are all of:</t>
          <ul spacing="normal">
            <li><tt>currentModelId == committedModelId</tt>, AND</li>
            <li><tt>currentModelVersion != committedModelVersion</tt></li>
          </ul>
          </dd>
        </dl>

        <t>Operators declare how provider updates are handled at construction
        time via the <tt>providerUpdatePolicy</tt> field:</t>

        <dl newline="true" spacing="normal">
          <dt><tt>"block"</tt>:</dt>
          <dd>Treat provider updates identically to <tt>MaliciousSubstitution</tt>.  Any
          version change <strong>MUST</strong> block execution immediately.  <strong>RECOMMENDED</strong> when
          strict model pinning is required.</dd>

          <dt><tt>"reauthorize"</tt> (default):</dt>
          <dd>When a provider update is detected, return
          <tt>{ allowed: false, reason: "PROVIDER_UPDATE_DETECTED", requiresReauthorization: true }</tt>
          and block all subsequent executions under this attestation
          instance until the User explicitly acknowledges the change.</dd>
        </dl>

        <t>The <tt>"reauthorize"</tt> policy preserves a recovery path.  The provider
        update is flagged and the system halts, but the cause is identified
        as a non-malicious provider action.  A human <strong>MUST</strong> explicitly invoke
        <tt>reauthorize()</tt> with <tt>userApproval: true</tt> before execution resumes.  This
        is an explicit human-in-the-loop checkpoint; the system <strong>MUST NOT</strong>
        silently resume execution after a provider update.</t>
      </section>

      <section anchor="malicious-substitution-detection" numbered="true" toc="default">
        <name>Malicious Substitution Detection</name>
        <t>The per-component comparison in the Phase 2 verification identifies
        exactly which aspects of model state changed: model identity,
        version, system prompt, or runtime configuration.  This enables
        forensic analysis of how an unauthorized execution occurred.</t>

        <t>The full SHA-256 measurement comparison is performed in addition to
        per-component comparison.  This is redundant given the component
        checks but provides a cryptographic guarantee: even if the component
        comparison logic contains a bug, the measurement comparison will
        detect any state change.</t>

        <t>Model State Attestation proves:</t>
        <ol spacing="normal" type="1">
          <li>Model identity at commitment time.  The Operator committed to a
          specific (<tt>modelId</tt>, <tt>modelVersion</tt>, <tt>systemPromptHash</tt>,
          <tt>runtimeConfigHash</tt>) tuple before execution began.  The ECDSA
          signature and TEE attestation prove this commitment was made
          inside a trusted environment and has not been altered.</li>
          <li>Model state at execution time.  The TEE verification attestation
          proves the measurement was recomputed inside the enclave
          immediately before execution, and that the recomputed measurement
          matched the committed measurement.</li>
          <li>Delegation binding.  The <tt>receiptHash</tt> component ensures the
          commitment is irrevocably bound to the specific delegation.  A
          commitment made under receipt A <strong>MUST NOT</strong> be presented as valid
          under receipt B.</li>
        </ol>

        <t>Model State Attestation does not prove that the committed model is
        safe, aligned, or correctly configured.  It does not inspect the
        content of the system prompt.  In simulation mode (the default for
        testing), attestations are signed with a software ECDSA key rather
        than produced by real TEE hardware.  Production deployments <strong>SHOULD</strong>
        use Intel SGX, Intel TDX, or ARM TrustZone attestation.</t>
      </section>
    </section>

    <section anchor="scope-discovery" numbered="true" toc="default">
      <name>Scope Discovery Protocol</name>
      <t>The Scope Discovery Protocol addresses the upstream authorization
      gap: a User cannot correctly define agent scope before observing
      agent behavior.  Asking users to define scope upfront produces one of
      two failure modes:</t>

      <dl newline="true" spacing="normal">
        <dt>Over-authorization:</dt>
        <dd>The User grants broad permissions to avoid
        blocking the agent.  The agent is then authorized to perform
        operations the User never intended to permit.</dd>

        <dt>Under-authorization:</dt>
        <dd>The User grants narrow permissions and the
        agent fails mid-task, requiring repeated round-trips to expand
        scope.  Users respond by granting progressively wider permissions
        under frustration.</dd>
      </dl>

      <t>Neither outcome produces a receipt that reflects the User's actual
      intent.  The scope field becomes a legal fiction rather than a
      genuine authorization boundary.</t>

      <t>The Scope Discovery Protocol inverts the authorization sequence.
      Instead of asking Users to define scope before running the agent, it
      runs the agent first in a sandboxed simulation and uses the observed
      behavior to derive the scope definition.</t>

      <t>The protocol proceeds in four stages:</t>

      <dl newline="true" spacing="normal">
        <dt>Stage 1 -- Sandboxed observation:</dt>
        <dd>The agent function is wrapped with transparent proxies for every
        supported resource type (email, calendar, payment, files,
        database, network).  Every operation call is intercepted,
        timestamped, and appended to an observation log.  Mock data
        matching the expected structure is returned so the agent proceeds
        normally.  No real I/O occurs; no side effects are produced.</dd>

        <dt>Stage 2 -- Scope generation:</dt>
        <dd><t>The observation log is analyzed to produce:</t>
        <ol spacing="normal" type="a">
          <li>A <tt>draftScope</tt> with an <tt>allowedActions</tt> list (de-duplicated
          observed operations) and conservative <tt>deniedActions</tt> defaults
          for delete, execute, and payment operations.</li>
          <li>A <tt>plainSummary</tt> in non-technical language suitable for end-user
          review.</li>
          <li><tt>riskFlags</tt> for: delete operations, execute operations, payment
          operations, external send and write operations, and any
          operation called more than 50 times in the observation
          session.</li>
          <li><tt>suggestedDenials</tt> for dangerous operations the agent did not
          use, with per-entry explanations.</li>
        </ol>
        </dd>

        <dt>Stage 3 -- Plain language review:</dt>
        <dd>The Operator or User reviews the plain summary, risk flags, and
        suggested denials before approving.  An <tt>approve()</tt> call accepts
        <tt>"remove"</tt> and <tt>"add"</tt> arrays for surgical modification of the draft
        scope.  This is the moment of genuine human authorization,
        grounded in observed behavior rather than speculation.</dd>

        <dt>Stage 4 -- Cryptographic commitment:</dt>
        <dd>The approved scope is embedded into a Delegation Receipt using the
        standard signing procedure (<xref target="signing-procedure"/>).  The receipt includes a
        <tt>scopeSchema</tt> field with the structured <tt>allowedActions</tt> and
        <tt>deniedActions</tt> lists, and a <tt>discoveryMetadata</tt> field recording
        observation count, any timeout abort, and the risk flags at
        generation time.</dd>
      </dl>

      <t>The receipt produced by Scope Discovery is structurally identical to
      one produced by direct issuance.  It carries all standard fields and
      <strong>MUST</strong> be verifiable by the standard Verify procedure (<xref target="verification-checks"/>)
      without modification.</t>

      <t>The critical property of observation-based scope generation is
      grounding: every entry in <tt>allowedActions</tt> corresponds to an operation
      the agent actually performed during a representative run.  This is a
      structural record of what the agent did, not a user estimate of what
      it might need.</t>

      <t>Grounding has three practical consequences:</t>

      <dl newline="true" spacing="normal">
        <dt>Precision:</dt>
        <dd>The <tt>allowedActions</tt> list contains exactly the resource/
        operation pairs observed.  An agent that reads email but never
        writes it receives a receipt authorizing read on email, not write.</dd>

        <dt>Defensibility:</dt>
        <dd>The <tt>discoveryMetadata.observationCount</tt> and <tt>riskFlags</tt>
        fields provide evidence that scope was derived from observation.
        The audit trail runs from observation to draft to approval to
        receipt.</dd>

        <dt>Ratcheting:</dt>
        <dd>Each time the agent's behavior changes, a new
        observation session produces a new draft.  If the agent begins
        calling a new operation class in a new version, that operation
        surfaces in the risk flags before any receipt is issued for the
        updated agent.  Drift in agent behavior is detectable before it is
        authorized.</dd>
      </dl>

      <t>For operators who trust their agent's observed behavior and do not
      require manual review, a guided mode provides a single-call end-to-
      end flow that runs observe, generate, approve, and finalize
      automatically.  The returned <tt>riskFlags</tt> allow operators to inspect
      what was flagged even when they choose not to gate on it.</t>
    </section>

    <section anchor="session-state" numbered="true" toc="default">
      <name>Session State and Adaptive Authorization</name>
      <t>A Delegation Receipt is a static artifact.  It answers one question
      at one moment in time: did this User authorize this Agent to perform
      this class of actions?  It cannot answer whether a specific action is
      safe to take right now, given everything that has happened in this
      session.</t>

      <t>Static receipts have three blind spots for long-running sessions:</t>

      <dl newline="true" spacing="normal">
        <dt>The drift problem:</dt>
        <dd>A receipt issued for "manage my calendar" remains
        technically valid after the agent has sent 400 emails and received
        a prompt injection payload.  The receipt scope string has not
        changed and cannot reflect runtime events.</dd>

        <dt>The escalation problem:</dt>
        <dd>A receipt with a generous scope becomes
        progressively more dangerous as the agent accumulates sensitive
        data and accesses external services.  Risk is not static -- it
        depends on what came before.</dd>

        <dt>The injection problem:</dt>
        <dd>A receipt cannot detect that the agent's
        input pipeline has been compromised mid-session by a prompt
        injection attack embedded in retrieved content.  The receipt was
        signed before the session began; it has no knowledge of runtime
        inputs.</dd>
      </dl>

      <t><tt>SessionState</tt> closes these gaps by maintaining a live, stateful view
      of each session that evolves with every action.  It tracks a
      <tt>trustScore</tt> for each session, initialized at 100 and bounded between 0
      and 100.</t>

      <t>Three formally distinct quantities govern session risk evaluation.
      Implementations <strong>MUST</strong> maintain all three:</t>

      <dl newline="true" spacing="normal">
        <dt><tt>trustScore</tt>:</dt>
        <dd>A Lyapunov-style bounded recoverable budget.  Initialized at
        100, bounded in [0, 100].  Decremented by <tt>anomaly.severity *
        trustDecayRate</tt> on each anomaly event; incremented by
        <tt>trustRecoveryRate</tt> on each clean action.  The recovery property
        is definitional: <tt>trustScore</tt> is not monotone and is not a load
        functional.  It models a resilience budget that is restored by
        sustained clean behavior.</dd>

        <dt><tt>cumulativeAnomalyMass</tt>:</dt>
        <dd><t>A monotone, non-decreasing quantity tracking the total
        structural burden accumulated over the session lifetime.
        <tt>cumulativeAnomalyMass</tt> has two components:</t>
        <dl newline="true" spacing="normal">
          <dt>Active (anomaly-driven):</dt>
          <dd>Incremented by <tt>anomaly.severity</tt> on
          each detected anomaly event.  Records the discrete burden
          contributed by individual anomaly detections.</dd>
          <dt>Passive (time-driven):</dt>
          <dd>Incremented by <tt>passivePressureRate *
          elapsedSeconds</tt> on each call to the session risk evaluator,
          where <tt>elapsedSeconds</tt> is the time elapsed since the previous
          evaluation.  The default <tt>passivePressureRate</tt> is 0.001 per
          second, yielding 3.6 units of passive burden per session-
          hour and 36 units per ten session-hours, even with zero
          detected anomalies.</dd>
        </dl>
        <t><tt>cumulativeAnomalyMass</tt> is never decremented.  It provides a
        permanent session-level record of total anomaly exposure that
        is not erased by subsequent clean behavior and is available
        for post-session forensic analysis independently of the final
        <tt>trustScore</tt> value.</t>
        </dd>

        <dt><tt>tauSession</tt>:</dt>
        <dd><t>A strictly decreasing capacity gate derived from
        <tt>cumulativeAnomalyMass</tt>:</t>
        <artwork name="" type="" align="left" alt=""><![CDATA[
   tauSession = sessionCapacity - cumulativeAnomalyMass
]]></artwork>
        <t>Initialized to <tt>sessionCapacity</tt> (default: 100).  Never
        recovered.  When <tt>tauSession &lt;= tauMin</tt> (default: 10), the gate
        condition fails and execution <strong>MUST NOT</strong> proceed regardless of
        <tt>trustScore</tt>.  The gate condition is checked before all
        <tt>trustScore</tt>-derived checks in <tt>dynamic_admissible</tt>:</t>
        <artwork name="" type="" align="left" alt=""><![CDATA[
   if tauSession <= tauMin: DENY TAU_SESSION_EXHAUSTED
]]></artwork>
        <t><tt>tauSession</tt> provides a hard lifetime cap on cumulative anomaly
        exposure that is not resettable by reauthorization.  Once a
        session's anomaly capacity is exhausted, the session is
        permanently closed to further execution.</t>
        </dd>
      </dl>

      <t>Trust decays when anomalies are detected:</t>
      <artwork name="" type="" align="left" alt=""><![CDATA[
trustScore -= anomaly.severity * trustDecayRate
]]></artwork>

      <t>Anomaly severity levels are defined as:</t>
      <artwork name="" type="" align="left" alt=""><![CDATA[
Prompt injection detected        : severity 5
Sensitive data in external dest. : severity 4
Frequency spike                  : severity 3
Scope edge usage                 : severity 2
First-time action                : severity 1
]]></artwork>

      <t>Trust recovers slightly on each clean action:</t>
      <artwork name="" type="" align="left" alt=""><![CDATA[
trustScore += trustRecoveryRate  (default: 0.01)
]]></artwork>

      <t>Session status is driven by trust score thresholds:</t>
      <artwork name="" type="" align="left" alt=""><![CDATA[
trustScore >= 30 : ACTIVE    -- normal operation
trustScore <  30 : DEGRADED  -- risk scores amplified
trustScore <  10 : SUSPENDED -- all actions blocked
]]></artwork>

      <t>The DEGRADED state does not block operations directly.  Instead, it
      causes the risk scorer to apply a multiplier to every score, making
      previously marginal decisions tip into REQUIRE_APPROVAL or BLOCK
      territory.</t>

      <t>Before each action, every payload is classified into one of four
      sensitivity levels:</t>
      <artwork name="" type="" align="left" alt=""><![CDATA[
RESTRICTED   : SSN, credit card, medical identifiers, API keys
CONFIDENTIAL : Internal email addresses, system prompts,
               database schemas, config files
INTERNAL     : Company domain references, internal project
               names, user IDs
PUBLIC       : Everything else
]]></artwork>

      <t>Each level modifies the block and approval thresholds:</t>
      <artwork name="" type="" align="left" alt=""><![CDATA[
RESTRICTED   : Block threshold drops to at most 60
CONFIDENTIAL : Approval threshold drops to at most 40
INTERNAL     : No change
PUBLIC       : All thresholds relax by +10
]]></artwork>

      <t>The complete decision engine evaluates five risk checks and maps the
      final score to one of three outcomes:</t>

      <artwork name="" type="" align="left" alt=""><![CDATA[
Check 1 -- Sensitive data scan:
  SSN pattern              +35
  Credit card pattern      +35
  API key pattern          +30
  High-entropy string      +20
  Prompt injection pattern +40
  Password keyword         +25

Check 2 -- External exfiltration:
  External domain + sensitive data  +30
  First-time external domain        +15

Check 3 -- Frequency anomaly:
  Same action type >10x in 60s  +25
  >50 total actions in session  +15

Check 4 -- Scope edge usage:
  New permission class   +10
  At scope boundary      +10

Check 5 -- Trust multiplier:
  finalScore = rawScore * (1 + (100 - trust) / 100)

if session.status == SUSPENDED       --> BLOCK
if finalScore >= blockThreshold      --> BLOCK
if finalScore >= approvalThreshold   --> REQUIRE_APPROVAL
else                                 --> ALLOW
]]></artwork>

      <t>The checks are deterministic and ordered.  The same action, payload,
      and session state always produce the same score.  Every BLOCK or
      REQUIRE_APPROVAL decision <strong>SHOULD</strong> be accompanied by a structured
      reason object identifying which specific checks contributed to the
      score.</t>

      <t><tt>SessionState</tt> <strong>MUST</strong> be integrated with the PreExecutionVerifier as a
      final check, running after all static receipt checks pass (see
      <xref target="verification-checks"/>).  An action that passes all cryptographic checks but
      produces a BLOCK outcome from session risk evaluation <strong>MUST NOT</strong>
      execute.</t>

      <t>The architectural insight is that authorization is not binary.  A
      valid receipt is a necessary condition for execution, not a
      sufficient one.  Real-world safety requires a live, stateful layer
      that observes behavior and adapts its decisions based on the full
      session context.</t>

      <t>The complete executability predicate is formally:</t>
      <artwork name="" type="" align="left" alt=""><![CDATA[
   executable(a, R, session, t) =
     Verify(R, a) AND dynamic_admissible(session, a, t)
]]></artwork>

      <t>where <tt>Verify(R, a)</tt> establishes static receipt admissibility (the
      complete set of <tt>pre(R)</tt> and <tt>admissible(a, R)</tt> checks defined in
      <xref target="security-considerations"/>) and <tt>dynamic_admissible(session, a, t)</tt> establishes
      runtime session admissibility.  <tt>dynamic_admissible</tt> evaluates
      checks in the following order: (1) <tt>tauSession</tt> gate -- if
      <tt>session.tauSession &lt;= tauMin</tt>, DENY <tt>TAU_SESSION_EXHAUSTED</tt>
      immediately; (2) trust score threshold check; (3) sensitivity
      classification; (4) risk score evaluation at time t.  Both the
      <tt>tauSession</tt> gate and the <tt>trustScore</tt> threshold must pass
      independently.  Execution requires both predicates to hold
      simultaneously.  A receipt that passes Verify is a necessary but
      not sufficient condition for execution.</t>
    </section>

    <section anchor="multi-agent-delegation" numbered="true" toc="default">
      <name>Multi-Agent Delegation Chains</name>
      <t>When a delegated Agent needs to hand off a subtask to another Agent,
      the chain of authority <strong>MUST</strong> remain auditable and bounded.  DRP
      enforces three invariants at every delegation hop.</t>

      <section anchor="scope-attenuation" numbered="true" toc="default">
        <name>Scope Attenuation</name>
        <t>Each delegation step <strong>MUST</strong> produce a strict proper subset of the
        parent's authorized scope.  Specifically:</t>
        <ol spacing="normal" type="1">
          <li>Every action the child Agent is permitted <strong>MUST</strong> already appear in
          the parent's <tt>allowedActions</tt> list.  An Agent <strong>MUST NOT</strong> grant
          permissions it was not itself given.</li>
          <li>The child <strong>MUST</strong> have strictly fewer permitted actions than the
          parent.  Equal scope <strong>MUST</strong> be rejected.</li>
          <li>Every action explicitly denied by the parent in <tt>deniedActions</tt>
          <strong>MUST</strong> be carried forward to the child.  A child <strong>MAY</strong> add new denied
          actions but <strong>MUST NOT</strong> remove any denial that the parent
          established.</li>
        </ol>

        <t>The receipt chain <strong>MUST</strong> track delegation depth.  The root receipt,
        signed directly by the User, is at depth 0.  Each delegation
        increments depth by 1.  When a delegation would produce a receipt at
        depth &gt;= <tt>maxDepth</tt>, the implementation <strong>MUST</strong> raise a <tt>MaxDepthExceeded</tt>
        error before creating the receipt.  The default <tt>maxDepth</tt> is 3,
        meaning at most three levels of agent-to-agent hand-off before the
        chain <strong>MUST</strong> be re-anchored at the User level.</t>

        <t>The root receipt <strong>MUST</strong> carry a valid ECDSA P-256 signature from the
        User's key.  If the root could be generated by an Agent or Operator
        without User involvement, the entire chain could be bootstrapped
        unilaterally, defeating the protocol.  Any downstream Agent that
        wants to prove its authority can walk the chain to the root and
        demonstrate a continuous path of scope-narrowing receipts.</t>
      </section>

      <section anchor="cascade-revocation" numbered="true" toc="default">
        <name>Cascade Revocation</name>
        <t>Revocation of a receipt in a multi-agent chain <strong>MAY</strong> or may not cascade
        to child receipts, depending on the revocation call.</t>

        <dl newline="true" spacing="normal">
          <dt>When <tt>cascadeToChildren</tt> is true:</dt>
          <dd>A breadth-first traversal of all descendants <strong>MUST</strong> be performed and
          each descendant marked revoked.  The cascade <strong>SHOULD</strong> be anchored to
          the append-only log before agents are notified, to prevent a race
          condition where a child Agent completes an action between the
          parent revocation and cascade propagation.</dd>

          <dt>When <tt>cascadeToChildren</tt> is false:</dt>
          <dd>Only the named receipt is invalidated.  Its children remain valid
          until explicitly revoked.  This allows surgical removal of one
          Agent from a chain without disrupting sibling branches.</dd>
        </dl>

        <t>Cascade revocation entries <strong>MUST</strong> be signed by the User's private key
        and anchored to the append-only log with the same requirements as the
        original revocation procedure (see <xref target="threat-model"/>).</t>
      </section>
    </section>

    <section anchor="security-considerations" numbered="true" toc="default">
      <name>Security Considerations</name>

      <section anchor="threat-model" numbered="true" toc="default">
        <name>Threat Model</name>
        <t>DRP considers the following adversaries and mitigations:</t>

        <dl newline="true" spacing="normal">
          <dt>Compromised Operator:</dt>
          <dd>An attacker who gains control of the Operator's systems can alter
          the instructions delivered to the Agent.  Under DRP, any
          instruction diverging from the hash committed in the Delegation
          Receipt is immediately detectable at step (7) of Verify.  The
          attacker cannot issue instructions that pass hash verification
          without the User's private key.</dd>

          <dt>Malicious Operator:</dt>
          <dd>An Operator who intentionally instructs the Agent to exceed the
          User's authorization -- under commercial pressure, legal
          compulsion, or bad faith -- produces a detectable instruction hash
          mismatch.  The discrepancy between committed and actual
          instructions is an auditable fact in the append-only log.  The
          Operator cannot alter the log entry and cannot alter the signed
          receipt.</dd>

          <dt>Log Integrity:</dt>
          <dd>The security of the protocol depends on the tamper-evidence of the
          append-only log.  Implementations <strong>SHOULD</strong> use decentralized log
          implementations following the Certificate Transparency model that
          do not depend on a single operator for integrity.  Log fork
          detection follows established approaches from CT ecosystems
          <xref target="RFC6962"/>.</dd>

          <dt>Key Compromise:</dt>
          <dd>If the User's signing key is compromised, an attacker can issue
          Delegation Receipts in the User's name.  Hardware key custody
          using a FIDO2 authenticator <xref target="FIDO2"/> significantly reduces this
          risk by making key extraction technically infeasible on modern
          devices with secure enclaves.</dd>

          <dt>Revocation:</dt>
          <dd><t>When a User wishes to revoke a Delegation Receipt, they <strong>MUST</strong>:</t>
          <ol spacing="normal" type="1">
            <li>Construct a revocation record containing: the SHA-256 hash of
            the original receipt, a reason string, and a revocation
            timestamp.</li>
            <li>Sign the revocation record with the same private key used to
            sign the original receipt.</li>
            <li>Publish the signed revocation record to the append-only log,
            producing an immutable log anchor.</li>
          </ol>
          <t>The log anchor establishes the authoritative revocation time.
          Actions taken before this timestamp under the original receipt
          remain valid.  Actions attempted after this timestamp <strong>MUST</strong> fail.</t>
          <t>Verification <strong>MUST</strong> check revocation before any other check
          (<xref target="verification-checks"/>, step 1).  Because the revocation record is itself
          signed by the User and anchored to the log, it carries the same
          evidentiary weight as the original receipt.  Revocation is
          auditable, tamper-evident, and does not depend on the Operator to
          propagate or acknowledge it.</t>
          </dd>

          <dt>Model Substitution:</dt>
          <dd>An Operator could silently substitute a fine-tuned model variant
          after receipt issuance.  Model State Attestation (<xref target="model-state-attestation"/>)
          closes this gap by binding a cryptographic measurement of the
          model state to the receipt at delegation time and re-verifying
          inside a TEE at execution time.</dd>

          <dt>Micro-Receipt Fatigue:</dt>
          <dd>A malicious Operator could structure a workflow to generate many
          micro-receipt requests in rapid succession, inducing the User to
          approve actions they do not meaningfully review.  This is
          analogous to notification fatigue attacks against MFA prompts.
          The protocol makes every approval a signed, auditable artifact.
          Rate-limiting and UI affordances are the primary mitigation;
          protocol implementations <strong>SHOULD</strong> enforce a minimum inter-request
          interval for micro-receipt prompts.</dd>

          <dt>Non-Repudiation:</dt>
          <dd>Let R be a Delegation Receipt with content C, user signature
          sigma, and log anchor L.  Under the ECDSA P-256 EUF-CMA
          unforgeability assumption, no party without the User's private key
          can produce a valid sigma for any C.  Therefore, the existence of
          a valid receipt on the log is non-repudiable evidence that the
          holder of the private key authorized the content of C at time L.</dd>

          <dt>Authorization Persistence:</dt>
          <dd>Authorization at time t requires both (a) a valid signed receipt
          anchored at time L and (b) the absence of any valid revocation
          record for that receipt anchored at time L' where L' &lt; t.  The
          validity of sigma (established under Non-Repudiation) is a
          necessary but not sufficient condition for continued
          authorization: it proves the receipt was genuinely issued but
          does not establish that it remained unrevoked through time t.
          Non-repudiation and authorization persistence are formally
          distinct results.  The protocol proves both: Non-Repudiation via
          the EUF-CMA unforgeability property of ECDSA P-256, and
          Authorization Persistence via the tamper-evidence property of
          the append-only log applied to both receipt anchors and
          revocation record anchors.</dd>

          <dt>Soundness:</dt>
          <dd><t>Verification decomposes into two independent predicates:</t>
          <artwork name="" type="" align="left" alt=""><![CDATA[
   Verify(R, a) = pre(R) AND admissible(a, R)
]]></artwork>
          <t><tt>pre(R)</tt> holds if and only if: (i) R has not been revoked
          (revocation check); (ii) the signature sigma over the canonical
          body of R is valid under the User's public key (signature
          verification); and (iii) the log timestamp falls within
          <tt>R.timeWindow</tt> (time window validity).</t>
          <t><tt>admissible(a, R)</tt> holds if and only if: (iv) a appears in the
          scope allowlist in C (scope check); (v) a does not violate any
          prohibition in C (boundary check); (vi) if a is an execution
          action, <tt>Hash(SafescriptDAG(program))</tt> equals the hash committed
          in C (execution hash check); (vii) the SHA-256 hash of the
          Operator's current instructions equals <tt>R.instructionHash</tt>
          (instruction hash check); and (viii) if <tt>R.toolSchemaHash</tt> is
          present, the SHA-256 hash of the current tool schema equals
          <tt>R.toolSchemaHash</tt> (tool schema hash check).</t>
          <t>For any action a, <tt>Verify(R, a) = true</tt> if and only if all of
          (i)-(viii) hold simultaneously.  Any deviation in any component
          causes Verify to return false.  The Operator cannot alter C
          without invalidating sigma; the Operator cannot alter L by the
          tamper-evidence property of the append-only log.  The
          <tt>executable()</tt> predicate in <xref target="session-state"/> further establishes that
          <tt>Verify(R, a) = true</tt> is a necessary but not sufficient condition
          for execution.</t>
          <t><tt>dynamic_admissible</tt> now requires both (a) <tt>trustScore</tt> above the
          block threshold and (b) <tt>tauSession</tt> above <tt>tauMin</tt>.  Either
          condition failing independently is sufficient to produce a DENY
          outcome.  The <tt>tauSession</tt> gate is evaluated first and is not
          resettable by reauthorization: once a session's anomaly capacity
          is exhausted, no subsequent clean actions or reauthorization
          calls can restore admissibility for that session.</t>
          </dd>
        </dl>
      </section>

      <section anchor="semantic-gap" numbered="true" toc="default">
        <name>Semantic Gap</name>
        <t>The protocol does not eliminate the semantic gap between authorized
        scope and authorized intent.  A User who authorizes "write to
        calendar" may not intend to authorize deletion of all existing
        events.  The Scope Discovery Protocol (<xref target="scope-discovery"/>) narrows this gap by
        grounding scope definitions in observed agent behavior rather than
        user speculation.</t>

        <t>The <tt>"executes"</tt> scope class narrows the gap further for code execution
        by requiring the SHA-256 hash of the program's static capability DAG
        rather than a program name or URI.  A program identified by name or
        URI can be silently replaced; a program identified by its capability
        signature <strong>MUST</strong> have the same capability set as the authorized
        version.  Any capability addition or removal changes the signature.</t>

        <t>Natural language <strong>MUST NOT</strong> appear in any scope field.  Scope entries
        <strong>MUST</strong> be structured <tt>resource:operation</tt> pairs.  This restriction exists
        because natural language scope definitions are ambiguous, subject to
        interpretation, and cannot be used for deterministic validation.  A
        scope entry of "manage email" does not deterministically resolve to a
        set of permitted or denied operations.</t>

        <t>Cryptographic primitive upgrade path: DRP uses SHA-256 throughout for
        receipt ID computation, instruction hash commitment, manifest body
        hashing, action log chain linking, and revocation record linking.
        The version field in the receipt structure provides a migration path
        to SHA-3-256 (FIPS 202) or BLAKE3 in a future protocol version.  Both
        are drop-in replacements for the SHA-256 role in this protocol.  No
        structural redesign is required for a hash function migration.</t>

        <t>Quantum resistance: ECDSA P-256 is vulnerable to Shor's algorithm on
        a sufficiently capable quantum computer.  The signing layer of the
        protocol is therefore not post-quantum secure under current
        implementations.  The migration path is through the FIDO2/WebAuthn
        credential layer: because all DRP signing is abstracted behind the
        WebAuthn API, a platform-level upgrade to post-quantum FIDO2
        authenticators (e.g., CRYSTALS-Dilithium, FALCON) upgrades the
        protocol's quantum resistance without protocol-layer changes.  The
        append-only log and hash commitment structures are unaffected --
        SHA-256 preimage resistance is not threatened by known quantum
        algorithms.</t>

        <t>For broader AI-specific risk management considerations beyond the
        cryptographic scope of this protocol, see the NIST AI Risk Management
        Framework <xref target="NIST-AI-100-1"/>.</t>
      </section>

      <section anchor="tee-enforcement" numbered="true" toc="default">
        <name>TEE Enforcement</name>
        <t>Cryptographic receipt verification alone cannot prevent a compromised
        agent runtime from calling the verifier with a spoofed receipt,
        receiving an "allowed" result, and then ignoring the scope.  A three-
        layer enforcement model addresses this:</t>

        <dl newline="true" spacing="normal">
          <dt>Layer 1 -- Receipt:</dt>
          <dd>Cryptographic proof of User authorization (what).  The User signs
          a Delegation Receipt specifying scope, boundaries, and Operator
          instructions.  Any tampering is immediately detectable.</dd>

          <dt>Layer 2 -- TEE:</dt>
          <dd>Hardware-measured execution environment (where and how).  The
          Agent runs inside an attested enclave whose measurement is bound
          to the receipt via the <tt>teeMeasurement.expectedMrenclave</tt> field.
          Any substitution of model weights, verifier code, or platform
          produces a different measurement and is detectable before
          execution.</dd>

          <dt>Layer 3 -- eBPF:</dt>
          <dd>Kernel-level enforcement.  An eBPF LSM hook validates a signed
          capability token on every relevant syscall (<tt>security_file_open</tt>,
          <tt>security_socket_connect</tt>, <tt>security_task_execve</tt>).  Scope violations
          <strong>MUST</strong> be denied at the kernel level before they reach userspace.</dd>
        </dl>

        <t>Without Layer 3, a compromised agent runtime could bypass the
        verifier.  The eBPF LSM runs in kernel space and cannot be disabled
        by userspace code, including a compromised agent runtime.  All three
        layers <strong>MUST</strong> be present for the enforcement model to be complete and
        non-bypassable.</t>

        <t>Intel TDX and AMD SEV-SNP provide encrypted memory pages inaccessible
        to the host OS and hypervisor, hardware-rooted attestation quotes
        signed by the CPU vendor's key, and measured boot that hashes every
        component loaded into the enclave.  DRP binds delegation receipts to
        enclave measurements via:</t>

        <artwork name="" type="" align="left" alt=""><![CDATA[
mrenclave = SHA-256(
  platform || verifierHash || modelHash
)
]]></artwork>

        <t>This value is committed into the receipt's
        <tt>teeMeasurement.expectedMrenclave</tt> field at delegation time.  At
        execution time, the runtime recomputes <tt>mrenclave</tt> from its runtime
        parameters and <strong>MUST</strong> reject execution if there is any mismatch.</t>

        <t>The token injection sequence is:</t>
        <ol spacing="normal" type="1">
          <li><tt>ConfidentialRuntime.launch()</tt> computes <tt>mrenclave</tt> and verifies the
          receipt measurement.</li>
          <li><tt>PreExecutionVerifier.check()</tt> gates execution -- no valid receipt
          means no execution.</li>
          <li><tt>TokenPreparer.prepare()</tt> builds a signed capability token binding
          receipt hash, scope hash, and TEE quote hash.</li>
          <li>The token is injected into the agent process context.</li>
          <li>The eBPF LSM validates the token on every relevant syscall.</li>
          <li>Any operation not covered by the token's scope <strong>MUST</strong> be denied at
          the kernel level.</li>
        </ol>
      </section>

      <section anchor="degraded-operation" numbered="true" toc="default">
        <name>Degraded Operation</name>
        <t>When the verifier cannot construct the required authorization state
        due to log unavailability or unverifiable revocation status,
        execution <strong>MUST NOT</strong> proceed regardless of operator acknowledgment.
        Operator acknowledgment does not reconstruct a structurally missing
        verification input and therefore cannot substitute for a complete,
        verifiable authorization state.  Implementations <strong>MUST</strong> fail closed
        under these conditions in all deployment contexts.</t>

        <t>When operating against a locally cached revocation registry,
        implementations <strong>MUST</strong> note the cache timestamp and <strong>MUST</strong> reject any
        receipt where the revocation status cannot be verified against data
        anchored within the configurable maximum cache age.  An
        unverifiable revocation status is treated equivalently to a
        verified revocation: execution <strong>MUST NOT</strong> proceed.</t>

        <t>Implementations <strong>MUST</strong> provide configuration to specify the maximum
        acceptable cache age for revocation data.  The default maximum
        cache age is one hour.</t>
      </section>
    </section>

    <section anchor="iana-considerations" numbered="true" toc="default">
      <name>IANA Considerations</name>
      <t>This document has no IANA actions.</t>
    </section>

  </middle>

  <back>

    <references>
      <name>References</name>

      <references>
        <name>Normative References</name>

        <reference anchor="RFC2119" target="https://www.rfc-editor.org/info/rfc2119">
          <front>
            <title>Key words for use in RFCs to Indicate Requirement Levels</title>
            <author initials="S." surname="Bradner" fullname="S. Bradner"/>
            <date year="1997" month="March"/>
          </front>
          <seriesInfo name="BCP" value="14"/>
          <seriesInfo name="RFC" value="2119"/>
          <seriesInfo name="DOI" value="10.17487/RFC2119"/>
        </reference>

        <reference anchor="RFC8174" target="https://www.rfc-editor.org/info/rfc8174">
          <front>
            <title>Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words</title>
            <author initials="B." surname="Leiba" fullname="B. Leiba"/>
            <date year="2017" month="May"/>
          </front>
          <seriesInfo name="BCP" value="14"/>
          <seriesInfo name="RFC" value="8174"/>
          <seriesInfo name="DOI" value="10.17487/RFC8174"/>
        </reference>

        <reference anchor="RFC3161" target="https://www.rfc-editor.org/info/rfc3161">
          <front>
            <title>Internet X.509 Public Key Infrastructure Time-Stamp Protocol (TSP)</title>
            <author initials="C." surname="Adams" fullname="C. Adams"/>
            <author initials="P." surname="Cain" fullname="P. Cain"/>
            <author initials="D." surname="Pinkas" fullname="D. Pinkas"/>
            <author initials="R." surname="Zuccherato" fullname="R. Zuccherato"/>
            <date year="2001" month="August"/>
          </front>
          <seriesInfo name="RFC" value="3161"/>
          <seriesInfo name="DOI" value="10.17487/RFC3161"/>
        </reference>

        <reference anchor="RFC7517" target="https://www.rfc-editor.org/info/rfc7517">
          <front>
            <title>JSON Web Key (JWK)</title>
            <author initials="M." surname="Jones" fullname="M. Jones"/>
            <date year="2015" month="May"/>
          </front>
          <seriesInfo name="RFC" value="7517"/>
          <seriesInfo name="DOI" value="10.17487/RFC7517"/>
        </reference>

        <reference anchor="RFC7518" target="https://www.rfc-editor.org/info/rfc7518">
          <front>
            <title>JSON Web Algorithms (JWA)</title>
            <author initials="M." surname="Jones" fullname="M. Jones"/>
            <date year="2015" month="May"/>
          </front>
          <seriesInfo name="RFC" value="7518"/>
          <seriesInfo name="DOI" value="10.17487/RFC7518"/>
        </reference>

      </references>

      <references>
        <name>Informative References</name>

        <reference anchor="NIST-AI-100-1" target="https://doi.org/10.6028/NIST.AI.100-1">
          <front>
            <title>Artificial Intelligence Risk Management Framework (AI RMF 1.0)</title>
            <author>
              <organization>National Institute of Standards and Technology</organization>
            </author>
            <date year="2023" month="January"/>
          </front>
          <seriesInfo name="NIST AI" value="100-1"/>
        </reference>

        <reference anchor="W3C-WebAuthn" target="https://www.w3.org/TR/webauthn-2/">
          <front>
            <title>Web Authentication: An API for Accessing Public Key Credentials Level 2</title>
            <author initials="D." surname="Balfanz" fullname="D. Balfanz"/>
            <date year="2021" month="April"/>
          </front>
          <seriesInfo name="W3C Recommendation" value="webauthn-2"/>
        </reference>

        <reference anchor="FIDO2" target="https://fidoalliance.org/specs/fido-v2.1-ps-20210615/fido-client-to-authenticator-protocol-v2.1-ps-20210615.html">
          <front>
            <title>Client to Authenticator Protocol (CTAP)</title>
            <author>
              <organization>FIDO Alliance</organization>
            </author>
            <date year="2021" month="June"/>
          </front>
          <seriesInfo name="FIDO Alliance Proposed Standard" value="CTAP-v2.1"/>
        </reference>

        <reference anchor="RFC6962" target="https://www.rfc-editor.org/info/rfc6962">
          <front>
            <title>Certificate Transparency</title>
            <author initials="B." surname="Laurie" fullname="B. Laurie"/>
            <author initials="A." surname="Langley" fullname="A. Langley"/>
            <author initials="E." surname="Kasper" fullname="E. Kasper"/>
            <date year="2013" month="June"/>
          </front>
          <seriesInfo name="RFC" value="6962"/>
          <seriesInfo name="DOI" value="10.17487/RFC6962"/>
        </reference>

        <reference anchor="RFC8693" target="https://www.rfc-editor.org/info/rfc8693">
          <front>
            <title>OAuth 2.0 Token Exchange</title>
            <author initials="M." surname="Jones" fullname="M. Jones"/>
            <author initials="A." surname="Nadalin" fullname="A. Nadalin"/>
            <author initials="B." surname="Campbell" fullname="B. Campbell"/>
            <author initials="J." surname="Bradley" fullname="J. Bradley"/>
            <author initials="C." surname="Mortimore" fullname="C. Mortimore"/>
            <date year="2020" month="January"/>
          </front>
          <seriesInfo name="RFC" value="8693"/>
          <seriesInfo name="DOI" value="10.17487/RFC8693"/>
        </reference>

        <reference anchor="NC2.5" target="https://doi.org/10.17605/OSF.IO/NHTC5">
          <front>
            <title>Navigational Cybernetics 2.5</title>
            <author initials="M." surname="Barziankou" fullname="Maksim Barziankou">
              <organization abbrev="MxBv"/>
            </author>
            <date year="2026"/>
          </front>
          <seriesInfo name="DOI" value="10.17605/OSF.IO/NHTC5"/>
        </reference>

        <reference anchor="RFC9396" target="https://www.rfc-editor.org/info/rfc9396">
          <front>
            <title>OAuth 2.0 Rich Authorization Requests</title>
            <author initials="T." surname="Lodderstedt" fullname="T. Lodderstedt"/>
            <author initials="J." surname="Richer" fullname="J. Richer"/>
            <author initials="B." surname="Campbell" fullname="B. Campbell"/>
            <date year="2023" month="May"/>
          </front>
          <seriesInfo name="RFC" value="9396"/>
          <seriesInfo name="DOI" value="10.17487/RFC9396"/>
        </reference>

      </references>
    </references>

    <section anchor="json-schema-definitions" numbered="true" toc="default">
      <name>JSON Schema Definitions</name>

      <section anchor="delegation-receipt-schema" numbered="true" toc="default">
        <name>Delegation Receipt Schema</name>
        <t>The following JSON Schema (draft-07) defines the structure of a
        Delegation Receipt as specified in <xref target="delegation-receipt"/>.</t>

        <artwork name="" type="json" align="left" alt=""><![CDATA[
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "https://authproof.dev/schemas/delegation-receipt-1.0.json",
  "title": "DelegationReceipt",
  "type": "object",
  "required": [
    "receiptId",
    "schemaVersion",
    "createdAt",
    "expiresAt",
    "publicKey",
    "scope",
    "operatorInstructionsHash",
    "canonicalPayload",
    "signature"
  ],
  "properties": {
    "receiptId": {
      "type": "string",
      "description": "Unique receipt identifier.",
      "pattern": "^rec_[0-9a-f]{16,}$"
    },
    "schemaVersion": {
      "type": "string",
      "description": "Schema version. MUST be 1.0.",
      "enum": ["1.0"]
    },
    "createdAt": {
      "type": "string",
      "format": "date-time",
      "description": "ISO 8601 datetime at which this receipt
                      was created and signed."
    },
    "expiresAt": {
      "type": "string",
      "format": "date-time",
      "description": "ISO 8601 datetime at which this receipt
                      expires.  Verification MUST fail after
                      this time."
    },
    "publicKey": {
      "type": "object",
      "description": "The authorizing user's public key in
                      JSON Web Key format (RFC 7517).",
      "required": ["kty", "crv", "x", "y"],
      "properties": {
        "kty": {
          "type": "string",
          "enum": ["EC"]
        },
        "crv": {
          "type": "string",
          "enum": ["P-256"]
        },
        "x": {
          "type": "string",
          "description": "Base64url-encoded x coordinate."
        },
        "y": {
          "type": "string",
          "description": "Base64url-encoded y coordinate."
        }
      }
    },
    "scope": {
      "$ref": "#/definitions/ScopeSchema"
    },
    "operatorInstructionsHash": {
      "type": "string",
      "description": "SHA-256 hash of the canonical operator
                      instructions string, formatted as
                      sha256:<hex>.",
      "pattern": "^sha256:[0-9a-f]{64}$"
    },
    "modelCommitment": {
      "type": "string",
      "description": "OPTIONAL. Cryptographic measurement of
                      the model state at authorization time,
                      formatted as sha256:<hex>.  When present,
                      verification MUST fail if the current
                      model measurement does not match.",
      "pattern": "^sha256:[0-9a-f]{64}$"
    },
    "metadata": {
      "type": "object",
      "description": "OPTIONAL. Arbitrary key-value pairs
                      included in the canonical payload and
                      covered by the signature.  MAY include
                      external delegation identifiers.",
      "additionalProperties": {
        "type": "string"
      }
    },
    "canonicalPayload": {
      "type": "string",
      "description": "Base64url-encoded canonical JSON
                      serialization of all fields except
                      signature, over which the signature
                      is computed."
    },
    "signature": {
      "type": "string",
      "description": "Base64url-encoded ECDSA P-256 signature
                      over canonicalPayload."
    },
    "logEntryHash": {
      "type": "string",
      "description": "OPTIONAL. SHA-256 hash of the append-only
                      log entry produced when this receipt was
                      published, formatted as sha256:<hex>.",
      "pattern": "^sha256:[0-9a-f]{64}$"
    }
  },
  "definitions": {
    "ScopeSchema": {
      "type": "object",
      "required": ["version", "allowedActions"],
      "properties": {
        "version": {
          "type": "string",
          "description": "Scope schema version.",
          "default": "1.0"
        },
        "allowedActions": {
          "type": "array",
          "description": "Explicit list of permitted actions.",
          "items": {
            "$ref": "#/definitions/ActionConstraint"
          }
        },
        "deniedActions": {
          "type": "array",
          "description": "Explicit list of prohibited actions.
                          Deny rules take precedence over allow
                          rules.",
          "items": {
            "$ref": "#/definitions/ActionConstraint"
          }
        }
      }
    },
    "ActionConstraint": {
      "type": "object",
      "required": ["operation", "resource"],
      "properties": {
        "operation": {
          "type": "string",
          "description": "The operation type. Wildcards (*) are
                          supported.",
          "examples": ["read", "write", "delete", "send", "*"]
        },
        "resource": {
          "type": "string",
          "description": "The resource identifier. Wildcards (*)
                          are supported.",
          "examples": ["email", "calendar", "database/*", "*"]
        },
        "constraints": {
          "type": "object",
          "description": "OPTIONAL. Argument-level constraints
                          on the action.",
          "additionalProperties": true
        }
      }
    }
  }
}
]]></artwork>
      </section>

      <section anchor="action-log-entry-schema" numbered="true" toc="default">
        <name>Action Log Entry Schema</name>
        <t>The following JSON Schema defines the structure of an Action Log
        Entry as specified in <xref target="append-only-log"/>.</t>

        <artwork name="" type="json" align="left" alt=""><![CDATA[
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "https://authproof.dev/schemas/action-log-entry-1.0.json",
  "title": "ActionLogEntry",
  "type": "object",
  "required": [
    "entryId",
    "receiptHash",
    "operation",
    "resource",
    "timestamp",
    "previousEntryHash",
    "entryHash"
  ],
  "properties": {
    "entryId": {
      "type": "string",
      "description": "Unique identifier for this log entry."
    },
    "receiptHash": {
      "type": "string",
      "description": "SHA-256 hash of the delegation receipt
                      that authorized this action, formatted
                      as sha256:<hex>.",
      "pattern": "^sha256:[0-9a-f]{64}$"
    },
    "operation": {
      "type": "string",
      "description": "The operation that was executed."
    },
    "resource": {
      "type": "string",
      "description": "The resource that was accessed."
    },
    "timestamp": {
      "type": "string",
      "format": "date-time",
      "description": "RFC 3161 trusted timestamp of this
                      log entry."
    },
    "previousEntryHash": {
      "type": "string",
      "description": "SHA-256 hash of the previous log entry.
                      The first entry in a log uses a
                      well-known genesis hash.",
      "pattern": "^sha256:[0-9a-f]{64}$"
    },
    "entryHash": {
      "type": "string",
      "description": "SHA-256 hash of this entry's canonical
                      serialization excluding entryHash.",
      "pattern": "^sha256:[0-9a-f]{64}$"
    },
    "decision": {
      "type": "string",
      "description": "The verification decision for this
                      action.",
      "enum": ["ALLOW", "REQUIRE_APPROVAL", "BLOCK"]
    },
    "riskScore": {
      "type": "number",
      "description": "OPTIONAL. Session risk score at the
                      time of this action.",
      "minimum": 0,
      "maximum": 100
    }
  }
}
]]></artwork>
      </section>

      <section anchor="session-state-schema" numbered="true" toc="default">
        <name>Session State Schema</name>
        <t>The following JSON Schema defines the structure of a Session State
        object as specified in <xref target="session-state"/>.</t>

        <artwork name="" type="json" align="left" alt=""><![CDATA[
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "https://authproof.dev/schemas/session-state-1.0.json",
  "title": "SessionState",
  "type": "object",
  "required": [
    "sessionId",
    "receiptHash",
    "trustScore",
    "status",
    "startedAt",
    "actionCount"
  ],
  "properties": {
    "sessionId": {
      "type": "string",
      "description": "Unique session identifier."
    },
    "receiptHash": {
      "type": "string",
      "description": "SHA-256 hash of the delegation receipt
                      that initiated this session.",
      "pattern": "^sha256:[0-9a-f]{64}$"
    },
    "trustScore": {
      "type": "number",
      "description": "Current session trust score. Starts at
                      100 and decays on anomaly detection.",
      "minimum": 0,
      "maximum": 100
    },
    "status": {
      "type": "string",
      "description": "Current session status.",
      "enum": ["ACTIVE", "DEGRADED", "SUSPENDED"]
    },
    "startedAt": {
      "type": "string",
      "format": "date-time",
      "description": "ISO 8601 datetime at which this session
                      was initiated."
    },
    "lastActionAt": {
      "type": "string",
      "format": "date-time",
      "description": "ISO 8601 datetime of the most recent
                      action in this session."
    },
    "actionCount": {
      "type": "integer",
      "description": "Total number of actions evaluated in
                      this session.",
      "minimum": 0
    },
    "anomalyCount": {
      "type": "integer",
      "description": "Total number of anomalies detected in
                      this session.",
      "minimum": 0
    },
    "sensitivityLevel": {
      "type": "string",
      "description": "Highest sensitivity level detected in
                      this session.",
      "enum": ["PUBLIC", "INTERNAL", "CONFIDENTIAL",
               "RESTRICTED"]
    }
  }
}
]]></artwork>
      </section>

    </section>

    <section anchor="acknowledgements" numbered="false" toc="default">
      <name>Acknowledgements</name>
      <t>The authors thank the IETF WIMSE, OAuth, and SCITT working groups for
      their work on workload identity, token exchange, and supply chain
      integrity, which informed the design of this protocol.</t>
      <t>The formal analysis of session state properties in this document
      benefited from review and guidance by Maksim Barziankou.  The
      treatment of structural burden, viability budgets, and admissibility
      predicates in <xref target="session-state"/> and
      <xref target="security-considerations"/> draws on primitives
      formalized in Navigational Cybernetics 2.5
      <xref target="NC2.5"/>.</t>
    </section>

  </back>
</rfc>
