# QuickFIX operational writer fence interoperability

The operational QuickFIX wrapper held only `flock`, so it did not exclude
pure-Java QuickFIX store owners on Linux. It could launch an incumbent into a
store Java already owned. In the opposite direction, Java could open and repair
an index while the wrapper's incumbent was live. The correction takes both
lock protocols before launching the child. It changes no engine implementation,
message format, send path or replay path, and adds no dependency to pure Java.

## Confirmed baseline

The unmodified wrapper is pinned by `16521fe80`; the eight-test startup fixture
is retained at `0f2d7dfe4`. Four wrapper tests fail and four existing/lifecycle
controls pass. The failures cover record-lock exclusion in both directions,
the signalled-child exit status and a signal during actual child creation.

The normal SIGTERM case returned 241 after the handler forwarded termination
in `baseline-lifecycle/`. Under the isolated functional run it also hit the
startup gap and the wrapper was killed directly (subprocess status -15).
The deterministic startup fixture delivers SIGTERM inside the real `Popen`,
after creating its child but before returning its handle. The old wrapper has
not installed its handler there and dies without forwarding that signal.

The Java probe compiles the actual `QuickFixFileStore`, `StoreFileHandles` and
`RawFixView` sources, not a replacement store or lock stub. Java 17 compiles
the bytecode with `--release 8`; runtime checks cover both layouts and both
ownership directions on Java 8, 11, 17, 21 and 25. All twenty
exclusion cases fail on the baseline; all forty ownership/release controls
pass. Every wrapper-to-Java attempt actually changes the torn index, and every
Java-to-wrapper attempt actually launches the marker child. The data is retained
in `baseline-startup/`, alongside compiler/runtime versions and input hashes.

## Correction

The wrapper acquires `flock` and a POSIX record lock on the agreed incumbent
side file before child creation. Both are nonblocking. Native store profiles
use the first protocol; Java's FileChannel uses the second, and managed .NET
participates in both. Partial acquisition and failed child creation release
both. Lock errors `EACCES` and `EAGAIN` identify contention, as specified by the
[Python fcntl documentation](https://docs.python.org/3/library/fcntl.html#fcntl.lockf);
other I/O errors are not presented as an occupied writer slot.

Signal handlers precede `Popen`. A signal received before the child handle is
available is retained and forwarded once its process group is known. A signal
already pending at the prelaunch check cancels the launch. A child
that exits between `poll` and signal delivery is harmless. The parent waits
for the child, preserves ordinary exit codes and reports signalled children
as `128 + signal`, then releases its locks.

This is cooperative supervision, not arbitrary writer detection. Keep the
wrapper alive for the incumbent's lifetime. Direct C++/Rust and pure-Java store
locks still differ as the Java store documents; this wrapper supplies the
common operational fence without changing those protocols. The tests use
local Linux XFS, not NFS or SMB. Shared-filesystem deployments still need their
own lock-semantics qualification, and Windows needs an equivalent supervisor.

## Evidence and reproduction

Raw logs, input hashes, source pins and runtime versions are under
`/home/yann/archive/libhft/quickfix-wrapper-record-lock-20261012/`. The retained
`evidence/quickfix-wrapper-record-lock-20261012/run-checks.sh` drives the wrapper
tests and the five-JVM production-store matrix. `run-qualification.sh` adds
conformance guards and public scanning. Set explicit session-worktree,
build-root, temporary-directory and retained-evidence variables, and run the
outer command through `host-cpu-slot`. Functional checks can use `isol` while
shared-core work runs; these results are not latency measurements.

## Corrected qualification

The corrected source pin is `a9d658496`. All nine wrapper tests pass with zero
skips, including three injected lock-error results (`EACCES`, `EAGAIN`, `EIO`),
failed launch cleanup, ordinary nonzero child exit, SIGTERM exit status and the
signal during actual child creation. The original four failures are corrected.
The five-JVM matrix passes all twenty ownership exclusions and all forty
controls. Every refused Java contender leaves the torn index untouched; every
refused wrapper leaves its marker child unstarted.

All three selected conformance guards pass with zero skips or failures:
the operational fence self-test, public-export self-tests and documented build
facts. The runner reports **PARTIAL (3 of 362)**, not a full conformance pass.
The two changed tool files pass the public scan with zero findings. Source and
driver manifests verify unchanged after the complete run; `git diff --check`
also passes.

Complete baseline and corrected unit logs, the five pairs of JVM reports,
runtime/compiler versions, source pins and selected source manifests are
retained in git under `evidence/quickfix-wrapper-record-lock-20261012/retained/`.
Retained log copies normalize trailing spaces; raw archive logs are unchanged.
The larger guard-input manifest and earlier lifecycle baseline remain in the
archive. Reproduce the original baseline using its pinned eight-test fixture;
`LIBHFT_EXPECT_BASELINE=1` selects that original class, requires its four
failures and requires four Java exclusions to fail on each JVM. Ordinary
execution requires all cases and controls to pass.

The post-rebase integrated source pin is `aea6eb6d5`. The complete qualification
runs again there: nine wrapper tests, twenty JVM exclusion cases, forty controls
and all three selected guards pass with zero skips. Both source and driver
manifests match the corrected run byte-for-byte; the integrated run's larger
manifest also verifies unchanged. Logs, reports and pins are retained under
`retained/integrated/`. Keep `PYTHONDONTWRITEBYTECODE=1` when reproducing the
original baseline fixture, so its imported wrapper writes no in-tree cache.

The final publication rebase onto `528745b64` also incorporates another owner's
classic FIX protocol and validation tests. None of the wrapper, its tests,
the three Java probe dependencies or the four retained drivers changes:
their complete manifests still match the integrated qualification. Those
unrelated protocol edits are not substituted for this source-pinned evidence.
