# SCAN single-session capacity brackets — 2026-09-29

## Result

The shared kernel-TCP load harness established a last-pass/first-fail bracket for each runtime flavor it covers:

| Flavor | Highest sustained target | First saturated target |
|---|---:|---:|
| C++ | 75,000/s | 100,000/s |
| Java Pure | 50,000/s | 75,000/s |
| Java/JNI | 75,000/s | 100,000/s |
| .NET Pure | 50,000/s | 75,000/s |
| .NET Native | 75,000/s | 100,000/s |

No covered flavor qualified for a 250,000/s probe under this contract. Rust is not wired into `bench/load/bench.sh`; its existing 50,000/s evidence belongs to a separate campaign and is not silently mixed into this sweep.

The complete extracted rows are retained in [`results-scan-single-capacity-20260929.tsv`](results-scan-single-capacity-20260929.tsv). Raw logs and samples remain on SCAN at:

```text
/home/yann/libhft-bench-runs/max-candidates-20260929-single-5s-rerun2
```

## Contract

- Source revision: `1bec04aa3`
- Runner: `bench/load/bench.sh`
- Scenario: `single`
- Transport: kernel TCP
- Workflow: FIX NewOrderSingle to ExecutionReport
- Schedule: open-loop v4
- Topology: one session, one client process, server core 10, client core 15
- Repetitions: three measured runs per cell
- Samples: raw samples retained
- 50,000/s: 50,000 warm-up messages, 250,000 measured messages
- 75,000/s: 75,000 warm-up messages, 375,000 measured messages
- 100,000/s: 100,000 warm-up messages, 500,000 measured messages

The benchmark host also carried BrokerForge processes on housekeeping cores 0–9. The measured processes used isolated cores 10 and 15, but this remains diagnostic capacity evidence rather than an unconditional production ceiling claim.

## Passing rows

| Flavor | Target | Achieved | p50 | p99 | p99.9 | Scheduler-delay p99 | Stability |
|---|---:|---:|---:|---:|---:|---:|---|
| C++ | 50,000/s | 50,000/s | 27.923 µs | 32.890 µs | 40.081 µs | 10.100 µs | PASS |
| C++ | 75,000/s | 75,000/s | 22.593 µs | 27.311 µs | 35.050 µs | 2.991 µs | PASS |
| Java Pure | 50,000/s | 50,000/s | 32.633 µs | 36.973 µs | 45.719 µs | 15.202 µs | PASS |
| Java/JNI | 50,000/s | 49,999/s | 28.033 µs | 35.080 µs | 52.299 µs | 12.804 µs | PASS |
| Java/JNI | 75,000/s | 75,000/s | 26.819 µs | 37.318 µs | 40.839 µs | 7.635 µs | PASS |
| .NET Pure | 50,000/s | 50,000/s | 34.050 µs | 41.463 µs | 56.605 µs | 15.142 µs | PASS |
| .NET Native | 50,000/s | 50,000/s | 25.850 µs | 31.011 µs | 33.605 µs | 11.563 µs | PASS |
| .NET Native | 75,000/s | 75,000/s | 27.221 µs | 39.831 µs | 53.862 µs | 8.940 µs | PASS |

## Saturation rows

| Flavor | Target | Achieved | Delivery | Gate reason |
|---|---:|---:|---:|---|
| C++ | 100,000/s | 99,999/s | 100.0% | Scheduler-delay p99 (11.360 µs) exceeded the 10 µs offer interval |
| Java Pure | 75,000/s | 60,922/s | 81.2% | Saturated |
| Java/JNI | 100,000/s | 85,988/s | 86.0% | Saturated |
| .NET Pure | 75,000/s | 74,839/s | 99.8% | Unstable and saturated |
| .NET Native | 100,000/s | 82,539/s | 82.5% | Saturated; stability WARN |

Latency values at a failed target describe overload behavior; they are not promoted as sustained-performance rankings. The 100,000/s Java Pure and .NET Pure probes were retained as additional saturation evidence but do not change their first-fail brackets.

## Publication rule

Public charts may show passing points only. They may state the first failed target as the bracket boundary, but must not draw a sustained curve through a failed point or imply that this sweep proves a production maximum. Campaigns with different hosts, load models, transports, or measurement windows remain visibly separate.
