# Session capacity and lifetime review — 2026-10-10

Reviewed from `19f8378f7ca163afb238c9702e5750b5a0eba7c4` in the isolated
`codex-review-session-1010` worktree. Parallel agents reviewed C++, Java and Rust;
the root serialized heavy builds/tests through `tools/host-cpu-slot`, with at
most 16 compilation jobs and `-flto=1` where LTO was enabled. No .NET source changed.

## Changes and reproduced failures

* **C++ disconnected send batches:** disconnect notification previously left an
  accepted, unwritten caller-owned batch pending. A later flush could send it on
  the old connection; a real half-close reproduced 189 leaked wire bytes. The
  disconnect boundary now discards that batch before calling the application,
  preserving sequence/store state for replay and any replacement batch created
  by the callback.
* **C++ and Java FIXP borrowed append:** compaction moved source bytes before
  copying a borrowed span. Append now preserves consumed and unread source parts
  in place. C++ also uses overlap-safe copying. Exhaustive range checks cover
  244,409 admitted C++ ranges and 802,150 Java compaction ranges; the original
  C++ implementation corrupted 46,376 admitted ranges. Another 52,360 C++
  refusals preserve bytes and cursors.
* **C++ shared-memory payload alignment:** cache-line alignment alone did not
  satisfy over-aligned payload types, and page-aligned mappings were not
  necessarily aligned to the shared layout. Storage now honors both alignments;
  mapping admission checks the actual address before typed access. Failed
  creators unlink their own object, while failed attachers preserve it.
* **C++ CORE liveness:** an unanswered TestRequest previously never expired its
  connection, and timer send failures were ignored. Timers now return terminal
  status to the transport owner. Comparisons handle backward clocks and overflow;
  HeartBtInt=0 disables inbound timers while retaining the existing outbound
  heartbeat policy. Acceptor removal deregisters readiness before close and
  preserves peer servicing when slots shift.
* **C++ CORE short sends:** a callback could close a zero-copy socket before its
  receive borrow was released, or close an acceptor-owned socket while readiness
  still referenced it. A sticky send fault blocks subsequent dispatch/sends;
  closure waits for borrow release and the transport owner. Successful reconnect
  explicitly clears stale parser/probe/fault state without choosing a new
  sequence-number policy.
* **Java encoder capacity:** oversized headers, bodies or configured identities
  grew retained scratch before the BodyLength refusal. Complete envelope admission
  now precedes variable-sized field writes. A cheap 19-digit upper bound handles
  ordinary sends; only near-capacity messages count the exact sequence width.
* **Rust application capacity:** header writes could consume the sequence or
  exceed the available frame budget before admission, while raw callbacks could
  return invalid end offsets. The complete envelope is admitted before encoding;
  callback ends must preserve the header, checksum reserve and BodyLength limit.
  Refused sends restore the sequence and do not save or batch invalid frames.

* **Supported C++ benchmark failures:** every direct CORE timer caller now
  propagates faults. Single/multi client waits, the paced harness and split
  worker/poller stop on failure; closed-loop early exits release client sessions.
* **VMA pool ownership:** due Heartbeat/TestRequest sends now acquire the same
  API lock as receive/coordinator work. Workers mark faults and stop the failed
  cell; sockets close only after the coordinator joins all workers. This also
  prevents a retired peer's undrained queue from blocking shared routing.
* **Multi-session tick-to-trade:** the accepted CLI mode sent a trigger and waited
  for the NOS/ER completion flag. It now sends an actual tick, observes the
  session's reaction counter and records the same feed-owned timing boundary
  as the single-session path. Existing open/split tick refusals remain explicit.
* **Multi-session send admission and peer lifetime:** closed/paced loops now stop
  immediately when an order send is refused, before marking it in flight or
  admitting an unrelated reply. The borrowed peer array remains alive through
  client cleanup and is then freed; allocation/connect/Logon early exits also
  release all clients.
* **Legacy CP benchmarks:** four documented programs could no longer compile
  after their helper headers were removed. Benchmark-local helpers restore the
  synthetic timestamp echo workload using the current CORE APIs. A shared
  runtime gives the I/O thread sole socket ownership, uses an atomic handoff,
  waits for each phase's exact completions, and keeps warmup out of measured
  storage. This removes cpclient2's warmup-over-capacity write and extra send,
  cross-thread slot races, unsafe shutdown and unbounded failure waits. The
  clients retain their default counts/rates and summary formats, and exit after
  joining their worker. Protocol helpers validate identifiers and numeric
  fields and stop coalesced business dispatch after Logout.

The original multi-session tick-to-trade TCP run exited with a client failure
and zero replies after its five-second stall deadline; the server exited normally.
The legacy programs' original evidence is four missing-header compile failures,
not a runtime comparison against an adapted historical implementation.

The capacity checks avoid allocation/growth on rejected messages. Alias repair
uses existing storage; its extra work occurs only on the compaction path. VMA
timer locking occurs only when a send is due, with an idle-no-ticket control.
These are structural observations, not measured latency improvements.

## Verification

Independent checkers validate exact test identities, pass/skip lists, process
results and the preceding published pass's coverage floor. Original/final
comparisons use identical corrected fixtures and preserved source hashes.

