# A Verified Agent Execution Record: One Sealed Sequence, Checked Offline

> Markdown mirror for AI agents, generated 2026-10-10 from the live page.
> Canonical: https://agenticrail.nz/proof/
> Site context: https://agenticrail.nz/llms.txt

# 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.

**Why the name is evidence rather than a label.** The caller sent `payment-workflow-001`. The `demo-mcp-` in front of it was added by the gate, not chosen by them, and it cannot be removed by the caller. It is the tag applied to an anonymous call arriving through the public MCP server. The rule is published in the server's own tool description, which anyone can fetch and read:

```
curl -s -X POST https://mcp.agenticrail.nz/ -H 'Content-Type: application/json' -H 'Accept: application/json, text/event-stream' -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
```

Run a sequence against that server yourself with no `Authorization` header and your own id gets the same prefix. A record we wrote ourselves would not carry it. **And the same caller's other runs that hour did not go well:** an earlier test was refused outright, and a later sequence took a single ALLOW followed by seven consecutive denials before they stopped and did not come back. Those failures are in the same public lane and readable the same way. A staged showcase does not include the part where the visitor gives up.

## 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.

If it is not obvious why that is worth anything, the short version is that this is the only kind of failure with no artefact of its own. A wrong answer can be read. A crash leaves a trace. A step that was never taken leaves a record identical to a run where it was never required, and no amount of logging closes that gap, because there is nothing to log. [Why a skipped step leaves nothing behind](https://agenticrail.nz/blog/ai-agent-skipped-steps-audit-logs/) sets that out at length, in the body before the software.

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 last permitted receipt before it, so altering a permitted record changes a hash and is detectable here, and altering any record, refused ones included, breaks its signature.

| # | 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…` |

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 key** — `k2_2026-06-07_ed25519`, SPKI, base64. Published inline here on purpose, so verification needs no fetch of any kind.

`MCowBQYDK2VwAyEA1ejM0xb/nkaPO8NhNWtXHOpqR1BgYqAOLWqig02FZdI=`

## Offline verification, step by step

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_ms` is supplied by the caller and covered by the signature, so it cannot be altered afterwards without breaking verification. The gate refuses any timestamp more than 300 seconds from its own clock, which bounds the claim without establishing it. 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](https://agenticrail.nz/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](https://agenticrail.nz/docs/) has the same thing as a copy-paste request if you would rather use a terminal, and the [verifier](https://report.agenticrail.nz/report) 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](https://agenticrail.nz/product/) — the enforcement gate that produced this record.

[The Completeness Specification](https://agenticrail.nz/spec/completeness/) — the eight requirements that separate an evidence-grade record from an ordinary log, and the criteria an auditor tests against.

[The Enforcement Specification](https://agenticrail.nz/spec/) — decision architecture, receipt fields, signing and the sealed chain.

[Tamper-evident, and the two words that overstate it](https://agenticrail.nz/blog/ai-agent-audit-log-best-practices/) — of the three terms in common use for audit-log integrity, only one describes something achievable.

He toi whakairo, he mana tangata
