When an autonomous agent spends money, someone will later ask three questions: who authorised it, what were they allowed to do, and can you prove it without taking your word for it. Everything below is the output of a run that actually happened — two organisations driven end to end through the real code, with their own keys and their own separate records. This page checks those records here, in your browser, and shows you every place the check fails when it should.
Demonstrations usually show a script. This one ships the bytes a real run produced, and then recomputes them in front of you. That is a stronger claim, so it comes with stricter limits — stated here rather than buried at the bottom.
Every hash, signature and coded reason on this page came out of the Go implementation and was written to a fixture file. The generator is deterministic and self-verifying: it refuses to emit a fixture whose chains do not check out.
The page recomputes each record's canonical form, its hash and the exact bytes its signature covers, then verifies with WebCrypto. If this page's arithmetic ever disagreed with the Go code, it would say so on screen rather than quietly agreeing.
The two-organisation run and the revocation walkthrough are separate runs shown side by side. The first has no revocation; the second has no evidence chain. Presenting them as one story would be the first thing an auditor caught.
There is no public API behind this page. The credential issuer and wallet in the run are the project's own test doubles, not a real qualified trust service. The clock is frozen, so nothing here supports any claim about speed.
Both organisations were driven through the same code, in the same run, against the same registry. Each ended with its own signing key and its own chain of four records: how the organisation proved who it was, then three decisions its agent made. Neither chain verifies under the other's key — that is Act 2, and it is not a coincidence.
action:human-approval-required, not a sentence someone wrote
afterwards.
This is the attack that matters for a registry. A chain is internally perfect — every hash recomputes, every link holds, every signature is genuine — and it is simply relabelled as somebody else's history. Until 31 August 2026 that worked, in this codebase, because the signature did not cover whose chain it was.
Pick an attack. The page mutates the records in memory and re-verifies. The last one is the interesting one, because it is the only attack on this page that verification cannot catch on its own.
… that somebody wrote down
earlier and independently. That is why an auditor keeps that one line, and why we publish
it rather than storing it beside the records it protects.
An agent's authority was withdrawn at 14:02 — a bad tool update, say, or a compromised deployment. Not a policy change queued for the next deploy: the identical call, made minutes apart, gets two different answers, and the refusal itself is recorded.
step3:class-log and step5:revoked are what the engine
emitted, naming which checks refused and in what order. A sentence would be a human's summary of a
decision; these are the decision. They are also stable enough to count, alert on and reconcile
against a record months later — which prose is not.
The run handled a company's registered name, the email of the person who approved a payment, the identifiers of two operators, and two monetary amounts. None of them appear anywhere in the records. That is a negative claim, which is the hardest kind to believe — so it is swept mechanically, over the exact bytes the signatures cover, and the sweep runs in the project's own test suite rather than only here.
| Value the run handled | Where it actually lives | In the records? |
|---|
Nothing here is novel cryptography, deliberately. Every primitive is old, standardised, and implemented in tooling the other side already trusts — because a construction that has to be defended is a construction that is not doing its job.
No per-signature random nonce, so no nonce-reuse failure — the mode that has repeatedly leaked private keys in the wild. Verifies with stock OpenSSL and, as this page shows, with the browser's own WebCrypto.
Keys sorted recursively, no whitespace. One subtlety we had to close: a payload field named
__proto__ vanished from the canonical form in JavaScript while remaining
visible in the record — and Go, having no such magic key, disagreed on the hash.
Covering the domain, the chain, the position and the previous hash is what makes Act 2 fail. For a registry whose claim is this organisation authorised this, attribution is the one thing a signature must carry.
A verifier that shrugs at an absent signature makes deleting signatures the attack. This one fails closed — and so does a public key it cannot load, which is subtler and was a real defect in a sister product's demo until it was caught.
Amounts and approver identities are dropped where the record is built, not filtered on the way out. A filter can be forgotten; a mapper that never carries the field cannot leak it.
The chains were produced in Go and are verified here in JavaScript. Two independent implementations agreeing on the same bytes is worth more than one implementation being confident.
SignWard is pre-beta and we would rather you heard the limits from us. The list below is generated from the fixture itself, so it cannot drift from what is actually on this page.
The engine is substantial and its operator console is live behind sign-in. What is missing is a public surface, and we are not going to pretend otherwise.