DocumentsProcurement and compliance

Due diligence: the 61 gates

9 min readSource due-diligence.mdsha256 0bd49fee22e72dc0…

Every gate a bank's procurement asks about, assessed against what is actually in the code and on the operator on 2026-09-29. Done names the file, route or test that proves it. Nothing here claims a certificate, an audit, an insurer, an opinion or a board that does not exist.

47 done - 0 partial - 1 refused by design - 13 need an outside party or the maintainer's decision - 0 not started.

G1 - Security & crypto custody#

Owner: CISO, crypto governance

GateStatusEvidence
HSM / KMS-native corridor-secret custody (deal-killer)DoneThe corridor secret and every signing key can live in the bank's HSM or KMS: mirror-custody spawns the bank's own tool (no shell), with KCV checks at the ceremony and before every run. See custody; tested in kernel/mirror-custody.test.js and server/witness-supply.test.js.
Key rotation ceremony for the corridor secret (deal-killer)DoneRotation by corridor version, never by clock: a signed plan (rotate-plan), a rehearsal against both HSM keys (rotate-rehearse), and a state machine with an honest rollback window and crypto-shredding of the old key. Rehearsed end to end in server/rotation-rehearsal.test.js. See corridor key rotation.
Key hierarchy and separationDoneMember root keys delegate scoped, short-lived desk keys (mirror-delegation, mirror-bander delegate); origination, relay, agreement and witness keys are separate ceremonies. No chains: delegates cannot delegate. See access control.
FIPS 140-2/3 answer, documentedDoneFIPS position: no validated module is shipped or claimed; the algorithms are approved; key operations can run inside the bank's own validated HSM. mirror-bander fips reports the running process's mode.
SBOM for every artefactDone/sbom.cdx.json (CycloneDX 1.5), freshness-tested by server/sbom.test.js.
Signed release provenance (SLSA / in-toto)Done/provenance.intoto.json: in-toto v1 + SLSA provenance v1 in a DSSE envelope, signed by /release-key.jwk, over every published artefact and every source file by digest. SLSA Build Level 1 - not L2/L3, which need a hosted builder. See provenance.
Reproducible builds (deal-killer)DoneEvery subject of the signed provenance rebuilds byte for byte: the operator, bander and kit bundles, the vectors, the OpenAPI document, the SBOM and all four native binaries. One command, node server/reproduce.js, verifies the provenance, confirms the sources are the release's, rebuilds in a disposable copy at another path and compares each digest. Reproduced on 29 Sep 2026 on Windows 11 and on Ubuntu 24.04 (Node 24.16.0): 10 of 10 both times, the Linux run against provenance signed on Windows. server/reproduce.test.js rebuilds the JavaScript artefacts on every build. Not shown: a rebuild by anyone but the maintainer (both machines are one computer's), and the source tree is not public - a reviewer receives it in diligence; publishing it is the maintainer's decision. See provenance.
Independent penetration test + retestOutside partyNone commissioned and none claimed. Needs a testing firm.
Threat model with a public review historyDoneReview history: every review that changed the threat model, what it found, what changed and the test that pins it. No named external reviewer yet - listed only with consent.
Secure development lifecycle statementDoneHow Mirror is built - the practice as it is, including where it falls short (one maintainer, no public repository, no second reviewer).
Disclosure programme with a published SLAOutside partyWaiting on the maintainer's decision about a contact route. No intake channel is invented in the meantime.

G2 - Regulatory & contractual#

Owner: Legal, vendor management, DORA

