# Native .NET mmap readiness recovers after an offline reset failure

Native .NET could return success from `TryAcquirePrimary` after a failed offline
mmap reset even though the store had no mapping and could neither save nor replay
a record. The adapter's existence was mistaken for an open durable store. The
readiness check now requires an actual open mapping, so the next primary-open
request follows the normal recovery path.

A failed reset can still hold the HA writer lock. Ownership and readiness are
therefore separate facts: losing a mapping does not make its owner a standby.
The role projection now reads actual lock ownership rather than the run-admission
gate. The failed operation retains its descriptor and lock until explicit
recovery or stop, as the C++ store contract requires.

## Reproduction

`test_native_mmap_reset_failure.cpp` compiles the actual native binding source
through its registered `native-tests` target. Each of its twelve cases runs in a
child process over a unique file beneath the session's scratch directory. Both
4,096- and 65,536-slot mmap adapters run with HA enabled and disabled, and with
three recovery paths: primary-open after failed reset, explicit reset retry after
failed reset, and successful reset.

The failure is a real OS I/O refusal, not a substituted store: `RLIMIT_FSIZE=0`
and ignored `SIGXFSZ` allow truncate-to-zero but refuse the resize that follows.
The process restores the limit before recovery. Reset returns
`HFTNET_ERR_INTERNAL`, preserves the runner's 8/9 counters and leaves capacity
zero because the mapping is gone. For HA cases, the retained writer lock refuses
an independent contender; canonical telemetry still identifies the real owner.

At baseline `d67390487`, each TLS configuration has **eight passes, four failures
and zero skips**. The four primary-open cases report `opened=1, durable=1` but
have `bytes=0, saved=0, found=0`. All explicit-reset retries and successful-reset
controls pass. The correction requires the full mapping, a successful append,
matching replay bytes and recovery of those bytes through an independently
reopened adapter. The baseline fixture and driver are retained on the private
branch `s/codex-libhft-hp-mmap-reset-baseline-20261014`.

## Correction

`HftNetStore::IsDurable` asks the mmap adapter's `IsOpen`, as it already did for
the other durable store types. `hftNetEnsurePrimary` itself is unchanged: an
unmapped adapter no longer satisfies its early success condition, so its existing
primary-open path reopens and recovers the configured store. The open edition
excludes the mmap checks at compilation; its unavailable mmap placeholder does
not need a new method.

`PrimaryRoleKnown` also recognizes a retained primary lock, and
`hftNetHaReportsPrimary` reads `HoldsPrimaryLock`. This preserves the role during
the failed-reset interval while refusing to treat that unmapped adapter as ready
to run. Configuration alone still proves no role; genuine lock refusal still
proves standby, as qualified in the
[native HA role record](RECORD_2026-10-14_native-ha-arbitration.md).

The writer-lock syscalls, reset implementation, store layout, send/replay paths
and reset error code are unchanged. No lock or allocation is added. This is
functional recovery qualification, not a latency benchmark.

## Qualification and scope

The focused corrected run passes **12/12 with zero skips** in each TLS
configuration. GCC 11.5.0, 14.2.1 and 15.2.1 and Clang 21.1.8 also pass all
twelve cases in both configurations. GCC 14 address and undefined-behavior
sanitizers pass both configurations with leak checking enabled.

The existing durable-teardown, memory-store and QuickFIX-store native fixtures
also pass in both TLS build configurations, six executables in total. The normal
optimized native library passes the 37-case HA regression/availability/edition
selection on .NET 8.0.31 and .NET 10.0.12. The broader development store and HA
selection passes 53/53. All runs have zero skips; selections overlap.

Open-edition stores and availability/edition guards pass 20/20, and the open
source boundary compiles independently. Java prerequisites and JNI guards pass
13/13. Both complete Workbench unknown-role stages pass twelve cells each across
six surfaces and two scenarios, with no unavailable lane. Native .NET's real
mmap standby/takeover lifecycle and its Chromium rendering also pass. The
supplementary before-arbitration DOM check shows the unstarted member as FAULTED
with `Primary role known: no`, matching the model rather than a healthy standby.
The source scan reports zero findings in both changed engine/test files.

Compiler qualification starts at the baseline pin with the implementation patch
captured in its logs. Later stages run the committed correction at `ee452133b`;
the source content is unchanged across those pins, and each driver checks its
input hashes at completion.

After the final fetch/rebase check, all source hashes from the full qualification
still match. At clean integrated pin `af83497c1`, the twelve native cases pass
again in both TLS configurations, and the registered 37-case binding selection
passes with zero skips. The binding rerun uses the unchanged qualified production
library and managed assembly; both source inputs and the native library hash are
checked before and after. `integrated-logs.tar.gz` retains the pin and reports.

These tests invoke the real native reset and primary-open C ABI and the actual
store adapter. They do not establish a FIX peer reconnect or restore data already
discarded by the explicitly requested destructive reset. The failed reset does
not rewind the runner's counters; only a successful explicit reset does so.
Writer exclusion is tested on the local filesystem, not as a multi-host HA
replication protocol.

JNI's classic offline mmap reset uses a temporary concrete store that is deleted
after the operation, rather than retaining this adapter. Rust's classic mmap
clear zeroes the existing mapped header/index without unmapping or resizing.
Those code paths do not have the pointer-as-open inference corrected here; the
cross-flavour model checks remain separate from this native fault fixture.

## Reproduction and retained evidence

[run-focused.sh](evidence/native-mmap-reset-failure-20261014/run-focused.sh) takes
a session source root, absolute output root and `baseline` or `fixed`. Baseline
expects eight passes and four failures per TLS configuration; fixed requires
twelve passes and zero skips. Use the baseline branch for the original source.

[run-qualification.sh](evidence/native-mmap-reset-failure-20261014/run-qualification.sh)
adds four compilers, sanitizers, existing native stores and the complete prior
HA binding/edition/browser qualification over the corrected source. Wrap the
outer invocation in `host-cpu-slot`; outputs stay under the session build root.
[run-integrated.sh](evidence/native-mmap-reset-failure-20261014/run-integrated.sh)
takes the source root, completed qualification root and fresh output root for
the final source-bound native and binding rerun.

Compressed logs are retained beside the drivers and under
`/home/yann/archive/libhft/native-mmap-reset-failure-20261014/`. Build products and
runtime scratch are under
`/home/yann/build/codex-libhft-hp/libhft/native-mmap-reset-failure-20261014/`.
