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.
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.
| # | Step | Decision | Time (UTC) |
|---|---|---|---|
| 0 | execute_transfer | DENY — SEQUENCE_VIOLATION"Step submitted out of order" | 23:21:38 |
| 1 | verify_identity | ALLOW | 23:24:34 |
| 2 | assess_risk | ALLOW | 23:24:44 |
| 3 | execute_transfer | ALLOW | 23:24:50 |
| 4 | audit_ledger | ALLOW — sealed: true | 23: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.
| # | Step | Signature | Chain link |
|---|---|---|---|
| 0 | execute_transfer | valid | chain start — no prior receipt |
| 1 | verify_identity | valid | no prior ALLOW to anchor to — null-anchored |
| 2 | assess_risk | valid | links to 4732664cc6510c6e…, hash-links to 6c7a712da7482378… |
| 3 | execute_transfer | valid | links to a088783b7876f2b3…, hash-links to 567b87bcb771279d… |
| 4 | audit_ledger | valid | links to f5f2ac28deba573d…, hash-links to 99515775926501e5… |
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 key — k2_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.
Python — pip 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
| Field | Value |
|---|---|
| verification_status | VERIFIED_INTACT |
| seal_status | SEALED — no further step can be added |
| signatures | 5 valid · 0 invalid · 5 third-party verifiable |
| hash chain | 3 verified · 0 broken · 2 not verifiable (see the note above) |
| independent archive | match — 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
- It establishes the order. Which steps were permitted, in what sequence, and that the record has not changed since it was written.
- It does not establish that permitted work succeeded. An ALLOW means the step was permitted. The executor's outcome is reported separately and is not signed into the receipt.
- Timestamps are asserted, not attested.
ts_msis generated by AgenticRail and covered by the signature, so it cannot be altered afterwards without breaking verification. That is a record of when, not proof of when. - AgenticRail holds the signing keys. The gate is independent of the agent, which can neither instruct it nor edit its output. It is not independent of us. The archive comparison above is what narrows that gap; it does not erase it.
- Offline-verifiability is per-receipt. Every receipt here is Ed25519 with
third_party_verifiable: true. Legacy HMAC receipts elsewhere are confirmed server-side only. Check the field; do not assume it holds for a whole chain.
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.