GateStatusEvidence
DORA Article 30(2) clause pack, all provisions (deal-killer)Outside partyCounsel's to draft. Product-side support is written: contract schedules (audit, exit, location, incidents, cooperation), each promise naming its mechanism.
Critical-function scoping opinion, in writing (deal-killer)Outside partyCounsel's to write. The facts it needs are test-pinned in /cannot.
TLPT cooperation clauseOutside partyContract text for counsel.
Incident reporting support pack (4h / 72h / 1 month)Donemirror-incident: the three clocks from stated times, and what the rail did during the window counted only from signed records the bank verified. See incident support. Not legal advice.
GDPR pack with a pre-filled DPIADoneDPIA pre-fill: every fact marked as code-enforced (with its test) or a design statement; the conservative reading of pseudonymised commitments.
Records retention schedule, erasure conflict resolvedDoneRetention schedule: per record class; erasure resolved by crypto-shredding the secrets that make commitments linkable, after the retention period and any hold. Automated pruning of two classes is stated as not yet built.
Audit rights clause with notice periodsDoneDrafted for counsel: Schedule A - continuous offline verification without notice, the supervisor seat, 30 days' notice for on-site audit.
Exit and portability clauseDoneDrafted for counsel: Schedule B - standing portability, a 30-day export, succession, continued verifiability.
Liability cap + published E&O / PI coverOutside partyNo cover is held and none is described. Needs an insurer.
Data residency commitmentDoneProcessing and storage in the EU. The operator runs in a Cloudflare Durable Object restricted to the EU jurisdiction, read from the object's own id at runtime; if it is unreachable, the request is refused and processed nowhere else. The store is in AWS eu-central-1. The operator signs this at GET /residency; a fail-closed meets(record, "eu") ships in the kit and every SDK. Tested in server/residency.test.js and kernel/mirror-residency.test.js. The record lists what it does not cover: the first edge hop (forwarded unread), object ids in Cloudflare's logs, and storage that is declared rather than observed. Clause drafted for counsel in Schedule C. See data residency.
Published sub-processor registerDoneSub-processors: Cloudflare and Supabase, what each processes and where, the shared database project disclosed, 30 days' notice of change proposed.
AMLR / 6AMLD position paper + R.16 alignmentDonePosition paper for counsel: AMLR information-sharing partnerships, both directives called 6AMLD, and why R.16 compliance stays with the payment chain.

G3 - Assurance & certifications#

Owner: Third-party risk, vendor assurance

GateStatusEvidence
SOC 2 Type II (deal-killer)Outside partyNot held, and never shown.
ISO 27001:2022Outside partyNot held.
ISO 42001Outside partyNot held. Mirror runs no model (deterministic kernels).
Published pen-test summary + retestOutside partyDepends on the pen test.
ISO 22301 or equivalent, testedOutside partyNot held.
Financial-crime programme alignment statementDoneProgramme map: what Mirror contributes to each part of an AML/CFT programme, and what it deliberately does not. The per-bank mapping is the bank's.
Regulator engagement packDoneSupervisor pack: one hand-over document - what it is, what it cannot do, how to check it offline, the seat, the known limits, who operates it.

G4 - The model#

Owner: Protocol

GateStatusEvidence
Versioned schema with a published stability policy (deal-killer)Done/stability-policy.md; the spec is pinned by hash on every record.
Extensible leg-role registry, without breaking v1 (deal-killer)DoneAn open lowercase namespace with defined unknown-role behaviour; independence comes from the signing key's class, never the role name.
Formal canonicalization / normalization specDoneSPEC §8.2, normative: canonical JSON, length-prefixing, exact decimal, every commitment derivation, key ids, low-S, webhook ids, and the wall's key normalisation - each pinned by named vectors.
Versioned signal / error taxonomyDone/signals.json, drift-tested against every code the operator can return.
/cannot: the refusal list as a contract (deal-killer)DoneSigned at GET /cannot; version 1.1.0, 39 refusals, change-controlled by test.
Stable identifier schemeDonemirror-locator: domain-separated locator commitments with normalisation rules and vectors.
Independent-implementation interoperability testDoneconformance/reference-impl.js, written from the spec text and importing nothing from the kernels, reproduces every vector byte for byte - including fine, basis, origin, both witness axes, webhook ids and canonical JSON.

G5 - Architecture & operations#

Owner: Infrastructure, bank platform team

