# Scaling: what one operator does today, what it costs, and how it would shard

Mirror has no load numbers for the hosted operator, and this page does not invent any. It states what was
measured, on one machine, with the tool that measured it, and then says what has not been measured and how a
pilot would measure it.

## What was measured

`node server/load-test.js` starts one operator on the loopback interface, sends signed reconciliations over
HTTP, and reports throughput and latency. Run on 9 October 2026:

| Setting | Result |
|---|---|
| Machine | Intel Core i5-8265U (1.6 GHz base), 8 threads, 8 GB RAM, Windows 11, Node 24.16.0 |
| Requests | 2,000 reconciliations of 3 committed legs each, 16 in flight |
| Verdicts signed | 2,000 of 2,000 (no failures) |
| Throughput | **about 497 signed verdicts per second**, one Node process |
| Latency | p50 29 ms, p95 40 ms, p99 58 ms, max 228 ms |
| Registry fold | one full fold of **40,000 governance events** (20,000 corridors): **130 ms** |

These numbers describe one process on one laptop with an in-memory store, over loopback. They do not include the
network, the database, the Cloudflare Worker or the EU Durable Object.

## The bottleneck the fold number exposes

The hosted operator runs in "fresh reads" mode. Every state-dependent route re-reads the governance log from its
store and folds it into the registry before answering, so that a fresh isolate never acts on stale governance. The
cost of that fold grows with every corridor, member and witness ever ratified. At 40,000 events it is 130 ms of
CPU per request, before the read from the store, and the store read returns up to 100,000 rows per call.

This is the first thing to fix, and it is a reason to measure before anything else. The design below starts there.

## The design

**1. Incremental fold (first, and small).** Keep the folded registry in memory, keyed by the highest event
sequence number it has applied. A request reads only the events after that sequence and folds those into the
existing state. The fold is already deterministic and append-only, so a fold of the new events onto the old state
gives the same registry as a full fold; the test for that is a property the registry can state, and this change
makes it load-bearing. Cost per request becomes proportional to new governance, not to all of it.

**2. Shard the verdict ledger by corridor.** A verdict belongs to one corridor. Each corridor's ledger (the signed
verdicts, the idempotency keys, the counts) can live on its own Durable Object, so two corridors never contend for
one writer. The registry stays global and read-mostly: a corridor's governance is the only state a verdict needs
from it, and that is what the incremental fold delivers.

**3. Governance stays single-writer.** Governance events are rare, quorum-gated, and must be totally ordered. They
keep one writer per federation (see [federation](/federation)), and that writer publishes a signed snapshot per
registry version. Everything else reads snapshots.

**4. Snapshots instead of re-reads.** A snapshot is the signed registry at a version. A host verifies a snapshot
against the operator key it already holds and serves reads from it, so a read costs a verification, not a log
scan. A stale snapshot is detectable, because it names its version.

**5. Measure each step against the previous one.** The load tool runs against a pilot's own staging operator.
A change ships only with before-and-after numbers on the same machine, and the page is updated with them.

## What is not measured, and what would measure it

- The Cloudflare Worker and its Durable Object, in the EU jurisdiction: the request path, the object's own limits
  and the store read. These need a load run against a staging deployment, never the live rail, because a load run
  creates governance-visible activity.
- The store: the PostgREST read of the governance log at realistic sizes.
- Multi-operator federation: k operators reconciling the same legs. Each reconciles independently, so the cost is
  roughly k times one operator, plus the bank's fan-out. It is not measured.
- Verdict volume over a real corridor, at a real bank's rate. No bank has run a pilot. Any throughput figure that
  claims a customer's volume would be invented.

## What a pilot does

1. Stand up a staging operator (`node server/app.js` with a staging key and a store).
2. Run `node server/load-test.js --requests 10000 --concurrency 32 --legs 3 --fold <the governance size you expect>`
   and keep the output.
3. Repeat against the deployed staging Worker with the same parameters, and report both.
4. Ask for the governance size the first corridor will reach in a year, and measure the fold at that size.

The numbers that matter are the ones a bank can reproduce on its own machine.
