<?xml version="1.0" encoding="utf-8"?>
<!-- name="GENERATOR" content="github.com/mmarkdown/mmark Mmark Markdown Processor - mmark.miek.nl" -->
<rfc version="3" ipr="trust200902" docName="draft-toraman-noa-action-digest-01" submissionType="IETF" category="std" xml:lang="en" xmlns:xi="http://www.w3.org/2001/XInclude" indexInclude="true">

<front>
<title abbrev="NOA Action Digest">The NOA Action Digest: a Domain-Separated Correlation Value for Human-Approved Agent Actions</title><seriesInfo value="draft-toraman-noa-action-digest-01" stream="IETF" status="standard" name="Internet-Draft"></seriesInfo>
<author initials="T." surname="Toraman" fullname="Tora Toraman"><organization>NordenSoft</organization><address><postal><street></street>
<country>Denmark</country>
</postal><email>hello@ordeliya.com</email>
</address></author><date year="2026" month="August" day="14"></date>
<area>Security</area>
<workgroup>Network Working Group</workgroup>
<keyword>AI agent</keyword>
<keyword>correlation</keyword>
<keyword>digest</keyword>
<keyword>domain separation</keyword>
<keyword>authorization</keyword>
<keyword>provenance</keyword>
<keyword>accountability</keyword>
<keyword>human approval</keyword>

<abstract>
<t>This document defines a domain-separated correlation value, the NOA Action Digest, that binds a
verified human authorization for an agent action to the artifacts and external events associated
with that action's execution attempt. The digest is a fixed-width value derived from an approved
action's authorization record, its tenancy and chain identifiers, its parameter commitment, its
execution grant, and a single-use nonce. It is designed to be embedded in external systems that
carry an opaque, caller-chosen identifier, so that a third party can correlate an external event
with a specific prior authorization. <strong>The digest establishes correlation only. Equality of
digests is not evidence that any statement made by any party about the action is true, and is not
evidence that any action was executed or any effect occurred.</strong></t>
</abstract>

</front>

<middle>

<section anchor="intro"><name>Introduction</name>
<t>Autonomous software agents increasingly take actions with external consequences. Systems that
require a human to approve such actions produce a record of the approval, but that record and the
action's later effects are usually correlated only by trusting an intermediary's bookkeeping.</t>
<t>This document defines a value whose derivation is fixed, public, and reproducible from the
authorization record itself, so that correlation does not depend on any intermediary's assertion.
The value is designed for the common pattern in which an external system carries a caller-chosen
opaque field that it commits to but does not interpret.</t>
<t>This document deliberately does <strong>not</strong> define an execution binding. Correlating an authorization
with an external event is strictly weaker than establishing that the approved action was
performed. <xref target="security"></xref> states the boundary.</t>
<t><strong>Non-goal:</strong> this document does not define, and its authors do not claim, any mechanism that
prevents a sufficiently capable adversary from causing harm. It defines a value that makes certain
classes of substitution detectable after the fact.</t>

<section anchor="philosophy"><name>Verification philosophy</name>
<t>This document is written under a discipline its authors call the <strong>Copenhagen model</strong>: a verifier
never states what happened; it states what the supplied evidence supports, and it records, in the
same breath and on every surface, what it does <strong>not</strong> claim. Every section below that names a
control also names the residual the control leaves behind. Where a control does not exist, this
document says so rather than describing an intention as a property. <xref target="security"></xref> is written to be
attacked, and <xref target="anchors"></xref> is deliberately an open list rather than a taxonomy.</t>
<t>The name is a nod to a remark about physics — that the subject concerns what we can <em>say</em> about
nature — attributed to Niels Bohr, secondhand, via Aage Petersen's 1963 recollection; it does not
appear in Bohr's own writings, and this document claims no more for the attribution than that.
The authors' own sentence for the same idea carries no attribution at all: <em>we do not tell you
what happened; we show you what the evidence proves.</em></t>
</section>

<section anchor="editorial-gate"><name>Editorial note on this revision</name>
<t><em>This subsection is non-normative and is to be removed before publication as an RFC.</em></t>
<t>Two conditions govern the release of this document, and they are stated here so that a reader
holding a revision can check them mechanically:</t>

<ol spacing="compact">
<li>This document is not submitted while any placeholder-marked item in <xref target="construction"></xref> or in
<xref target="security"></xref> is unresolved. <strong>No such item is open in this revision.</strong> Exactly one <em>unresolved</em>
item remains anywhere in this document — the registry request awaiting working-group direction in
<xref target="iana"></xref> — and this condition does not cover it.</li>
<li>No claimed defence is submitted without a conformance vector that enforces it. A stated
requirement on an unimplemented interface is a request, not a control, until a conformance
vector enforces it. Where a property is not vector-enforceable at all — see P4 in
<xref target="properties"></xref> — this document says so at the point of use and states the residual, rather
than implying an enforcement that does not exist.</li>
</ol>
</section>
</section>

