Decionis
Verify a Decision Dossier

Check the record yourself.

Every decision Decionis governs produces a Decision Dossier: a signed record of what was proposed, which policy version judged it, and what happened next. It is signed with Ed25519 against a public key we publish, so you can check it without an account — and without taking our word for the result.

Open a dossier you were sent

Paste the whole verification link. If you only have the dossier id, you will also need the sig token that came with it — a dossier cannot be opened from its id alone.

Nothing is sent to Decionis from this form — it only builds the link to the dossier.

What is checked when you open one

The dossier page reports four checks and states each one plainly, including when a check fails. A failing signature is shown as a failure — it is never rounded up to “unverified”.

Signature

The Ed25519 signature over each signed document verifies against the public key published in our JWKS. This is the check that makes the record ours and unaltered.

Policy snapshot

The dossier names the policy version that governed the action, along with hashes of the rules and parameters in force at evaluation time — so the policy can be pinned, not just described.

Chain integrity

The dossier's entry hashes into the decision ledger, and that chain is intact. A record cannot be quietly removed or reordered after the fact.

Proof bundle

Each signed artifact's canonical SHA-256 digest matches the document it covers. A bundle that is present but fails this check is reported as failed, not as unverified.

Verify it without this page

A verification page run by the vendor being verified is worth exactly as much as the method behind it. So here is the method. Every input is public, and the check runs on your machine against a key you fetch yourself.

Algorithm

Ed25519 (EdDSA)

One signature per signed document, over its canonical bytes.

Canonical form

sort keys → JSON.stringify

Object keys sorted recursively; arrays and scalars left in place. Deliberately boring, so it is reimplementable in any language.

Public key

Published as a JWKS. Rotation keeps superseded keys listed through a grace window, so an older dossier stays verifiable after a rotation.

https://api.decionis.com/v1/.well-known/decision-dossier-jwks.json

One command

The dossier page links its public proof bundle. Hand that URL to the open verifier and it fetches the bundle, discovers the JWKS from it, and runs every check locally.

npx @decionis/verify "<proof-bundle URL from the dossier page>"
  • Exit code 0 verified, 1 not verified, 2 a usage or IO error — so it drops into CI as a gate.
  • Add --json for machine-readable output, or --file dossier.json --jwks https://api.decionis.com/v1/.well-known/decision-dossier-jwks.json to check a dossier you saved earlier.
  • Zero runtime dependencies, Node’s built-in crypto only. It talks to nothing except the public proof bundle and the public JWKS.

Or reimplement it — the method is small

Nothing above is privileged. If you would rather not run our code at all, these are the four steps the verifier performs, in any language:

  1. 1

    Fetch the dossier's public proof bundle — the dossier page links it, and the response carries the signed documents plus the absolute JWKS URL.

  2. 2

    Fetch that JWKS and pick the Ed25519 key whose kid matches the bundle's key id.

  3. 3

    For each artifact in the bundle, canonicalise the document it points at, and check its SHA-256 against the digest recorded in the bundle.

  4. 4

    Verify the artifact's Ed25519 signature over those same canonical bytes. All artifacts must pass.

// verify-dossier.mjs — Node 18+, no dependencies.
// Usage: node verify-dossier.mjs "<proof-bundle URL from the dossier page>"
import { createHash, createPublicKey, verify } from "node:crypto";

const { dossier_payload, jwks_url } = await (await fetch(process.argv[2])).json();
const { keys } = await (await fetch(jwks_url)).json();

// Canonical JSON: sort object keys recursively, leave arrays and scalars alone.
const canonical = (value) =>
  Array.isArray(value)
    ? value.map(canonical)
    : value && typeof value === "object"
      ? Object.fromEntries(Object.keys(value).sort().map((k) => [k, canonical(value[k])]))
      : value;

const bundle = dossier_payload.integrity.proof_bundle;
const jwk = keys.find((k) => k.kty === "OKP" && k.crv === "Ed25519" && k.kid === bundle.key_id);
const publicKey = createPublicKey({ key: jwk, format: "jwk" });

for (const artifact of bundle.artifacts) {
  const document = artifact.document_path
    .split("/")
    .slice(1)
    .reduce((node, segment) => node?.[segment], dossier_payload);
  const bytes = Buffer.from(JSON.stringify(canonical(document)), "utf8");
  const digest = createHash("sha256").update(bytes).digest("hex");

  console.log(artifact.document_path, {
    sha256: digest === artifact.canonical_document_sha256,
    signature: verify(null, bytes, publicKey, Buffer.from(artifact.signature, "base64url")),
  });
}

The same checks the command above runs, written out in full: Node’s built-in crypto, no Decionis package, SDK, or account.

What a verified signature does not prove

Verification answers one question well and several others not at all. The distinctions matter most to the people who rely on them hardest.

  • That the action was a good one. Verification proves the record of the decision is authentic, not that the policy behind it was right.
  • That the decision reproduces. Reproducibility — re-running the recorded inputs through the recorded policy and getting the same verdict — is reported separately on the dossier itself, because the recompute needs the deterministic engine.
  • When the decision happened, on the signature alone. The dossier's timestamp is part of the signed document; anchoring it externally is a separate control.
  • Anything about a dossier you were not sent. The sig token in a link is a capability that stops dossier ids being enumerated — it is not evidence, and it is not what makes a dossier authentic.

Check it without an account

A public corpus of synthetic dossiers, signed by a published key, lives in the open-source agent-safe-pipeline repository. Two files and the registry package are enough to reproduce every check on this page.

npx -y @decionis/verify \
  --file dossiers/vectors/owned-execution-bound.json \
  --jwks dossiers/corpus-jwks.json

Change one byte inside a signed artifact — flip a verdict from ALLOW to BLOCK — and the digest and the signature both fail. Graft a valid issuer claim from one dossier onto another and the signature breaks; the verifier also declines to report the grafted claim, because a claim only counts when it sits inside an artifact whose signature verified.

The corpus proves the verifier behaves correctly, including when it should refuse. It does not prove that a production dossier verifies — that needs a real dossier and the live JWKS, and the repository documents that check separately rather than shipping a production artifact it should not have.

Cite this corpus

Version v0.1.4 · published 10 September 2026 · Apache-2.0 · DOI 10.5281/zenodo.22692903

Jejelowo, Festus B. “Agent-Safe Pipeline: Reproducible Execution-Authority Reference Architecture and Decision Dossier Corpus.” Zenodo, version v0.1.4, 10 September 2026. https://doi.org/10.5281/zenodo.22692903.

The version DOI identifies these exact bytes. The concept DOI, 10.5281/zenodo.22312955, resolves to the latest release.

Related