Real program output · verified in your browser

Two companies. One registry. Neither can read the other's records.

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.

loading the fixture… SHA-256 · Ed25519 no API · no analytics · no font CDN
Before anything else

What you are looking at, and what it is not

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.

what it is

Output, not prose

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.

what it is

Checked here, not asserted

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.

what it is not

Two runs, not one timeline

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.

what it is not

Not a live service

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.

Act 1 · Two vaults

One registry, two organisations, two separate records

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.

What each record actually contains The first record is the anchoring event: the organisation, the assurance tier it reached, and when. The next three are decisions: a payment allowed, a larger one held for a human, and the same one allowed after that human approved it. Each carries the coded reasons the engine emitted — action:human-approval-required, not a sentence someone wrote afterwards.
You may have noticed records #2 and #4 share a hash They do, and it is worth understanding rather than explaining away. This run uses a frozen clock so the fixture is byte-reproducible, so two identical allow decisions — same tool, same authority, same timestamp — canonicalise to identical bytes and therefore hash identically. A record hash is not an event identifier, here or anywhere: it identifies content. The chain still tells them apart, because each record's signature covers its position and the link to what came before, which is why both verify and neither can be swapped for the other. In production the timestamps differ and the question does not arise — but a demonstration that quietly varied its data to avoid the collision would be hiding the more interesting fact.
Act 2 · Attribution

Take one company's records and present them as another's

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.

choose a combination
every pairing is verified in your browser
What the signature covers, and why each field is there

      The domain stops a record signed for one product replaying as a record of another. The
      chain id stops a whole history being lifted between organisations. The sequence number
      stops a valid record being moved to another position. The previous hash binds it to what
      came before. Remove any one of them and one of the attacks on this page starts working.
    
Act 3 · Your turn

Break a chain, and watch where it fails

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.

Chain intact
The one attack verification cannot catch by itself Turn off the checkbox above and try attack 4 again. A truncated chain is a valid chain — every hash recomputes, every link holds, every signature is genuine, and nothing in the records says how many there should have been. Verification can only check what it was handed. The only thing that catches it is a commitment 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.
Act 4 · Withdrawing authority

The same request, two minutes apart

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.

Why the reasons are codes and not sentences 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.
Act 5 · The negative claim

What the record deliberately does not contain

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.

sweeping
searching every canonicalised record for each value
Value the run handledWhere it actually livesIn the records?
The honest limit on this claim
The architect's question

Why these choices

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.

Ed25519 · RFC 8032

Deterministic signing

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.

Canonical JSON

Same facts, same hash

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.

Domain and chain binding

A signature knows where it lives

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.

Refusals are failures

A missing signature is not a skip

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.

Minimisation at the boundary

The record drops what it does not need

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.

Two implementations

Go and JavaScript, cross-checked

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.

Reality & roadmap

What is built, what is not, and what this page does not prove

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.

Where the line is on 31 August 2026

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.

running
The engine. Organisation anchoring, agent classes countersigned and logged, short-lived instance identities, scoped mandates, an enforcement point, and a signed evidence chain per organisation — all exercised by the acceptance run that produced this page's data.
running
The operator console, live and behind single sign-on, with two-person control on the destructive actions. Not public, and not shown here.
not yet
No public verification service. This page ships a fixture because there is nothing to call. That is also why it can make the offline claim honestly — but it is a limitation first and a feature second.
test doubles
The credential issuer and wallet in this run are the project's own test doubles. The verification performed against them is cryptographically real; the counterparties are not. Anchoring against real qualified credentials needs a root bundle we have not deployed.
roadmap
Private beta is the next milestone, not a shipped product.
never
We will not tell you a record proves your case. These are operational records with checkable provenance. What they are worth in a dispute is for your advisers, and anyone claiming otherwise about their own product is selling you something.
Read from the fixture — claims this data does not support