<section anchor="terms"><name>Conventions and Terminology</name>
<t>The key words <bcp14>MUST</bcp14>, <bcp14>MUST NOT</bcp14>, <bcp14>REQUIRED</bcp14>, <bcp14>SHALL</bcp14>, <bcp14>SHALL NOT</bcp14>, <bcp14>SHOULD</bcp14>,
<bcp14>SHOULD NOT</bcp14>, <bcp14>RECOMMENDED</bcp14>, <bcp14>NOT RECOMMENDED</bcp14>, <bcp14>MAY</bcp14>, and <bcp14>OPTIONAL</bcp14> in this document
are to be interpreted as described in BCP 14 <xref target="RFC2119"></xref> <xref target="RFC8174"></xref> when, and only when, they appear
in all capitals, as shown here.</t>

<ul spacing="compact">
<li><strong>Authorization Record</strong> — a signed statement that a named principal approved a specific action
under stated bounds. In the reference implementation this is a <tt>noa.receipt/0.1</tt> whose governance
verdict is <tt>ALLOWED</tt>. <strong>The record names the approving principal in a field; it is signed by the
issuing gate's key, which is not the same thing.</strong> The signature establishes that the gate issued
and has not since altered the record — not that the named human held any key, and not who
physically approved. Which identity a deployment binds to the approval, and how, is outside this
document; see <xref target="not-established"></xref>.</li>
<li><strong>Parameter Commitment</strong> — a cryptographic commitment to the canonical byte encoding of the
action's parameters. In the reference implementation this is <tt>action.paramsHash</tt>.</li>
<li><strong>Execution Grant</strong> — a single-use, time-bounded authorization to perform one execution attempt
of one committed action.</li>
<li><strong>Action Digest</strong> — the value this document defines.</li>
<li><strong>Correlation</strong> — the property that two records refer to the same authorized action.
<strong>Correlation is not attestation.</strong></li>
<li><strong>Relying Party</strong> — any party that verifies these artifacts. A Relying Party is assumed to trust
neither the agent nor the operator of the approval system.</li>
</ul>
</section>

<section anchor="frozen"><name>The Frozen Base Record Is Not Modified</name>
<t>The Authorization Record format assumed by this document is frozen and MUST NOT be modified to
carry an Action Digest. Implementations <bcp14>MUST NOT</bcp14> add a member to the Authorization Record at
any depth. The Action Digest is carried in separate, referencing artifacts.</t>
<t><em>Implementation note, non-normative:</em> in the reference implementation the record schema sets
<tt>additionalProperties:false</tt> at the root and on every nested object, and lists all root members as
required (<tt>schema/noa-receipt-0.1.schema.json</tt>), so a new member is rejected twice. Adding one
would change canonical bytes, record hashes, signatures, chain links, checkpoints and every
published conformance vector.</t>
</section>

<section anchor="construction"><name>Construction</name>
<t>The construction is fixed and is reproduced here in full; it is a SHA-256 <xref target="FIPS180-4"></xref> value over
RFC 8785 <xref target="RFC8785"></xref> canonical JSON. The reference corpus that enforces it is the <strong>Copenhagen
vectors</strong> — the cross-language conformance corpus published with the reference implementation, at
<tt>conformance/action-digest/vectors.json</tt>. See <xref target="impl-status"></xref> for the exact anchor and the
measurement date.</t>

<artwork><![CDATA[projection = a JSON object with EXACTLY these ten string members:
  spec, authorizationReceiptHash, tenant, chain, actionId, actionCanonical,
  actionParamsHash, executionGrantId, executionGrantHash, executionNonce

JCS      = RFC 8785 canonical JSON of the projection
PREIMAGE = UTF8("NOA-ActionDigest-v0.1-dig:") || SHA-256(JCS)      ; 26 + 32 = 58 bytes
DIGEST   = "sha256:" || lowercase-hex(SHA-256(PREIMAGE))

wire form: { "spec": "noa.action-digest/0.1", "digest": "sha256:<64 lowercase hex>" }
]]></artwork>
<t>Four properties of the construction that a reviewer will ask about, answered rather than deferred:</t>

