Sizing and measured performance

The first question after "is it secure" is "how many developers will it hold". This document answers it with numbers from a run anyone can repeat, together with the caveats that make those numbers honest. Where the measurement does not support a claim, the claim is not made.

Everything below was measured, not modelled. Reproduce it with hack/load.sh.

The measurement

One command, on a kind cluster, using the Helm chart as a customer would install it:

ENVS=30 SOAK=5m hack/load.sh

It creates N environments through the API and waits for each to report Ready, then drives the read path with concurrent clients, then soaks with several writers appending to the audit chain, and finally verifies the chain. Results land in .load-results/.

Results

Measured 2026-09-12 on an Apple M4 Pro, 14 cores, 24 GiB RAM, macOS 26.5.2, Docker Desktop with 14 CPUs, single-node kind, one API replica and one operator replica.

Environment creation

Environments requested 30
Reached Ready 30 of 30
Time to Ready p50 6.3 s, p95 7.3 s, max 7.3 s
Wall clock for all 30 34 s, six creates in flight

Measured from the API accepting the create to the Environment reporting Ready — the reconcile, the pod scheduling and the routing update, which is what a developer actually waits for.

These environments deploy a prebuilt image. Building from source adds the build, which depends on your repository and registry and is not included here.

API read load

Load 20 concurrent clients, 60 s, GET /environments
Throughput 290 requests/second
Errors 0 non-2xx out of 17,411
Latency p50 13 ms, p95 24 ms, p99 78 ms, max 128 ms

This is the endpoint a dashboard polls, with 30 environments in the workspace.

Soak, with sustained audit appends

Duration 5 minutes, 4 concurrent writers
Writes 12,640, 0 errors
Latency p50 8 ms, p95 15 ms, p99 17 ms, max 28 ms
Audit chain after verifies intact

Every write appends to the hash chain, which cannot be parallelised inside the database — each entry hashes onto the previous one. Four concurrent writers is the shape that would expose that as a bottleneck, and at this rate it is not one: write latency is lower than read latency, because a read serialises 30 environments and a write appends one row.

What this supports

Tested to 30 concurrent environments on a 14-core laptop, with the API answering 290 reads/second at a p99 of 78 ms and sustaining 42 audited writes/second with the chain intact.

For a rough sense of scale: a team of 200 developers, each creating a couple of environments a day and having a browser poll the dashboard, is nowhere near any of these figures. The single-replica decision in ADR 0005 assumed "a few hundred developers doing occasional writes"; nothing measured here contradicts that.

What this does not support

Read this part before quoting the numbers above.

Rules of thumb

Until you have measured your own cluster:

Repeating this

ENVS=60 PARALLEL=8 SOAK=30m hack/load.sh    # bigger, longer
KEEP=1 hack/load.sh                          # keep the cluster afterwards

The script fails if the audit chain does not verify at the end. That is not decoration: this measurement is how the canonicalisation bug in phase 10 item 15 was found, where the chain reported tampering on a log nobody had touched.