# .NET Pure OPEN affinity review — 2026-09-08

## Outcome and publication status

The 12 .NET Pure OPEN observations listed below did not enforce their requested
measurement-thread affinity. Their canonical latency and achieved-rate fields have
been withdrawn from `results-scan-open.tsv`. Original observations and evidence
paths remain in `withdrawn_results` in [the retained R7 table](open-sweep-scan-r7.json)
and [the retained R10 table](open-sweep-scan-r10.json), and in the original sitting directories.
The withdrawal is a placement-contract failure, not a claim that measured replies
were missing or that any particular historical CPU executed the clients.

The managed pinning fix is implemented and installed kernel smoke verification
has passed the startup affinity checks in all four shapes for both .NET flavours.
Replacement canonical runs remain pending. The first smoke below predates the
pinning fix; the follow-up is documented separately. This note publishes no
replacement latency values.

## Retained provenance

This conclusion was checked against the retained tar members and each sitting's
`source_files` and `installed_artifacts` manifests, not inferred from today's source
alone. Both manifests record Git base commit
`fba506060919fd7061bf534476e4d4291749f79f` plus retained working-source evidence;
that Git base alone is not a complete source identity.

The exact sitting roots are:

- R7: `/home/yann/libhft-bench-runs/open-v3-20260908-r7`
- R10: `/home/yann/libhft-bench-runs/open-v3-20260908-r10`

Each contains `source-files.tar`, `source-state.patch`, and `sweep.json`.
SHA-256 of the inspected archive and manifest bytes:

| Sitting | File under the sitting root | SHA-256 |
| --- | --- | --- |
| R7 | `source-files.tar` | `bad061911d305fc2aa554b789fe225f110d7acef21a50a827371e4e53cc0c0ff` |
| R7 | `sweep.json` | `834bbd188ddebffe66752f95f16ddf291e991289ced281e7618d16f64a1c5ede` |
| R10 | `source-files.tar` | `2fd760e8269f2b6255d7359ca453ed12cd9edb89ac4591986c64b780ac829731` |
| R10 | `sweep.json` | `88aa5081d0f4537c831e28c5d81d6477247d80a6a0593d96a873247646c05e9a` |

These selected tar members are byte-identical between R7 and R10. Each computed
hash exactly matches its entry in both `source_files` manifests:

| Exact archive member | SHA-256 |
| --- | --- |
| `bench/dotnet/fixbench/libhft-net/Program.cs` | `2f65971eaac9411b44caf882ab9cd6d6ecd8a79e192f5df77d8e614011cb699a` |
| `bench/dotnet/hft-bench/src/Libhft.HftBench/BenchRunner.cs` | `3d7246752a4787250cc8f12a55178fed775cc0e76c55bcc817dbd518047ff92f` |
| `ops/scripts/bench-run` | `a232ddbb44639041ebb9c9090976a0ed27bb8b1287325b473dd47267ae47a54a` |

Both installed-artifact manifests also identify the same managed benchmark DLL:

```text
dotnet-fix/libhft-net/LibhftNet.Bench.dll
1e9310f1ee3a2aaede46d3f1cc26aa6daf68d0519ceecc3d879f0074c4fd411a
```

The installed `bench-run` hash equals the archived launcher hash above in both
sittings. This does not assert that every installed artifact was identical: the
shared `dotnet-fix/libhft-net/Atrekes.Libhft.HftBench.dll` hashes differ:

```text
R7  f08b595c2f2fb0c96c527dfe894d3fba38d5e6dd20227db1f5f8689165e36db3
R10 5fb56d6fbe204bf0616ff580b02981e87a0c24d26bfdf590dfb6071401bf37fd
```

For comparison, the pre-affinity-fix `Program.cs` at `dd8c6c0c` has SHA-256
`7802e777041e54a39d5a3f021bf2a775c03a1bd40929f3f896006a1b52d7d6a4`.
It includes the later OPEN correlation repair but still has the same direct-client
pinning omission. Its different whole-file hash is not substituted for the retained
R7/R10 source hashes.

## What the retained source proves

Line numbers here refer to the archived members above, not the evolving checkout.

1. `Program.cs:150` returns directly into `RunMultiSessionClient(opt)` for OPEN,
   including a single session. Lines 152–153 also route multi/forced-multi clients
   there. The direct multi-client path contains neither `PinCurrentThread` nor
   `ReportCurrentThread`.
2. The pinning at `Program.cs:76–80` is server-only. The client configuration carries
   `MeasureCore` at line 895, but that belongs to the separate `BenchRunner.Run`
   path invoked at line 901. OPEN's early return bypasses that path.
3. `BenchRunner.cs:20–26` applies `PinCurrentThread(config.MeasureCore)` and reports
   client affinity. Those calls cannot establish the placement of a client that
   never enters the runner.
4. Archived `bench-run:1411–1429` removes `--core`, translates it to
   `--measure-core`, and deliberately avoids `taskset` for the .NET process.
   The actual invocation at line 1489 likewise has no `taskset`. Thus the requested
   core was forwarded to a CLI option but not applied by this client path.

