Arbiter Decision Attestation Format
Version 0.1 · Draft
An open format for records of automated decisions that a third party can verify
without trusting the party that produced them.
This specification is published openly and may be implemented by anyone,
including competitors. That is deliberate. A format only becomes useful to a
supervisor when more than one vendor emits it, and an evidence format nobody
else can produce is not evidence — it is a lock-in.
1. Scope and motivation
When an automated system makes a decision that must later be defended — a credit
decline, a fraud block, a benefits determination, an employment screening — the
institution is normally expected to produce "the log." A log records what a
system reported it did. It does not let anyone re-derive that decision from the
inputs that produced it, and it cannot demonstrate that it was not edited
afterwards.
The gap is measurable. On 30,000 real credit customers, retraining a model with
the customer population held completely constant caused re-running the current
system to misreport 15.5% of past decisions (95% CI 14.7–16.3). The model had
improved. That is precisely why the reconstruction moved.
EU AI Act Article 12, in force since 2 August 2026, requires high-risk AI systems
to record events automatically over their lifetime, retained at least six months,
and states that manual documentation does not satisfy this. It requires that
records exist. It does not require them to be tamper-evident or independently
checkable. This format addresses that second gap.
1.1 What this format does not claim
Determinism holds over pinned, exact-valued inputs: the recorded score,
thresholds, and outcome are recoverable bit-for-bit. Re-deriving a score from raw
inputs through a non-deterministic model is a different and unsolved problem, and
nothing here should be read as solving it.
2. Conventions
The key words MUST, MUST NOT, SHOULD, and MAY are to be interpreted as described
in RFC 2119.
An implementation conforms to this specification only if it passes every
vector in conformance-vectors.json, including every case listed under
must_reject. An implementation that accepts a receipt in must_reject does not
conform. Leniency here is not a lesser conformance; it is a verifier that will
accept forged evidence.
3. Canonical form
All signatures and digests are computed over canonical JSON.
A canonical encoding MUST:
- encode as UTF-8, emitting non-ASCII characters literally rather than as
\u
escapes;
- order object keys by Unicode code point, recursively at every depth;
- preserve array order, which is significant and MUST NOT be sorted;
- emit no insignificant whitespace, using
,and:as separators; - exclude any
signaturemember from the preimage of the object that carries
it, so an object can be signed and then carry its own signature.
Canonicalisation is where independent implementations diverge silently: key
ordering, unicode escaping, and number formatting all differ between language
defaults, and any one of them produces a valid receipt that fails verification in
another implementation. Implementers SHOULD treat section 3 vectors as a gate
rather than a smoke test.
4. Receipt
A receipt binds one decision to the state that produced it.
| Field | Binds |
|---|---|
action.mandate_id | the model version that decided |
action.params.model | model name, version, feature-store snapshot |
action.params.features | the exact feature vector read at scoring |
action.params.thresholds | the cutoffs then in force |
action.params.score | the score as emitted, as a decimal string |
action.params.outcome | the outcome taken |
verdict.reasons | the rule path that produced it |
verdict.authorizer_id | signing identity, hex Ed25519 public key |
verdict.signature | Ed25519 over the canonical verdict |
seq, prev_hash, this_hash | position in the hash chain |
score and the threshold values MUST be represented as decimal strings, not
JSON numbers. A cutoff comparison performed in binary floating point can be wrong
by one representable value, which is a wrong decision carrying a valid signature.
4.1 Verification
A verifier MUST perform all three checks and MUST fail if any fails:
1. Signature. Ed25519 over the canonical verdict with signature removed,
against verdict.authorizer_id.
2. Re-derivation. Re-classifying the pinned score under the pinned
thresholds MUST reproduce the recorded outcome.
3. Integrity. this_hash MUST equal SHA-256 over the canonical form of
{seq, prev_hash, action, verdict}.
A verifier MUST NOT require network access, an account, or any interaction with
the issuer. If it does, the format has failed at its only purpose.
4.2 Uniqueness
A given decision_id MUST be attested at most once. Without this, re-attesting
produces a second receipt that also verifies — it chains at a new position, so
its hash legitimately differs — and nothing in the record establishes which of
two contradictory attestations governs.
5. Merkle commitments
Trees follow RFC 6962.
leaf_hash(d) = SHA-256(0x00 || d)node_hash(l, r) = SHA-256(0x01 || l || r)- The empty tree hashes to
SHA-256(""). - For
n > 1, split atk, the largest power of two strictly less thann.
The 0x00/0x01 prefixes are load-bearing: without domain separation a leaf can
be presented as an internal node. The split rule is equally load-bearing —
duplicating a final odd node instead allows two differently-shaped trees to
produce the same root.
Leaves commit to a receipt's this_hash, not its payload. This is what
allows a receipt body to be destroyed under an erasure obligation while the root
and every proof already issued remain valid.
5.1 Inclusion proofs
An inclusion proof demonstrates one receipt is in a committed set using
O(log n) sibling hashes and reveals nothing about any other receipt. The path
is ordered innermost sibling first.
Verifiers MUST reject a path of the wrong length rather than raising, and MUST
NOT crash on malformed input. A verifier is an adversarial surface.
5.2 Consistency proofs
A consistency proof demonstrates that a later tree append-only extends an earlier
one. Anchoring without it proves only that a root existed: an issuer could
publish a root, rewrite history, publish a new root, and every inclusion proof
against the new root would still verify. Implementations that anchor SHOULD
publish consistency proofs between successive anchors.
6. Key transparency
Where a supervisor may rely on a signature, an issuer SHOULD publish an
append-only log of which key was in force over which period. Verifying a
signature establishes that a key signed. Only the log establishes that it was
the institution's key on the day of the decision.
An epoch MUST record only when a key came into force. It MUST NOT store an end
time; the end is implied by the successor's start. Storing it would require
rewriting a committed record whenever a key rotates, and any party able to do
that legitimately can also do it illegitimately.
7. Conformance
Run the vectors. conformance-vectors.json contains:
- 10 canonicalisation cases, each with expected canonical bytes and digest
- 10 Merkle trees, with 72 inclusion and 72 consistency proofs
- 3 receipts that MUST verify
- 7 receipts that MUST be rejected
The reference implementation checks itself with python -m signet.conform, and
the same vectors are the contract for any other implementation.
8. Security considerations
- Fail-open placement. An attestation layer MUST NOT be able to block the
decision it observes. A component that can halt a credit decision has become
part of the decision path. Failures SHOULD be recorded as counted coverage gaps
rather than raised, and gaps MUST be surfaced rather than silently absorbed.
- Key custody. Software signing proves a record is self-consistent, not who
produced it. Where a supervisor relies on the signature, the key SHOULD sit in
an HSM or KMS the signing process cannot read.
- What deletion still achieves. Write-once storage prevents edits, not
deletion of the whole store. Anchoring a root outside the issuer's control is
what makes destruction detectable rather than silent.
- Fuzzy and non-deterministic paths. Out of scope, and any implementation
extending to them MUST NOT present the result as bit-exact replay.
9. Licence
This specification is published under Apache-2.0, including its patent grant.
Implementations owe no royalty and need no permission.