# Replay durability and finalization history — 2026-10-09

Session `codex-review-replay-1009`, starting at `a8aa1b2d7` in private
`atrekes/libhft-devel`. Parallel C++, Java and Rust reviewers used this session's
worktree. Root alone ran builds and suites under the shared host lease, with
parallelism capped at 16 and a memory/process check before each job. Every build
used the session's absolute `LIBHFT_BUILD_ROOT`.

## C++ synchronous queue preservation

`FileJournal::Sync` advanced the queue head to its tail without writing accepted
entries. Rewriting the current replay window could recover only retained payloads;
queued records already evicted from RAM disappeared even when Sync returned true.
The shared journal also serves FIXP finalization, so that boundary had the same gap.

Sync now drains accepted entries under the existing file mutex, then writes owed
window payloads and the authoritative checkpoint. A shared consume helper preserves
acknowledgement and replacement-mark behavior. The worker checks its captured head
under that mutex before touching a slot that the owner may have freed. I/O faults
remain terminal; no new syscall, allocation or lock was added to asynchronous saves.
Acknowledging ordinary queued frames also removes their replay-window repair work:
when distinct queued records clear all obligations, repair needs one window scan
instead of repeatedly searching the window for each owed frame. No timing claim
is attached to that source-level reduction.

The new 25-case binary covers classic Sync and FIXP finalization, small/wrapped
queues, eviction, checkpoint-only endings, dropped retained payloads, duplicate-key
replacement, resumed worker writes and reopen. An independent decoder checks the
actual journal. Three fault cases force failed/positive-partial writes and verify
rollback and retirement. The original journal fails 22 cases and passes three
controls; optimized and ASan/UBSan corrected runs pass all 25.

## Java finalized-session ID ownership

The finalized-session journal returned an unmodifiable list containing its own
mutable ID arrays. A caller could change future history exports while the internal
membership set still held the correct ID. An acceptor importing that altered list,
then replacing its store, could admit the real retired ID and reject an unrelated ID.

The history accessor now returns a frozen list of copied IDs. Each caller owns its
arrays; neither element mutation nor later journal additions alter an earlier
snapshot. This is a cold history-export operation, with no per-message allocation.
The shared helper also serves the private mmap store.

Twenty new cases exercise live and recovered histories, input/output ownership,
list mutation controls, public file-store access, and actual Standard/CME acceptor
handshakes after store replacement. Original code fails 14 cases; six new controls
and the native-loading guard pass. The corrected focused suite passes 50 cases,
with zero failures, errors or skips.

## Rust durable-store behavior

QuickFIX compatibility stores latched reset failures but allowed ordinary writes
after append or checkpoint I/O failures. Subsequent I/O could obscure a partial
sequence file or append behind a torn index. All ordinary write/sync failures now
fence saves, inbound checkpoints, teardown checkpoints and unchecked clear. Explicit
offline reset can recover the same object only after its requested I/O succeeds;
writer fences remain held. Cold reopen remains a separate recovery operation.
Committed outbound evidence stays readable after a later checkpoint fails. Failed
inbound checkpoints retain the previous cached target number. Invalid arguments
remain nonpoisoning refusals.

Sixteen new methods cover both QuickFIX layouts. Eight isolate real positive-partial
regular-file writes with Linux process limits in subprocesses; three refuse outbound
sequence-file paths; four force real fsync failures; one checks healthy behavior
after rejected arguments. Original code fails the 15 fault methods and passes the
healthy control. An existing inbound-error regression now requires explicit reset
after repairing the path, matching the terminal failure policy.

The first full Rust run exposed an HA regression fixture that deleted its valid
checkpoint and expected failed-store teardown to recreate it. That fixture now
moves the valid checkpoint aside, restores it after the injected refusal, and
verifies continued fencing, unchanged bytes at handoff and correct cold recovery.
Only the test changed; the HA wrapper inherits the same store failure contract.
The initial failed run is retained beside the final complete runs.

Classic async-file empty administrative saves also erased or evicted RAM payloads,
although their portable journal representation is only a checkpoint. Those payloads
could reappear on reopen; an empty marker colliding with a dropped dirty payload
could instead lose it permanently. Empty saves now update checkpoint state without
changing replay payloads, timestamps or dirty obligations. Standalone MemoryStore
empty-marker behavior and the on-disk format are unchanged. Sparse/nonmonotone
payload saves and lower checkpoint-only markers remain supported.

Five new empty-save methods cover 16 final combinations: same-key saves, wrapped
non-power-of-two windows, sync-before-send, sparse payloads, reset, and queue-full
dirty payloads. They inspect live/indexed replay, checkpoint, close, reopen and raw
records. All five methods fail on original production code. The initial focused
store suite passes 103 tests; the later dirty-payload method passes separately and
is included in both final full feature runs.

## Final verification

| Gate | Result |
|---|---|
| C++11 open edition, layering and simulator | 150/150 binaries pass; zero reported skips; 83 private binaries excluded |
| Additional private mmap/journal binary | Pass; zero reported skips |
| C++ new optimized and ASan/UBSan regression | 25/25 each; leak detection and fatal UB enabled |
| Java development, mandatory native loading | 5,989 unique cases pass |
| Java open, separately built native library | 5,546 unique cases pass |
| Rust default features | 1,462 pass; one pre-existing ignored documentation example |
| Rust no-default-features | 1,462 pass; the same example ignored |
| Rust default all-target Clippy | Pass, warnings denied |
| Export-name scan | Ten engine files (nine changed plus incoming Rust context), zero findings |

Java full totals have zero final failures/errors/skips and deduplicate by class and
case name. Three counters-disabled cases skip in the ordinary fork and pass in
their configured fork. Native-loading guards pass in both editions. No missing
native library was treated as a green skipped run.

Independent reviewers cross-checked the other languages' ownership, queue-head,
fault and reset changes. Their suggested Rust dirty-payload regression was added
before final full verification. Root questioned two C++ fixture counts, then
confirmed the original expectations after accounting for each classic save's
automatic checkpoint entry; no fixture correction was needed.

Execution was on Linux only. Windows-specific paths were not run. New Java owner
tests use the public file store and single acceptor; existing shared/private
finalization suites also pass. No NIC benchmark, throughput or latency percentile
claim is made. The earlier .NET aliasing proposal remains separate and pending
reserved-path approval; this pass changes no .NET source.

## Publication and retained evidence

Final integration is based on `d6289a6e1`. All nine changed engine files
match the final verification manifest; incoming changes are reviewed before push.
The incoming Rust changes write five canonical tag prefixes directly and avoid
zeroing/copying a temporary plain-field array. Independent review checked header
byte/order/sequence/timestamp equivalence and the array's initialized-prefix proof:
only a successful survey reads its written prefix; partial fallback reads none.
Both full Rust feature configurations and strict all-target Clippy pass after each
integration round. Earlier integration logs are retained too.
The final source manifest also retains this incoming `wire.rs`, for ten files total.
Fixes are committed and backed up on the private session branch during verification,
then published linearly to private main after fetch/rebase. Other sessions' claims
are preserved.

Evidence is retained locally and on HP at
`~/archive/libhft/reviews/2026-10-09-codex-review-replay-1009/`: original/final sources,
counterfactual drivers and logs, complete test reports, independent reviews, source
hashes, verification summary, published patch and Git history bundle. Both archive
manifests are verified before removing this session's worktree and build outputs.
