Benchmarks

Every number here is reproducible with a command on this page. If you cannot re-run it, treat it as marketing, not measurement — including these.

All figures below were measured on one machine on 2026-08-05 with NovaFabric 0.100.1. They are not a promise about your hardware; they are a starting point and a method.

Hardware, stated because it changes every number: 13th Gen Intel Core i7-13700 (24 threads), 62 GB RAM, Linux 6.8.0, Python 3.12. A CI runner has roughly a sixth of these cores and produces materially slower numbers — see what we do not claim.


1. Capture overhead

The question that matters: how much does wrapping a workload in nova capture cost?

uv run pytest tests/bench/test_capture_overhead_gate.py \
  --benchmark-json=capture.json

Measured over 30 full captured runs of a trivial command through CaptureOrchestrator(fast_emit=True):

ms
Min 123.6
Median 168.8
Mean 165.3
Max 215.9
Std dev 26.9

CI gate: p95 < 2000 ms, enforced on every pull request by the capture-overhead-gate job. The measured median sits about 12× under the ceiling — the gate is deliberately loose because it must also pass on a shared CI runner, and a gate that flakes gets ignored.

Read this honestly. This is the fixed cost of a capture: process setup, hook installation, environment lock, redaction scan, and capsule write. It is essentially constant, so it disappears against a workload of any real length — a 40-second agent run pays under half a percent. For a workload that finishes in 10 ms, it dominates. NovaFabric is not built for capturing 10 ms workloads.

2. NovaSeal signing latency

The question: does sealing a capsule make the pipeline wait?

make benchmark
# or: uv run pytest tests/seal/test_benchmark.py --benchmark-json=seal.json

Over 100 rounds of NovaSeal.seal():

ms
Min 5.64
Median 6.86
Mean 7.50
Max 13.30
Throughput ~133 seals/sec

CI gate: median < 50 ms, enforced on every pull request, plus a non-blocking p99 ≥ 200 ms tail alarm (see slo.md). The p99 used to be the gate; on shared CI runners it is decided by scheduler stalls (3 of 55 runs carried a >200 ms sample while their medians stayed under 10 ms), so it now warns instead of failing.

This is an ECDSA P-256 DSSE signature over a Merkle root, so it is dominated by hashing the capsule rather than by the signature itself — expect it to scale with capsule size, not with the number of files.

3. Query engine — the measurement that changed a default

Worth including because it is the case where benchmarking contradicted the design.

nova query shipped with DuckDB as the implicit default. Measuring it against SQLite across 10 → 20,000 capsules found DuckDB ~20–25× slower, at a flat ratio — per-row index-build cost, not a crossover. Anyone installing the [query], [scale] or [all] extras was silently getting a 20× slower nova query with no way to opt out.

The default is now SQLite. NOVAFABRIC_QUERY_ENGINE=duckdb opts back in.

A later pass moved the DuckDB index build to a columnar Arrow path — ~968 µs/row to ~1.1 µs/row, and a build at n=5,000 from 5.14 s to 0.0125 s (411×). The default still did not change, because the directory scan is 86–89% of total time and the index build was never the bottleneck. Making the wrong thing 411× faster changed nothing that a user can feel.

Reproducibility caveat. Unlike the rest of this page, the query-engine figures in this section have no command you can re-run from the public repository: the crossover benchmark script is not published. They are recorded in the CHANGELOG entries that shipped each change. By this page's own rule, weigh them accordingly.

That is the whole reason this page exists.


What we do not claim

Reproducing all of it

git clone git@github.com:MSKazemi/novafabric.git
cd novafabric
uv sync --all-extras

make benchmark                  # seal latency, 100 rounds
uv run pytest tests/bench/test_capture_overhead_gate.py   # capture overhead, 30 runs

Both write a --benchmark-json artifact you can diff against these figures. If your numbers differ substantially and your hardware is comparable, that is a bug report we want.