GateStatusEvidence
Streaming / event-driven, not batch (deal-killer)DoneSigned webhooks to proven parties only, first attempt immediately (under 2 s on loopback, test-enforced), a stated retry schedule. See webhooks.
Idempotency and replay semantics (deal-killer)DoneA retry and a failover resubmission are one verdict: counts key on the judgement, not signature bytes (mirror-idempotency).
HA bander, active-active with a degraded modeDoneTwo hosts band to byte-identical commitments; the operator counts one verdict; an unreachable HSM stops the run with no fallback. Tested in server/bander-ha.test.js. See HA bander.
Clock discipline, documented and monitoredDoneSigned, nonce-bound POST /time; mirror-clock proves an offset interval from the round trip; client.clock() monitors it. See clock discipline.
Backfill and re-processingDoneParty-side re-banding under a new table version makes new verdicts on the append-only ledger; /replay bounds a period. See HA bander.
Documented RTO / RPO, testedDoneRTO / RPO: a recovery drill on every build (restore and rebuild from members' signed copies to the same log root) and measured restore times. The store's backup setting is stated as unconfirmed.
Business continuity plan, tested annuallyOutside partyNeeds an operating organisation to test it.
Multi-operator resilienceDonemirror-cosign, federation, succession, witness-cosigned heads with gossip fork detection.
Documented graceful degradationDoneDegradation runbook: every failure degrades toward not clearing and toward telling the member; each row is tested.

G6 - Integration & enterprise plumbing#

Owner: Bank engineering, procurement

GateStatusEvidence
Terraform provider (deal-killer)DoneA compiled provider (terraform/provider, Go, terraform-plugin-framework). It manages webhook subscriptions with drift detection and import, and sends signed governance events; a data source reads the registry. The key never enters Terraform: the bander signs. Tested with a real terraform 1.16.4 against an operator (server/terraform-provider.test.js): apply, drift recreated, import, no key in the state. The module is validated as well (server/terraform-e2e.test.js). Not on the Terraform Registry: publishing is the maintainer's decision. See Terraform.
OpenAPI 3.1 + SDKs (Python, Java, .NET, Go) (deal-killer)Done/openapi.json (generated, drift-tested, raw-data wall in the schema), and verifying SDKs in JavaScript, Python, Go, Java and .NET. Each is held to the 100 shared cases in /sdk-vectors.json and run against an operator (server/sdk-polyglot.test.js). Shipped as source; not on PyPI, Maven Central, NuGet or the Go module proxy. See SDK.
SSO (SAML 2.0 + OIDC) with SCIMRefused by designBy design, not at the operator: Mirror authenticates keys, not people, and will not hold a staff directory (/cannot staff_directory). SSO sits at the member's gateway, which holds scoped desk keys. See access control.
Fine-grained RBACDoneDelegated desk keys with scopes (reconcile, governance, webhooks, read), enforced on every request, revocable live.
Native audit-log export to the bank's SIEMDonePOST /audit/export: the member's own signed records as JSON lines, signed batch, cursor paging. The operator stores no SIEM credential.
Reference connectors for the top trade platformsDoneReference connectors for the messages trade platforms exchange: SWIFT MT700 / MT710 / MT720 documentary credits, and DCSA eBL 3.0 bills of lading (connectors/mirror-connect.js; tested in kernel/mirror-mt700.test.js and kernel/mirror-ebl.test.js). They sit beside the origination sidecar, the ISO 20022 ingest, the e-invoice readers and import mapping. Tested against messages built from the published standards. No named platform is connected; that is per-platform work with its owner. See connectors.
Webhooks with documented retry and delivery guaranteesDoneAt least once, dedupe id stable across retries and failover, 7-step schedule, 410 pauses, redelivery. See webhooks.
Migration and import toolingDoneimport-check (a dry run reporting counts and column names only), band --mapping, table-import. Tested.
Sandbox with production-parity auth, RBAC and auditDoneserver/sandbox.js: the same code with every production default on; its verdicts can never verify as production ones. See sandbox.

G7 - Governance & protocol stability#

Owner: Board, ecosystem

GateStatusEvidence
Published change control over the refusal list (deal-killer)Doneserver/cannot.test.js: no removal or weakening within a major version; additions announced as minor versions.
Protocol stability policy (deal-killer)Done/stability-policy.md.
Public RFC processDoneRFC process: what needs an RFC, a 30-day last call, published objections and answers. Today the maintainer decides - stated.
Independent security advisory board, namedOutside partyNo names are published until people have agreed.
Transparency-log operations policyDoneLog policy: one history, mirroring, compelled withholding, what happens on a detected fork.
Roadmap governance, published and signedDoneGET /roadmap signs the roadmap's Refused list (binding, change-controlled) and pins the page by hash.

Generated by server/deal-gates.js; the same data drives the private tracker.