<ul spacing="compact">
<li><strong>The domain tag ends in <tt>-dig</tt>, not <tt>-sig</tt>.</strong> This value is hashed and <strong>never signed</strong>, so it
is kept out of the signing namespace: a <tt>-sig</tt> tag here would create a signing pre-image some
other verifier might one day be persuaded to accept. <em>(Consequence for <xref target="iana"></xref>: a registry named
for <strong>signing</strong> domains does not fit a <strong>hashing</strong> tag.)</em></li>
<li><strong>The digest object is not signed.</strong> It is a derived value, recomputed by the verifier from the
Authorization Record and the Execution Grant. <xref target="verification"></xref> is written accordingly: there is
no digest artifact to authenticate, and therefore none to substitute.</li>
<li><strong>Member order is irrelevant</strong> because JCS sorts names; the <em>named slots</em> are what prevent a
transposition of <tt>actionId</tt> and <tt>actionCanonical</tt> from colliding (vector
<tt>reject-action-fields-transposed</tt>).</li>
<li><strong>The two hash rules inside the projection are deliberately different</strong> and must not be
interchanged: <tt>authorizationReceiptHash</tt> is the receipt-reference rule, <tt>executionGrantHash</tt> the
side-artifact rule.</li>
</ul>

<section anchor="commitments"><name>Required commitments</name>
<t>The digest input <bcp14>MUST</bcp14> commit to at least the following:</t>

<ol spacing="compact">
<li>the <strong>locally recomputed and verified</strong> Authorization Record hash — not a hash asserted by a
third party;</li>
<li>the tenant identifier;</li>
<li>the chain identifier;</li>
<li>the action identifier;</li>
<li>the action's canonical name;</li>
<li>the Parameter Commitment;</li>
<li>the Execution Grant identifier and/or its hash;</li>
<li>a single-use execution nonce, carried inside the signed Execution Grant. The nonce is signed
<strong>by being a member of the signed grant</strong>, not by carrying a signature of its own.</li>
</ol>
</section>

<section anchor="properties"><name>Properties required by this document</name>

<ul spacing="compact">
<li><strong>P1 — Width.</strong> The digest <bcp14>MUST</bcp14> be exactly 32 octets. <em>Rationale:</em> the external carrier
fields this document targets are 32-octet opaque values (see
<xref target="I-D.toraman-noa-settlement-evidence"></xref>). A construction of any other width cannot be embedded
without a lossy transformation, and a lossy transformation destroys the correlation.
<em>Scope, because it is narrower than it looks:</em> this rationale binds <strong>mode (a)</strong> of
<xref target="embedding"></xref>. Where a profile uses the digest as an input to a derivation whose <em>output</em> is
carried instead (<strong>mode (b)</strong>), the carried value's width is set by that derivation, not by this
property. P1 is retained unchanged because this document does not restrict a profile to one mode,
and a fixed width is what keeps the two modes interchangeable.</li>
<li><strong>P2 — Domain separation.</strong> The digest <bcp14>MUST</bcp14> be computed under a domain tag distinct from
every other signing or hashing domain the producing system uses, so that a digest can never be
replayed as, or confused with, another artifact's signature pre-image or reference hash.</li>
<li><strong>P3 — Determinism.</strong> The digest <bcp14>MUST</bcp14> be re-derivable, byte-identically, by any party
holding the same inputs, with no dependence on wall-clock time, iteration order, locale, or
floating-point behaviour.</li>
<li><strong>P4 — Unguessability.</strong> The digest <bcp14>MUST NOT</bcp14> be guessable by a party that does not hold the
input preimage. The single-use nonce (item 8 of <xref target="commitments"></xref>) <bcp14>MUST</bcp14> contribute at least 128
bits of entropy from a cryptographically secure source. <em>Rationale:</em> the digest, or a value
derived from it, becomes public when embedded in an external system (<xref target="embedding"></xref>). If the other
inputs are low-entropy or enumerable, a public digest permits confirm-by-guess disclosure of the
action's parameters. Under a derivation profile (mode (b) of <xref target="embedding"></xref>) the same nonce is
also the derivation's seed, so P4 carries that profile's unguessability as well — one
requirement, two loads. See <xref target="privacy"></xref> for where each lands.</li>
</ul>
<t><strong>P4 is not verifiable from the value.</strong> Entropy is a property of the <em>generator</em>, not of 32
  octets: no relying party and no conformance vector can distinguish a CSPRNG digest from a counter
  by inspection. P4 is therefore stated as a <strong>producer obligation with a disclosed residual</strong>, and
  a conforming implementation <bcp14>MUST</bcp14> document the nonce source. <xref target="privacy"></xref> carries the residual.
  See <xref target="impl-status"></xref> for the reference implementation's measured nonce source.
- <strong>P5 — Ordering.</strong> The digest <bcp14>MUST</bcp14> be computable <strong>before</strong> the execution attempt is
  dispatched. Any construction requiring an input that exists only after dispatch is out of scope,
  because a value that cannot be committed before dispatch cannot correlate a pre-committed
  authorization with a post-dispatch event. This is enforced <strong>by construction</strong> — every one of the
  projection's ten members exists at approval time — not by a conformance vector, and is stated here
  as such.
