# FIXP explicit replacement and mailbox ownership review — 2026-10-11

Reviewed from `3417938773c8f6752b65c93a2b8fa06875c17873` in the isolated
`codex-review-flow-1011` worktree. Three agents reviewed C++, Java and Rust in
parallel. The root serialized heavy builds and tests through `tools/host-cpu-slot`
with at most 16 build jobs and `-flto=1`. No .NET source changed.

## Confirmed defects and fixes

* **Native FIXP mailbox:** the payload was copied, but its `SofhFrameView.payload`
  still pointed into the producer's receive storage. Reusing that storage could
  change the returned frame view despite the copied payload remaining correct.
  The mailbox now retains frame metadata without a borrowed pointer. A successful
  drain binds the returned view to the caller's output; a refused copy exposes no
  payload pointer and preserves the pending message. Mailboxes can be copied
  without borrowing each other's storage. Both native initiator/acceptor Step
  and Drain paths are covered, including source reuse, retry and empty payloads.
* **C++ direct Connect:** a failed replacement could leave a closed connection
  marked LIVE, with pending gap notifications, heartbeat deadlines and the old
  callback generation. Admitted replacements now retire that connection before
  opening a store or dialing. New negotiation encode/send failures also mark the
  protocol disconnected while preserving send diagnostics. Preflight refusals
  retain the existing connection; successful replacements preserve the outbound
  sequence frontier and replay records.
* **Java start:** a durable store reopen can release its old owner before failing.
  The runner previously retained its established protocol/status in that case.
  Connection work is now retired before the reopen, so store errors, HA standby
  and recovered sequence exhaustion leave the runner disconnected. Tests include
  a real file-store reopen against a directory, successful retry/history checks,
  and null-transport admission controls. The caller continues to own transports.
* **Rust direct connect:** even a successful direct replacement retained the old
  pending gap and liveness clocks. That could emit old NotApplied/heartbeat work
  or expire the new handshake. Retirement now precedes store acquisition/dialing;
  failed Negotiate sends also disconnect protocol state without erasing failed
  send diagnostics. Configuration/finalization guards still precede retirement.

These fixes change lifecycle work and pointer ownership. They introduce no
allocation or lock on the application send path. No latency improvement is
claimed from these correctness runs.

## Verification

Original/final comparisons use the same frozen regression source for each pair.
Independent checkers compare exact identities, outcomes, skip lists and process
results rather than relying only on suite exit status or totals.

| Gate | Result |
|---|---|
| Native inbox original | 6 passed; 20 failed; 44 failed assertions |
| C++ replacement original | 14 passed; 54 failed; 326 failed assertions |
| Inbox/replacement final, ASan+UBSan, Clang, exceptions+RTTI disabled | 26 / 68 passed in each variant; no skips |
| C++ complete open edition | 164 binaries passed; zero skips |
| C++ selected private integrations | 11 binaries passed; zero skips |
| Java focused original | 53 passed; 16 failed; zero errors/skips |
| Java focused final | 69 passed in each of three configured executions; zero errors/skips |
| Java development / open edition | 6,522 / 6,054 unique passing identities; zero final errors/skips |
| Rust expanded original | 8 passed; 28 failed; no ignored tests |
| Rust focused default / no-default / open with service packs | 36 passed in each; zero ignored |
| Rust full default / no-default | 1,861 passed and one unchanged ignored doctest in each |
| Rust Clippy default / service packs | Both passed with warnings treated as errors |
| Export scan | 9 changed code/build/test files; zero findings |

The Java focused inventory comprises 24 new cases, 44 existing restart controls
and one required native-loading guard. Final full-edition checks retain every
preceding published identity. Native libraries remain in their standard
build-root locations and native loading is required. Three counter-disabled
controls skip under the default execution and pass in their dedicated disabled
execution; the final inventory includes those passing outcomes.

The first Rust 20-case fixture reproduced 14 failures with six controls. It was
then extended to cover initial/replacement Negotiate refusal, including zero,
negative, partial and encoding failures. The complete 36-case original was rerun;
its eight controls include the two initial partial-write cases that already
retired protocol state. The initial fixture, patch and logs remain archived.

C++ and Rust fault injection uses deterministic transports/providers and public
connect/send/step entry points. C++ failure cases seed prior lifecycle states;
its success controls complete a replacement handshake. Rust replacement fixtures establish
their prior connections through protocol handshakes; initial-connect failure
cases stop before admission. Those focused fixtures are
not physical network or disk/HA fault qualifications. Java additionally
uses a real file replay provider for its failed-reopen scenario. Broader runner
and native integration coverage is reported separately above.

## Evidence and publication

Publication base: `2cb40b176ec0fa9badb78fffa79c1bdaf2b9283b`. The incoming changes affect benchmarks and
documentation; the complete engine, tools and publish trees are byte-identical
before and after rebase. All nine tested source hashes match.

Evidence archive: `/home/yann/archive/libhft/reviews/2026-10-11-codex-review-flow-1011`.
The mirror destination is the same path on `hp`. Archives retain original and
final source, exact fixture inventories, full logs/XML reports, driver results,
source hashes and a git bundle. Source hashes are checked after publication
rebase and before cleanup.

Independent checkers are retained as `scratch/cpp/check-results.py`,
`scratch/java/check-reports.py` and `scratch/rust/check-results.py`.
Root reproduction drivers live under `scratch/root/`; run them from a disposable
worktree with an out-of-tree build root through the host resource guard.

Code commits:

* `ef70291c9` — fix(cpp): retire FIXP replacements and own native mailbox views
* `c279ae4c3` — fix(java): retire FIXP session before reopening its replay store
* `02e460748` — fix(rust): reset FIXP transport work before explicit reconnect
