A verified agent execution record, in full

One sealed sequence. Five steps, one of them refused. Every signature and every signed byte published here, so you can check it yourself without an account.

Most claims about agent audit trails are descriptions of a mechanism. This is the artefact. Below is a complete enforcement record for a real sequence, exactly as the verifier returns it, with enough published alongside it that a stranger can confirm the signatures offline and needs to trust neither the operator nor us.

The sequence

demo-mcp-payment-workflow-001 — sealed 6 August 2026. It was produced by a third party calling the public MCP server, not written by us to look good. It needs no key: the report below is open to anyone.

What happened

An agent working a payment flow attempted to execute the transfer as its first action, before identity had been verified or risk assessed. The gate refused it. Nearly three minutes later the agent returned and ran the steps in order, and the transfer was permitted.

#StepDecisionTime (UTC)
0execute_transferDENYSEQUENCE_VIOLATION
"Step submitted out of order"
23:21:38
1verify_identityALLOW23:24:34
2assess_riskALLOW23:24:44
3execute_transferALLOW23:24:50
4audit_ledgerALLOW — sealed: true23:24:55

Elapsed from first decision to last: 196.742 seconds. The two-minute-fifty-six gap between the refusal and the retry is the agent responding to the denial.

The step that did not run

This is the part an ordinary audit log cannot produce. Step 0 was refused before it executed, and a signed record of that refusal exists.

A log records what happened. A step that never ran leaves no entry, and absence leaves no trace — so a log has nothing to say about the payment that was attempted out of order. Here the attempt is in the record, signed, with the reason, and it is as verifiable as any of the permitted steps.

The signed bytes for that receipt carry "decision":"DENY" and "executed":false. The permitted steps carry "executed":true. In this schema executed means the step was permitted, not that its downstream work succeeded — see the limits at the end.

How the chain holds

Each receipt commits to the exact bytes of the receipt before it, so altering an earlier record changes a hash and is detectable here.

#StepSignatureChain link
0execute_transfervalidchain start — no prior receipt
1verify_identityvalidno prior ALLOW to anchor to — null-anchored
2assess_riskvalidlinks to 4732664cc6510c6e…, hash-links to 6c7a712da7482378…
3execute_transfervalidlinks to a088783b7876f2b3…, hash-links to 567b87bcb771279d…
4audit_ledgervalidlinks to f5f2ac28deba573d…, hash-links to 99515775926501e5…
Read the hash-chain count carefully

The verifier reports 3 verified, 0 broken, 2 not verifiable. The two that are not verifiable are receipts 0 and 1, and that is correct rather than a gap: the chain anchors to the last permitted receipt, so nothing before the first ALLOW has a predecessor to hash against. A null anchor is legitimate exactly when no ALLOW precedes it. Reading "2 not verifiable" as two unchecked receipts is the misreading this note exists to prevent — their signatures are valid, they simply have nothing behind them.

One receipt, complete

Receipt 0, the refusal. These are the exact bytes the signature was computed over — 603 bytes of UTF-8, keys sorted, no whitespace variation.

signed_canonical

{"attestation":null,"decision":"DENY","executed":false,"key_id":"k2_2026-06-07_ed25519","meta":{"action_type":"CHECK_STATE","function":"execute_transfer","model_id":"client:demo","policy_map_ids":[],"sequence_id":"demo-mcp-payment-workflow-001","step":"execute_transfer"},"pack_id":"80d4a564ada10a11d759b557391f125334749aebb867d2e9eb71ea79f305dbf2","payload_hash":"21bfad36b9b646a8cc82ccf2c389f587cee0fb1b8819254b8b9633cab5b2c4de","prev_receipt_hash":null,"prev_receipt_id":null,"reasons":["SEQUENCE_VIOLATION"],"sealed":false,"signature_alg":"Ed25519","ts_ms":1786058498833,"version":"slp8_receipt_v2"}

signature (Ed25519, base64)

TcYRiuYF95py78A/cS7vULbxIN7h+AKfMuDD5LSoRX+3w4fdFUJ/lB03JSWASGwZ4zvwnhGNPEF7VJRSSubAAA==

public keyk2_2026-06-07_ed25519, SPKI, base64. Published inline here on purpose, so verification needs no fetch of any kind.

MCowBQYDK2VwAyEA1ejM0xb/nkaPO8NhNWtXHOpqR1BgYqAOLWqig02FZdI=

Verify it yourself, offline

The whole check is one line of intent: ed25519_verify(public_key[key_id], utf8_bytes(signed_canonical), base64_decode(signature)). Nothing below touches the network.

Pythonpip install cryptography

import base64
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey

SPKI_B64  = "MCowBQYDK2VwAyEA1ejM0xb/nkaPO8NhNWtXHOpqR1BgYqAOLWqig02FZdI="
SIGNATURE = "TcYRiuYF95py78A/cS7vULbxIN7h+AKfMuDD5LSoRX+3w4fdFUJ/lB03JSWASGwZ4zvwnhGNPEF7VJRSSubAAA=="
CANONICAL = r'''PASTE THE signed_canonical LINE ABOVE, EXACTLY'''

raw_pub = base64.b64decode(SPKI_B64)[-32:]   # last 32 bytes of the DER are the key
Ed25519PublicKey.from_public_bytes(raw_pub).verify(
    base64.b64decode(SIGNATURE), CANONICAL.encode("utf-8"))
print("signature valid")

JavaScript — WebCrypto, no dependencies

const b64 = s => Uint8Array.from(atob(s), c => c.charCodeAt(0));

const key = await crypto.subtle.importKey(
  "spki", b64("MCowBQYDK2VwAyEA1ejM0xb/nkaPO8NhNWtXHOpqR1BgYqAOLWqig02FZdI="),
  { name: "Ed25519" }, false, ["verify"]);

const ok = await crypto.subtle.verify("Ed25519", key,
  b64("TcYRiuYF95py78A/cS7vULbxIN7h+AKfMuDD5LSoRX+3w4fdFUJ/lB03JSWASGwZ4zvwnhGNPEF7VJRSSubAAA=="),
  new TextEncoder().encode(CANONICAL));

console.log(ok ? "signature valid" : "signature INVALID");

Change one character of the canonical string and it fails. That is the whole property.

The verifier's own verdict

FieldValue
verification_statusVERIFIED_INTACT
seal_statusSEALED — no further step can be added
signatures5 valid · 0 invalid · 5 third-party verifiable
hash chain3 verified · 0 broken · 2 not verifiable (see the note above)
independent archivematch — copy received 2026-08-06T23:24:56.79Z

That last row is a separately credentialled write-once store holding its own copy of each sealed receipt. It is compared at every verification, which is what makes a wholesale rewrite by a key holder detectable rather than silent.

What this establishes, and what it does not

Now do it with your own

The same report is generated on demand for any sequence. The browser demo runs a real sequence against the live gate on the public demonstration key, then opens the signed report for that run in one click — keyless, nothing to copy. The documentation has the same thing as a copy-paste request if you would rather use a terminal, and the verifier takes a sequence identifier directly if you already have one.

Anything placed in attestation on a demonstration sequence is world-readable, because its report needs no key. Treat the demo lane accordingly.

What AgenticRail is, and what it is used for — the enforcement gate that produced this record.

The Completeness Specification — the eight requirements that separate an evidence-grade record from an ordinary log, and the criteria an auditor tests against.

The Enforcement Specification — decision architecture, receipt fields, signing and the sealed chain.

Tamper-evident, and the two words that overstate it — of the three terms in common use for audit-log integrity, only one describes something achievable.

He toi whakairo, he mana tangata