- <strong>P6 — Not the parameter commitment.</strong> The Action Digest <bcp14>MUST NOT</bcp14> be the Parameter
  Commitment, and no document may name the Parameter Commitment as the action digest. <em>Rationale:</em>
  a parameter commitment does not bind the complete authorization, tenant and chain, the exact
  attempt, the grant, or the nonce, and it may repeat across retries. This is a naming prohibition
  on other documents; no conformance vector can enforce it, and it is stated here as a residual, not
  a control.
- <strong>P7 — Uniqueness across retries.</strong> Two distinct execution attempts of the same action <bcp14>MUST</bcp14>
  yield distinct digests. This follows from item 8 of <xref target="commitments"></xref> and is stated separately
  because it is the property retries break.</t>
</section>

<section anchor="open-items"><name>Status of the construction's open items</name>
<table>
<thead>
<tr>
<th>Item</th>
<th>Status</th>
</tr>
</thead>

<tbody>
<tr>
<td>exact member names and their order</td>
<td><strong>RESOLVED</strong> — <xref target="construction"></xref>, ten members, order irrelevant under JCS</td>
</tr>

<tr>
<td>encoding of the digest input (JCS vs CBOR)</td>
<td><strong>RESOLVED</strong> — JCS <xref target="RFC8785"></xref></td>
</tr>

<tr>
<td>the domain-tag string</td>
<td><strong>RESOLVED</strong> — <tt>NOA-ActionDigest-v0.1-dig</tt></td>
</tr>

<tr>
<td>whether the digest object is itself signed, or purely derived</td>
<td><strong>RESOLVED</strong> — purely derived, <tt>{spec, digest}</tt>, no <tt>sig</tt></td>
</tr>

<tr>
<td>test vectors</td>
<td><strong>RESOLVED</strong> — the Copenhagen vectors, <tt>conformance/action-digest/vectors.json</tt></td>
</tr>

<tr>
<td>whether a rail-binding component (chain id, contract, payer) is inside the digest or carried separately</td>
<td><strong>RESOLVED</strong> — the projection is <strong>frozen at ten members</strong>; it carries a <tt>chain</tt> member (a tenancy/record-chain identifier) but <strong>no</strong> <em>ledger/rail</em> chain id, <strong>no</strong> token contract and <strong>no</strong> payer. A rail binding is therefore carried <strong>outside</strong> this digest, and in the profile the reference implementation ships it is carried twice: by the mandate's Parameter Commitment, and as inputs to the derivation that consumes this digest and produces the value the rail actually carries (mode (b) of <xref target="embedding"></xref>). See <xref target="I-D.toraman-noa-settlement-evidence"></xref>.</td>
</tr>

<tr>
<td>the nonce's entropy source</td>
<td><strong>RESOLVED as a producer obligation</strong> — see P4 in <xref target="properties"></xref> and <xref target="impl-status"></xref>. Entropy is unverifiable from the value, so this closes as a documented obligation with a disclosed residual, never as a vector-enforced control.</td>
</tr>
</tbody>
</table></section>
</section>

<section anchor="embedding"><name>Embedding in External Systems</name>
<t>An Action Digest MAY reach an external system in either of two modes, and the difference decides
what becomes public:</t>

<ul spacing="compact">
<li><strong>mode (a) — direct embedding.</strong> The digest itself is placed in the external system's
caller-chosen opaque identifier field.</li>
<li><strong>mode (b) — derivation input.</strong> The digest is one committed input to a derivation whose
<strong>output</strong> is placed in that field. <strong>Under mode (b) the digest itself never reaches the external
system</strong>, and the carried value binds whatever else the derivation commits to.
<xref target="I-D.toraman-noa-settlement-evidence"></xref> defines such a profile, and it is the one the reference
implementation ships.</li>
</ul>
<t>Both modes are subject to:</t>

