# Batch visibility and FIXP owner review — 2026-10-08

Worktree: `codex-review-flow-1008`, based on `0febbcfdf`.
Parallel reviewers covered C++ classic FIX batching/store faults, Java FIXP
finalization, and Rust FIXP protocol response failures. Root reviewed Java TCP
callback ownership and ran all builds/tests serially under the shared host CPU
lease, with at most 16 workers. The preceding pass's published fixes are retained.

## Confirmed defects and fixes

- C++ deferred outbound persistence happens after batch admission, which may
  precede transport visibility. A failed save followed the already-sent failure
  path and sent Logout, flushing the queued unstored frame first. Durable
  prepare/sync failures could also leave an earlier batch flushable after the
  session retired. Store faults now discard and detach the pending batch before
  notifying user callbacks. A deferred persistence failure of a still-buffered
  frame uses pre-write retirement and returns ERROR without Logout. Frames
  already sent directly retain the existing SENT result and cleanup policy.
  This includes oversized direct sends and rollover that wrote only earlier
  saved frames. Previously saved records and consumed sequence numbers remain;
  durable prepare rollback and uncertain sync semantics are unchanged.
- Java's FIXP initiator consumed FinishedReceiving and finalized the logical
  session, but stayed live when its required Terminate wrote zero/negative bytes.
  There was no queued retry, and later heartbeat traffic could still be sent.
  It now retires on every failed required Terminate, without closing a positive
  short write twice. The inbound step retains outbound template, transport return
  code and visible byte count for every outcome. Successful sends also now report
  their own write result instead of the preceding read result; keepalive answer
  waiting and immediate-close behavior are preserved.
- Java TCP owners resumed an old inbound step after an application callback
  closed/reconfigured the owner or a nested send retired its connection. The
  initiator could report RUNNING with no transport, and both owners overwrote
  nested configuration/store failures with OK. They now snapshot transport
  identity before pumping and preserve the nested owner result/state if ownership
  changed. Replacements finish their own handshake and exchange application
  traffic; ordinary callback sends leave the existing live connection intact.
- Rust's multi-acceptor returned EncodeError after an accepted input advanced
  protocol state but its required response could not be encoded. Direct
  pump_peer retained that peer and its coalesced input with no response retry.
  It now retires only that peer, closes its store/transport and clears buffered
  input while preserving the failed step's diagnostic fields. This covers SOFH
  response capacity and payload encoding refusal, matching the single acceptor.
  Exact-capacity success and sibling traffic remain supported.

## Baselines and coverage

Java's focused baseline ran 95 tests: 29 assertion failures, zero errors/skips,
with the mandatory JNI guard passing. TCP owner tests contributed 24 failures
among 40 cases; finalization contributed five failing methods among 54 tests.
An older test explicitly expected a failed finalization Terminate to leave the
initiator established. That expectation was corrected because its trigger had
already been consumed and logical finalization prevented a recoverable retry.

The TCP matrix covers both owner roles, both SOFH formats, keepalive off/on,
close, store failure, failed reconfiguration, replacement connect/listen and an
ordinary nested-send control over actual loopback sockets. Replacement timestamps
were made monotonic after the baseline so the successful continuation does not
hit an unrelated connect timeout. The finalization addition covers 48 combinations
of three roles, two formats, keepalive off/on and negative/zero/partial/full writes,
including later traffic suppression, exact write counts and sibling usability.
All 95 focused Java tests pass after the fixes.

Rust's focused baseline had four failing methods and one passing control. The
final matrix covers both formats and required NegotiationResponse,
EstablishmentAck and RetransmitRequest responses, configured credentials too
large for the encoder, exact buffer capacity, coalesced tail retirement and a
usable sibling. For the recovery response boundary, establishment uses the same
simulator with a separate adequate output buffer because its ACK and the later
recovery request have equal encoded length. These are scripted transports/stores,
not real network or durable-I/O failure injection.

The initial C++ baseline's 108 cases reported 330 failed assertions. The first
fixed focused run, extended to 144 cases, exposed 24 fixture failures: its parsed
message labelled oversized still fitted the 128-byte batch. The fixture now
contains a 200-byte Text field and explicitly asserts that size. Visibility
expectations and production stayed unchanged. Both original logs are retained;
a fresh counterfactual run of the corrected full matrix against the old header
is the final before-fix evidence: 513 failed assertions across all 144 cases.
The same corrected matrix passes the focused run with the production fix. The
matrix spans FAST/SAFE/TEST, healthy/deferred-save/prepare/sync outcomes,
body/parsed/admin sends, and direct/queued/oversized/frame-count rollover paths.
Fault callbacks attempt a reentrant flush.

## Verification

Rust default and no-default-features each pass 1356 tests, with zero failures and
one pre-existing ignored builder documentation example. Their library subsets
pass 1208 tests. All five focused methods pass.
Java development passes 3759 unique tests; Java open passes 3317. Both have
zero final failures, errors or skips, with required JNI loading and separately
built development/open native libraries. The three counters-disabled cases skip
in the ordinary fork and pass in their configured fork; final aggregation keys
by class and case name.

The C++11 open gate selects, runs and passes all 147 binaries, with no reported
skips and 83 private binaries excluded. The focused reliability run and its
AddressSanitizer/UndefinedBehaviorSanitizer run both pass all 144 new cases;
leak detection and fatal UB diagnostics are enabled. The private reliability
companion separately passes its own mmap cases. It includes open fixtures but
does not run the open main. The preceding recovery-faults record now clarifies
this same distinction for its 126 new cases; its archived logs are unchanged.

## Evidence and scope

No .NET or reserved C++ FIXP runner, flow, liveness, finalization or process source
is edited. Verification is Linux-only; Windows and optional Rust venue/service-pack
features are not claimed. Independent reviewers checked the C++ batch visibility distinction and Java
owner/finalization changes;
root checked Rust peer retirement and preserved diagnostics. No blocker remained.

No per-message allocation, lock or atomic is introduced. The C++ and Rust changes
are in failure paths; Java's TCP owners add one transport identity comparison per
pump. No throughput or latency measurement is claimed. Callback concurrency and
transport-method reentry are not newly promised.

Evidence is retained locally and on HP under
`~/archive/libhft/reviews/2026-10-08-codex-review-flow-1008/`: baseline/intermediate/
final logs, JUnit reports, source hashes, drivers, this record, patch and history
bundle. Both SHA-256 manifests are verified before worktree/build cleanup.

## Publication

Rebased onto `cbc64b088`, whose incoming changes contain only internal benchmark
evidence and coordination updates. All nine engine files match their tested
SHA-256 hashes after rebase; the export scan checks all nine with zero findings.
Whitespace checks pass.

Fix commits:
- `99ee82c05`: Rust response encoding failure retirement.
- `bb9f1528d`: Java required finalization Terminate retirement and diagnostics.
- `a340842c5`: Java TCP callback owner continuation.
- `f3428ffa7`: C++ pending-batch retirement on store faults.
- `90e8bf375`: correction to the preceding review's private test coverage wording.

The original fix checkpoints were backed up to the private session branch.
Their pre-rebase history bundle is retained alongside the final publication
bundle before that branch is removed. Publication targets private
`atrekes/libhft-devel` directly at main. Other sessions' claim blocks are
preserved exactly. Final counts are machine-readable in the archived
`verification-summary.json`.