| Gate | Result |
|---|---|
| C++ disconnected batch original | 6 passed; 36 failed |
| C++ borrowed append original | 3 passed; 3 failed |
| C++ shared-memory alignment original | 6 passed; 8 failed |
| Those three final / ASan+UBSan / Clang / exceptions+RTTI disabled | 42 / 6 / 14 passed in every variant |
| CORE timer original, normal and NICTIME | 12 passed; 25 failed in each |
| CORE timer final, normal / NICTIME / both sanitized / Clang / exceptions+RTTI disabled | 37 passed in each |
| CORE short-send original / timer-only intermediate | 8 passed, 40 failed / 10 passed, 38 failed |
| CORE short-send final / ASan+UBSan / Clang / exceptions+RTTI disabled | 48 passed in each |
| C++ open edition | 162 binaries passed; no reported skips |
| C++ selected private integrations | 6 binaries passed; no reported skips |
| Java borrowed append and field-capacity original / focused final | 19 passed, 26 failed / 45 passed |
| Java full-envelope capacity original / focused final | 37 passed, 96 failed / 133 passed |
| Java full development / open edition | 6498 / 6030 unique cases passed; no final failures/errors/skips |
| Rust application capacity original | 72 passed; 152 failed; no ignored cases |
| Rust focused default / no-default / open with service packs | 224 passed in each |
| Rust full default / no-default | 1825 passed in each; one existing ignored documentation example |
| Rust Clippy default / service packs | All targets passed with warnings denied |
| Benchmark driver original / final / ASan+UBSan | 4 passed, 15 failed / 19 passed / 19 passed |
| VMA pool original / final / ASan+UBSan | 4 passed, 13 failed / 17 passed / 17 passed |
| Multi-session send original / final / ASan+UBSan | 2 passed, 8 failed / 10 passed / 10 passed |
| Benchmark real TCP | 4 passed: NOS/ER and tick-to-trade, each with one/two sessions |
| Unsupported tick-mode controls | 2 passed: open and split refuse before connecting |
| Existing benchmark helpers / open-warmup wiring | 6 binaries / 3 checks passed |
| Legacy application final / ASan+UBSan | 38 passed in each; no skips |
| Legacy real TCP | 11 passed; exact counts/sinks, graceful server stop and refused connections |
| Final export scan | 37 changed code/build/test files; zero findings |

The Java focused pairs overlap at the native-loading guard: the union is 177
cases, of which 176 are new. The first 45-case focused run preceded the additional
full-envelope preflight; the complete edition runs validate the final encoder
against the entire union. Native loading is required and libraries remain at
the standard build-root paths. Three counter-disabled controls are rerun by the
explicit disabled-counter execution; the final XML inventory must contain no skips.

Rust capacity cases use MemoryStore, both save-before/save-after policies,
single/batched sends, FIX 4.0/4.4, sequence widths, optional identities and tag 369.
They do not establish durable-store behavior. C++ alignment tests use real shared
mappings, forced aligned/misaligned addresses, 64/8192/65536-byte payload alignment,
creator/attacher cleanup and retry controls. CORE ownership fixtures cover real
acceptor paths and deterministic descriptor/child transports. Fake VMA operation
is not a vendor hardware or network performance result.

`CoreEngine::CheckSession` now returns an integer fault status. Ordinary callers
that ignored its former void result remain source compatible; an external exact
void member-function pointer or custom void-return timer send hook needs to adopt
the integer contract. All in-tree call sites were reviewed. Ordinary/NICTIME engine variants and
the VMA pool mock were rebuilt; vendor hardware behavior was not qualified.

## Evidence and publication

Publication base: `00253caf32008681a2583fe335ba2915296c567e`. The incoming changes were confined to
documentation, internal configuration and retained evidence. All 37 tested
source/build/test files match their frozen hashes after the clean rebase.
Local archive: `/home/yann/archive/libhft/reviews/2026-10-10-codex-review-session-1010`.
The mirror destination is the same path on `hp`. Archives retain original/final
source, full logs/reports, checksums and a git bundle. Final source hashes are
rechecked after publication rebase and before cleanup.

Independent checkers: `scratch/cpp/check-results.py`,
`scratch/java/check-reports.py`, and `scratch/rust/check-results.py`.
The reproduction drivers and per-run command metadata live under `scratch/`;
run them from a disposable worktree with a session build root through the host
slot/guard. Several baseline drivers select preserved original headers; Java
and Rust originals instead use the explicitly hashed baseline snapshots.

Earlier fixture development is preserved separately: the disconnect fixture
initially retained string views into temporaries; its corrected source was rerun
against original and fixed implementations. Earlier smaller Rust and benchmark
inventories are retained but excluded from final coverage claims. The Java
checker was corrected to expect JUnit's grouped decimal sequence labels. The
benchmark driver fixture needed a conditional guard for the vendor-only zero-copy
flag before its first successful build; the corrected fixture ran on both versions.
The first restored legacy application attempt passed 26 of 38 cases: three builder calls supplied a one-byte length for
complete `35=...` fields. The corrected calls use each field's full literal length;
explicit order/report MsgType assertions were added, and all 38 cases and the
real TCP workload were rerun. The failed attempt remains separately archived.
A later scratch helper build omitted the VMA selection/include flags required by the existing single-server
poll-failure fixture; correcting that harness rule did not change production or
test sources. Its first attempt and final rerun are also retained.

Code commits:

* `36ac8b044` — fix(rust): admit application envelopes before encoding
* `b1c6c3261` — fix(cpp): enforce send and buffer lifetime boundaries
* `6f5a44010` — fix(java): preserve borrowed frame bytes during compaction
* `c47e38071` — fix(cpp): retire failed CORE sessions through their transport owner
* `8af9c7e36` — fix(java): admit complete FIX bodies before growing encoder scratch
* `82e948d9f` — fix(bench): propagate CORE faults and repair legacy clients