<ul spacing="compact">
<li><strong>E1</strong> — the external system <bcp14>MUST</bcp14> commit to the field in a way <strong>no party in the dispatch
path</strong> can alter after the embedding party signs (for example, by including it in a signed
structure the external system independently verifies). The threat this addresses is an
<strong>intermediary in the dispatch path</strong> — a facilitator, a relay — not the embedding party's own
choice of value before signing. Under mode (b) E1 binds the <strong>carried value</strong>; the digest itself
is protected only by whatever protects the derivation's inputs, which is the embedding party's
own custody of its documents and not the external system. E1 constrains a <strong>third-party</strong> external
system's behaviour, so no conformance vector in this corpus can enforce it — it is a residual on
the deployment, not a control this document verifies.</li>
<li><strong>E2</strong> — the external system <bcp14>MUST NOT</bcp14> require the field to be produced by a generation
process it names, registers or attests. Where a system requires only <em>uniqueness</em>, a
deterministic digest satisfies it. Under P4 of <xref target="properties"></xref> the digest is a SHA-256 image over a
pre-image carrying at least 128 bits of cryptographically secure entropy, so <strong>no statistical
inspection of the field distinguishes it from a freshly drawn random value</strong> — and this holds for
a mode-(a) digest and a mode-(b) derived value alike; a system that merely inspects the field for
apparent randomness is satisfied by either. What no such value can satisfy, in <strong>either</strong> mode, is
a system that requires a <strong>named generator</strong> — that the field be produced by a named, registered
or attested process rather than merely appear random — because neither value was drawn from one.
That kind of system is out of scope in both modes. This is not vector-enforceable — no conformance
vector can inspect a producer's generator — and is stated here as a residual, not a control.</li>
<li><strong>E3</strong> — the embedding party <bcp14>MUST</bcp14> treat <strong>the value it places in the external system</strong> as
public from the moment it leaves the embedding party's control, and <bcp14>MUST</bcp14> apply <xref target="privacy"></xref>.
Under mode (a) that value is the digest. Under mode (b) the digest does not become public by
embedding — but it becomes <strong>recomputable</strong> by every party handed the derivation's inputs, and
the embedding party <bcp14>MUST</bcp14> treat that disclosure as equally permanent. <strong>Note either may be
earlier than dispatch:</strong> a profile that projects the digest into an OAuth <tt>authorization_details</tt>
entry <xref target="RFC9396"></xref> transports it <em>through the user agent</em> (<xref target="RFC9396"></xref>, Section 12), so under that
projection the digest is public at <strong>authorization-request</strong> time, to every party in the browser
path, <strong>before the payment is signed</strong> — and it is public there in mode (b) too, because that
projection carries the digest itself rather than a derived value. A profile that puts either
value in a user-agent-visible channel MUST say so. Like E1 and E2, E3 is an obligation on the
embedding party and its deployment, not a property any conformance vector can check — stated at
the point of use as a residual.</li>
</ul>
</section>

<section anchor="verification"><name>Verification</name>
<t>A Relying Party verifying a correlation claim <bcp14>MUST</bcp14>:</t>

<ol spacing="compact">
<li>verify the Authorization Record's signature against a trust anchor it holds independently, and
recompute its hash locally rather than accepting an asserted hash;</li>
<li>verify the Execution Grant and its bindings to that record;</li>
<li>recompute the Action Digest from the construction in <xref target="construction"></xref>, building the projection
<strong>from the authenticated documents themselves</strong> — the <tt>tenant</tt> and <tt>chain</tt> members take the
values those documents carry;</li>
<li><strong>separately</strong>, compare the projection's resulting <tt>tenant</tt> and <tt>chain</tt> against the Relying
Party's <strong>own</strong> expected values, and fail on any difference. This is a distinct step from step 3
and <bcp14>MUST NOT</bcp14> be folded into it: substituting the expected values <em>into</em> the recomputation
would make the digest agree by construction and destroy the check. The two steps answer two
different questions — step 3 asks <em>&quot;what do these documents say?&quot;</em>, step 4 asks <em>&quot;are these
documents mine?&quot;</em> — and only the second is a defence against a genuine, correctly-signed bundle
belonging to another tenant or another chain;</li>
<li>compare the recomputed digest to the value observed in the external system;</li>
<li>on any mismatch, return a distinct, machine-readable failure — <bcp14>MUST NOT</bcp14> collapse a digest
mismatch into a generic invalid result.</li>
</ol>
<t>Steps 1 and 2 are <strong>not optional and not reorderable</strong>, and the reference implementation pins that
as a permanent test rather than asserting it: the digest construction <strong>verifies no signature</strong>, so
a fully forged pair — an attacker's key claiming the victim's <tt>kid</tt>, a record asserting an approved
transfer, a grant signed with 64 zero bytes — is <strong>ACCEPTED</strong> by step 3 and <strong>REFUSED</strong> by the
record's own chain verification against an honest keyring. <strong>A green step 3 over unverified
documents establishes nothing.</strong></t>
<t>In-realm recomputation is <strong>not</strong> a trust boundary. A verifier that recomputes inside a runtime an
adversary can influence has moved the trust anchor, not removed it.</t>
<t>A Relying Party <bcp14>MUST NOT</bcp14> conclude from a successful comparison that the action was performed,
that any effect occurred, or that any statement about the action made by any party is true. See
<xref target="not-established"></xref>.</t>
</section>

<section anchor="security"><name>Security Considerations</name>
<t>This section is written to be attacked. Where a control does not exist, this document says so
rather than describing an intention as a property.</t>

