agent-fabric
Treasury
Evidence Bundles

Evidence Bundles

The bundle is the portable, verifiable artifact that an auditor, regulator, or counterparty can consume to prove what happened. It contains:

  • Every trace event for the workflow.
  • Every policy verdict.
  • Every approval (request, decision, approver, reason).
  • The final proposal envelope (content-hashed).
  • The on-chain (or rail) receipt.
  • Canonical content hash.
  • Signature.

Generate

import { EvidenceBundler, Ed25519EvidenceSigner } from '@veridex/agents-treasury';
 
const bundler = new EvidenceBundler({
  signer: new Ed25519EvidenceSigner({ privateKey, publicKey, keyId: 'ops-2026' }),
  portal: portalTelemetry,
});
 
// Inside a workflow:
bundler.recordTrace(event);
bundler.recordPolicyVerdict(verdict);
bundler.recordApproval(approval);
bundler.recordProposal(proposal);
bundler.recordChainTx(receipt);
 
const bundle = await bundler.finalize({ workflowId, submit: true });

(The kit.plugin returned by createTreasuryKit wires this automatically.)

Verify

import { verifyEvidenceBundle } from '@veridex/agents-treasury';
 
const ok = await verifyEvidenceBundle(bundle, { publicKey });
if (!ok.signatureValid) throw new Error('Signature invalid');
if (!ok.chainConsistent) throw new Error(`Tamper at event ${ok.brokenAt}`);

Verification is offline — no network call required.

Canonicalisation

Stable JSON canonicalisation (RFC 8785) before hashing: sorted keys, no whitespace, ULID timestamps preserved. Hashes are stable across language implementations.

Signers

SignerUse case
NoopEvidenceSignerDev, tests
HmacEvidenceSignerInternal verification, shared-secret
Ed25519EvidenceSignerPublic verification, third-party audit
CustomKMS-backed, HSM-backed
import { EvidenceSigner } from '@veridex/agents-treasury';
 
class KmsSigner implements EvidenceSigner {
  async sign(canonicalBytes) { /* call KMS */ }
  publicKeyInfo() { return { alg: 'ed25519', keyId: '...' }; }
}

Portal submission

When submit: true and a portal telemetry client is configured, the bundle is uploaded to the developer-portal trace store. The portal returns a permanent receipt URL embedded in the bundle's submission field.

Selective disclosure

import { redactBundle } from '@veridex/agents-treasury';
 
const redacted = redactBundle(bundle, {
  redactFields: ['counterparty.address', 'memo'],
});
// signature remains valid only if redaction policy is verifier-known
// otherwise use selective-disclosure receipts (Merkle-based, opt-in)

For regulator-friendly selective disclosure (prove an event happened without revealing it), opt in to Merkle-receipt mode.

Related