This proves an omitted enforcement step for these archived OPEN clients. Requested
CLI cores and recipe masks are not observations of actual thread affinity. Missing
client affinity lines alone would only establish missing evidence; the retained
source and launcher establish the stronger implementation defect here.

No historical CPU assignment, migration pattern, overlap, or numerical latency
effect is inferred. Historical closed/paced provenance is **undetermined by this
review**: single-session shared-runner and direct-multi dispatch differ, and those
results require their own artifact, mode, and placement review. This withdrawal
does not silently reclassify those separate datasets.

## Exact affected OPEN cells

All cells below are `dotnet-pure`. The evidence suffix is relative to its exact
sitting root above; the original `sweep.json` result records retain the corresponding
absolute path and `source_revision=initial`.

| Sitting | Transport | Layout | Retained evidence suffix |
| --- | --- | --- | --- |
| R7 | kernel | single | `single/dotnet-managed/kernel/attempt-3uiiv5_q/run` |
| R7 | onload | single | `single/dotnet-managed/onload/attempt-ncm4in1c/run` |
| R7 | vma | single | `single/dotnet-managed/vma/attempt-0xa5crtr/run` |
| R7 | kernel | mono | `mono/dotnet-managed/kernel/attempt-yax3ad8n/run` |
| R7 | onload | mono | `mono/dotnet-managed/onload/attempt-8swara4u/run` |
| R7 | vma | mono | `mono/dotnet-managed/vma/attempt-fo1lwyfx/run` |
| R7 | kernel | pool | `pool/dotnet-managed/kernel/attempt-q5j2o3ud/run` |
| R7 | onload | pool | `pool/dotnet-managed/onload/attempt-uz9fan2i/run` |
| R7 | vma | pool | `pool/dotnet-managed/vma/attempt-p86bbizr/run` |
| R10 | kernel | shard | `shard/dotnet-managed/kernel/attempt-w2kc61_0/run` |
| R10 | onload | shard | `shard/dotnet-managed/onload/attempt-0u4335cw/run` |
| R10 | vma | shard | `shard/dotnet-managed/vma/attempt-7bvpooq1/run` |

## First post-correlation, pre-affinity-fix smoke

Evidence root:
`/home/yann/libhft-bench-runs/dotnet-open-correlation-smoke-20260908-Ena5b5`.
This installed-artifact smoke at source `dd8c6c0c` covered both .NET arms on kernel,
each with single, mono, shard, and pool. It configured 3,000 warmup slots and one
3,000-iteration measured run per session; multi cells used four processes of eight
sessions. It was a functional smoke, not a full three-run canonical measurement.

Independent read-only checks found:

- All eight cells delivered their requested measured replies: 3,000 per single
  cell and 96,000 per multi cell, totaling 582,000. Measured deficits and shed
  counters were zero, with no correlation-failure or timeout diagnostic.
- All 26 raw files parsed completely. Their 582 distinct run/session/probe series
  each contained 3,000 samples, run index 1, and zero dropped samples. File and
  series payload SHA-256 values were computed during the check; raw bytes were not
  changed. One-run stability correctly remained `INSUFFICIENT`.
- The smoke summary was six passing and two saturated cells, not eight canonical
  passes. Native single and managed pool exceeded the scheduler-delay gate despite
  complete measured delivery. No latency values from that smoke are promoted here.
- All four managed cells lacked client affinity evidence. Their requested cores
  therefore did not validate actual client placement. Native mono, shard, and
  single had disjoint logged placement. Native pool's pinning check reported an
  expected-set mismatch (`15 16 17 18 != 15`), not an observed server/client overlap.
- The native single server also retained `rc=-4` with `accepted=1 completed=1` and
  `errors=0`; this footer anomaly is disclosed, not treated as proof of clean server
  shutdown. It is separate from the managed affinity omission.

Complete delivery and valid raw ownership evidence do not repair missing affinity
enforcement. Replacement results require the installed pinning fix to be verified
on the actual measuring thread, followed by fresh canonical runs and new provenance.

## Post-affinity-fix installed kernel smoke

Evidence and machine-readable summary are retained at
`/home/yann/libhft-bench-runs/dotnet-affinity-smoke-20260908-p1vR5e`.
The same 3,000 warmup / 3,000 measured, one-run recipe completed all eight kernel
cells. Startup affinity readback passed for every cell. All 582,000 measured
replies arrived with zero measured deficits or shedding. Seven smoke verdicts
passed; native single remained saturated because scheduler-delay p99 was
199.842 us against its 20 us interval. Managed single's functional profile stamp
remains unverified; placement and delivery do not prove that missing stamp.

The native single server retained its first negative Step result (`-1`, status
`Disconnected`), proving that the later lifecycle error no longer overwrites it,
not proving that every initial `-1` is a benign EOF. These are kernel-only,
short functional probes, not replacement canonical latency measurements or
continuous CPU-residency evidence. The twelve historical managed observations
remain withdrawn pending fresh full-size runs.