<section anchor="not-established"><name>What the digest does not establish</name>
<t>Digest equality is <strong>linkage and correlation only</strong>. It is not proof that a controller claim, a
physical claim, a delivery claim, or any other statement about the action is true. It is not an
execution binding.</t>
<t>A system built on this document establishes that <strong>a key the Relying Party's own keyring trusts
signed an Authorization Record carrying this parameter commitment, and that the Execution Grant's
own signature is authentic</strong>; it does <strong>not</strong> establish that <em>that intent is what executed</em>.</t>
<t><strong>Say exactly what the authenticating entry point checks, because a partial check described as a
whole one is worse than none.</strong> The reference entry point (<tt>verifyActionDigest</tt>) verifies the
record chain and the Execution Grant's Ed25519 signature against a keyring the Relying Party holds
independently. It does <strong>not</strong> check the grant's authorization <em>semantics</em>: the signer's type and
role, the signing key's activation window, the grant's expiry, and the envelope reference chain are
<strong>not</strong> evaluated here — they belong to the full artifact verifier (<tt>verifyArtifact</tt> in the
reference implementation), which this entry point has no dependency edge to. A caller enforcing an
authorization decision <bcp14>MUST</bcp14> run that full verifier as well. Consequently this entry point alone
does <strong>not</strong> establish that the key was authorized <strong>at the time of the action</strong> — it checks
signature authenticity, never key activation or grant expiry. It also does not establish <em>which
human</em> held the key; the approval's subject field is an opaque identifier, not an identity; and a
device that signs without opening produces evidence indistinguishable from a device that opened,
read and approved.</t>
</section>

<section anchor="anchors"><name>Residual trust anchors</name>
<t>A digest does not reduce the following. This is an <strong>OPEN list of the largest known classes, never
an exhaustive attack surface</strong>; at least seven further classes are omitted or collapsed by it,
including <strong>availability and denial of service</strong>, <strong>replay and rollback</strong>, <strong>verifier defects</strong>,
<strong>revocation and recovery</strong>, <strong>privacy leakage</strong>, <strong>cross-tenant isolation</strong> and <strong>supply-chain
compromise</strong> — four of which are live in this document and its companion. Each entry below is named
permanently, on every surface where this mechanism is described, because each leaves the
correlation intact while defeating a guarantee a reader might infer from it.</t>
<t>Note also that these anchors do <strong>not</strong> all leave third-party-verifiable evidence:
infrastructure-root compromise can alter or suppress evidence, stolen keys produce
apparently-valid evidence, and an ungated action produces no evidence at all — <strong>including no
record of its absence</strong>.</t>

<ol spacing="compact">
<li><strong>Infrastructure root.</strong> Compromise of the host or operating system running the approval system
defeats every in-process control. Detection depends on evidence leaving the host.</li>
<li><strong>Key custody.</strong> A party that can read a signing key can produce artifacts indistinguishable
from genuine ones. <strong>No claim of unforgeable authority may be made for a deployment whose
signing key is held in the process the signed artifacts are meant to defend.</strong> See
<xref target="impl-status"></xref> for the reference implementation's measured status against this anchor.</li>
<li><strong>Governance capture.</strong> A correctly signed decision made under a corrupt policy is
cryptographically valid and substantively wrong. Signatures authenticate authorship, never
wisdom.</li>
<li><strong>The deceived approver.</strong> Nothing here proves the approving human understood what they
approved, or that an accurate description was rendered to them. This mechanism produces evidence
about an approval; it does not prevent a person from being misled into giving one.</li>
<li><strong>Cross-action composition.</strong> Individually approved actions may compose into an outcome no
approver sanctioned. Per-action binding says nothing about sequences.</li>
<li><strong>The ungated surface.</strong> Anything not routed through an enforced adapter is outside coverage
entirely and produces no artifact at all — including its absence.</li>
</ol>
<t><strong>Activity outside enforced gateways is outside coverage.</strong> This is a scope statement, not a
mitigation, and it is stated with no justifying clause. Model sandbox escapes fall inside it.</t>
</section>

<section anchor="substitution"><name>Substitution and replay</name>

<ul spacing="compact">
<li><strong>Digest substitution.</strong> An attacker who can alter the digest before it is embedded breaks
correlation. Under mode (a) of <xref target="embedding"></xref>, E1 is the only defence; where the external system
does not cryptographically commit to the field, correlation via that system is worth nothing and
<bcp14>MUST NOT</bcp14> be claimed. Under mode (b) the substitution is additionally detected on the
verifier's side — a digest altered before derivation produces a carried value that no longer
equals the one recomputed from the verified documents — but E1 remains required, because
detecting a broken correlation is not the same as having one.</li>
<li><strong>Replay across attempts.</strong> Prevented by P7 of <xref target="properties"></xref> (per-attempt nonce). A construction
without a per-attempt nonce permits an old authorization to be presented as correlating to a new
event.</li>
<li><strong>Cross-domain replay.</strong> Prevented by P2 of <xref target="properties"></xref>. Without domain separation a digest
could be presented as another artifact's hash or signature pre-image.</li>
</ul>
</section>

<section anchor="privacy"><name>Privacy</name>
<t>Under mode (a) of <xref target="embedding"></xref> the digest becomes a permanent public correlator. Under mode (b) it
does not — but the analysis does not simply improve, it <strong>moves</strong>, and both halves have to be
stated or the improvement is oversold.</t>

<ol spacing="compact">
<li><strong>Confirm-by-guess, mode (a).</strong> If the digest inputs are enumerable, an observer can test
candidate parameter sets against the public digest. P4 of <xref target="properties"></xref> is the mitigation and
it is load-bearing, not hygiene.</li>
<li><strong>Confirm-by-guess, mode (b) — closed against an outside observer, by the seed rather than by
this document.</strong> The carried value's pre-image contains the derivation's seed, so an observer of
the external system holds a value it cannot test a candidate parameter set against, and cannot
recover the digest from. What is doing the work is the seed's secrecy, not the digest's
construction; the protection therefore lasts exactly as long as the seed is withheld, and not
one moment longer.</li>
<li><strong>Disclosure by evidence sharing — unchanged in kind, and larger under mode (b).</strong> Handing a
third party the material needed to recompute the digest permanently grants them the ability to
locate the corresponding external event. <strong>A relying party receiving an evidence bundle gains a
durable capability, not a one-time view.</strong> Under mode (b) that material necessarily includes the
derivation's seed, so the same disclosure also hands over the only thing standing between the
bundle holder and item 2 — the outside observer's closed channel is open to every bundle holder,
permanently, before or after the external event exists. Implementations SHOULD make this
explicit to the approving human before the first embedding, and SHOULD NOT embed digests for
actions whose existence is itself sensitive.</li>
</ol>
</section>
</section>

<section anchor="iana"><name>IANA Considerations</name>
<t><tt>[PLACEHOLDER — pending working group direction]</tt>. The provisional intent:</t>

<ul spacing="compact">
<li><strong>Media type registration</strong> (<xref target="RFC6838"></xref>) for the digest's carrier artifact, provisionally
<tt>application/noa-action-digest+json</tt>, and — if a COSE profile (<xref target="RFC9052"></xref>, <xref target="RFC9053"></xref>) of this
artifact is adopted — <tt>application/noa-action-digest+cose</tt>.</li>
<li><strong>A registry for NOA signing-domain tags</strong>, policy <em>Specification Required</em>. <strong>Rationale:</strong>
domain separation is the core anti-cross-protocol mechanism (P2 of <xref target="properties"></xref>), and today the
uniqueness of those tags is asserted only in the reference implementation's source. A registry is
the correct home for a value whose whole purpose is global distinctness. Note that a registry
named for <em>signing</em> domains does not, without widening, accommodate this document's <em>hashing</em>
tag.</li>
<li><strong>No COSE header label is requested by this document.</strong> Were one needed later, the COSE Header
Parameters registry policy is <em>Standards Action With Expert Review</em> for 1-255, <em>Specification
Required</em> for 256-65535, and <em>Expert Review</em> above 65535; the highest currently assigned integer
label is 396 (<xref target="RFC9942"></xref>).</li>
<li><strong>No OAuth registry action.</strong> <xref target="RFC9396"></xref> registers the <tt>authorization_details</tt> parameter and
related metadata, but <strong>type values are not IANA-registered</strong>: Section 2.1 only <strong>RECOMMENDS</strong>
that <tt>type</tt> identifiers be collision-resistant, and Section 14 creates no <tt>type</tt> registry — so
there is nothing to register for an <tt>authorization_details</tt> projection of this digest.</li>
</ul>
</section>

<section anchor="changelog"><name>Change log</name>
<t>[[RFC EDITOR: please remove this section before publication.]]</t>
<t>Changes since -00: author metadata completed (country, explicit submission date). No technical
changes; every normative statement, conformance count and reference is byte-identical to -00.</t>
</section>

</middle>

<back>
<references><name>References</name>
<references><name>Normative References</name>
<reference anchor="FIPS180-4" target="https://csrc.nist.gov/pubs/fips/180-4/upd1/final">
  <front>
    <title>Secure Hash Standard (SHS)</title>
    <author>
      <organization>National Institute of Standards and Technology</organization>
    </author>
    <date year="2015" month="August"></date>
  </front>
  <seriesInfo name="FIPS" value="PUB 180-4"></seriesInfo>
</reference>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.2119.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.6838.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8174.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8785.xml"/>
</references>
<references><name>Informative References</name>
<reference anchor="I-D.toraman-noa-settlement-evidence" target="https://datatracker.ietf.org/doc/draft-toraman-noa-settlement-evidence/">
  <front>
    <title>Settlement Evidence for Human-Approved Agent Payments</title>
    <author fullname="Tora Toraman" initials="T." surname="Toraman">
      <organization>NordenSoft</organization>
    </author>
    <date year="2026"></date>
  </front>
  <seriesInfo name="Internet-Draft" value="draft-toraman-noa-settlement-evidence-00"></seriesInfo>
</reference>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.7942.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.9052.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.9053.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.9396.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.9942.xml"/>
</references>
</references>

<section anchor="impl-status"><name>Implementation status</name>
<t><em>This section is to be removed before publication as an RFC, per <xref target="RFC7942"></xref>.</em></t>
<t>A zero-runtime-dependency reference implementation, together with the <strong>Copenhagen vectors</strong> — the
cross-language conformance corpus this document's construction is enforced by — is available under
the Apache-2.0 license at <eref target="https://github.com/NordenSoft/noa">https://github.com/NordenSoft/noa</eref>.</t>
<t>The following were measured, in that repository, on 2026-08-14, at <tt>main</tt> commit <tt>7aa8e37</tt>:</t>

<ul spacing="compact">
<li>The digest construction and its normative prose: <tt>docs/action-digest-spec.md</tt>; implementation
<tt>src/action-digest.ts</tt>.</li>
<li>The Copenhagen vectors for this document: <tt>conformance/action-digest/vectors.json</tt> — 33 cases,
1 ACCEPT and 32 REJECT, generated from fixed seeded keys, each rejection pinning the substring of
the refusal reason it measures. Named cases include cross-tenant replay, cross-chain replay, retry
non-collision, field transposition, wrong-domain-tag, no-domain-tag, and a
<tt>/0.2</tt>-spelled-as-<tt>/0.1</tt> refusal.</li>
<li>The knockout sweep over those controls, stated exactly rather than rounded up: <strong>eight</strong> Action
Digest controls are registered in the repository's control-knockout registry
(<tt>scripts/lint-control-knockout.mjs</tt>) and are proven to turn a named vector red when the control
is removed — the ALLOWED-verdict requirement, the blank-scope-identifier refusal, chain
authentication, grant-signature verification, the closed <tt>sig</tt> object, authorization selection by
grant binding, the expected-tenant/chain check, and domain separation. <strong>Not all 32 rejections are
knockout-gated, and the gap is structural rather than an omission:</strong> the registry records that the
projection's <tt>actionId</tt>, <tt>actionCanonical</tt>, <tt>actionParamsHash</tt>, <tt>executionGrantId</tt> and
<tt>executionNonce</tt> members cannot be isolated, because <tt>authorizationReceiptHash</tt> and
<tt>executionGrantHash</tt> are hashes over the whole receipt and the whole grant — any mutation that
moves one of those five moves a whole-document hash too, so the attack is refused either way and a
knockout that &quot;passed&quot; for that reason would be vacuous.</li>
<li>P4's nonce source: the single-use nonce is the Execution Grant's <tt>nonce</tt>. The grant schema pins
it to <tt>^[0-9a-f]{64}$</tt> (<tt>packages/approval-artifacts/schema/noa-execution-grant-0.1.schema.json</tt>)
and the gate generates it as 32 CSPRNG bytes rendered as 64 lowercase hex
(<tt>packages/gate/src/trust.ts</tt>), refusing loudly rather than minting a nonce that fails that
pattern. That is 256 bits against P4's 128-bit floor. <strong>This is a producer property, not a
verifiable one:</strong> a conforming verifier cannot distinguish this generator from a counter, which
is why P4 is written as an obligation with a disclosed residual.</li>
<li>Mode (b) of <xref target="embedding"></xref>: the reference implementation carries a <strong>derived</strong> value on its target
rail, never this digest — <tt>packages/rail-x402/src/correlation-nonce.mjs</tt> performs the derivation
and <tt>packages/rail-x402/src/settlement-evidence.mjs</tt> recomputes it during verification. The
Execution Grant nonce measured above is that derivation's seed, so the one measurement carries
both of the loads P4 names.</li>
<li>Key custody, anchor 2 of <xref target="anchors"></xref>: the reference implementation documents its own open
weakness in <tt>NON-CLAIMS.md</tt> — the execution-grant signing key is held as a string in the process
the grants are meant to defend. No claim of unforgeable authority is made for it until that key
leaves the process and the signer validates approval proof per signature.</li>
</ul>
</section>

</back>

</rfc>
