# Recovery progress and reconnect timing — 2026-10-08

Session `codex-review-progress-1008`, based on `100f301cb`. Parallel reviewers
covered classic C++ connection timing and Java/Rust FIXP recovery progress and
terminal-response ownership. Root serialized all builds/tests through the shared
host CPU lease, with at most 16 workers and separate out-of-tree build roots.

## Findings and changes

- C++ armed its Logon deadline and SendingTime from the timestamp supplied before
  store recovery, TCP connection and TLS/proxy setup. Slow setup could consume
  the entire timeout before sending Logon, or cross a trading-window boundary.
  Connect now adds measured elapsed setup time to the caller's timestamp,
  preserving its clock origin. The production duration is monotonic; injected
  backward movement is clamped and timestamp addition saturates. Schedule
  admission is rechecked by the existing OnConnected gate.
- C++ reconnect delay multiplied a valid 16-bit seconds value into a 32-bit
  Windows long. The remaining microseconds now use uint64_t, retaining bounded
  cancellation slices through the maximum configured interval.
- Java and Rust pending NotApplied queues previously returned before reads and
  liveness checks. A maximum gap could delay available Terminate, FIN, read
  error or peer silence by billions of pumps. A cold poll now handles eligible
  FIFO-head controls and reads at most once per pump while still advancing at
  most one notification chunk. The last chunk may also send FinishedReceiving.
  Terminate, UnsequencedHeartbeat and an unchanged-frontier Sequence outside
  incoming replay are eligible. Failed terminal input retires the pending owner.
- Application frames, new gaps and finalization markers remain at the FIFO head
  until the current notification queue completes. Such local receive
  backpressure suppresses peer-silence judgement and prevents reads past data
  into a later EOF. Controls behind this data remain ordered; this is not an
  arbitrary-priority bypass or an unbounded pending-message queue. New partial
  bytes credit transport progress once; repeated peeks do not refresh liveness.
- Java acceptor and Rust single/multi acceptor silence, protocol-violation and
  finalized-session rejection wrappers could close a positive partial response
  twice. Cleanup now checks whether its lower layer already retired the owner.
  Rust's outer multi-peer pump also avoids reclosing an inactive child. This
  concerns cleanup within one operation, not later explicit close/recycling.
- Java and Rust initiator Terminate answers bypassed the helper that retires a
  positive partial write. They now use that helper. Java also retains the failed
  reply's byte count and raw write result. Zero/negative/full replies retain their
  existing terminal behavior; tests distinguish ordinary and queued recovery.
- Pending-step diagnostics retain a consumed control's input metadata, or a
  queued notification's outbound application metadata when no control was
  consumed, alongside the current read/write counts.

- Cross-review found a finalization interaction: planning FinishedReceiving sets
  optimistic peer-acknowledgment state before the pending NotApplied output has
  drained. An early Terminate must abort without retiring the session ID. The
  runners now distinguish a queue that still owes FinishedReceiving from an
  ordinary recovery gap after an acknowledgment already sent. The latter still
  permits finalization. Initiators capture this distinction before a partial
  terminal reply can clear the queue.
- An interrupted finalization also left acknowledgment state across reconnects.
  A matching Terminate during the next negotiation could falsely finalize the
  logical session. Rust resets unfinished state after the finalized-ID refusal
  and successful dial. Java resets unfinished initiator state on successful
  start and per-connection acceptor state on accept, preserving the completed
  initiator marker and the acceptor's separate retired-ID registry/store.

## Verification

C++11 open verification selects, runs and passes 147 binaries, with zero reported
skips and 83 private binaries excluded. The full reconnect-driver suite and its
ASan/UBSan run pass, including all 35 new cases (19 setup-clock/schedule and 16
virtual backoff/cancellation cases). Leak checking and fatal undefined-behavior
diagnostics are enabled. The original header produces 52 failed assertions;
the native LP64 backoff controls already pass there. The Windows overflow fix has
source-level width evidence and portable boundary tests, not a Windows run.

Rust default and no-default-features each pass 1393 tests in 21 result sections,
with zero failures and one existing ignored builder documentation example. Each
library run contains 1245 cases. All 17 new focused methods pass, exercising 344
scripted combinations: 144 queue/control, 72 acceptor terminal cleanup, 32
ordinary/pending initiator Terminate reply cases, 72 acknowledgment-order cases,
and 24 initiator reconnect-state cases. All seventeen methods fail against the
original three runners; the six follow-up methods also fail against the first
progress fix. Baseline methods stop at their first assertion, so this does not
claim every combination failed on the baseline.

Java focused verification passes 721 cases with mandatory JNI: 504 new
parameterized cases, 216 existing legacy finalization cases and the native-load
guard. The original production files fail 408 cases and pass 97 (including the
guard), with zero errors/skips. The first progress fix fails 80 cases and passes
377 in the finalization follow-up baseline. The new suite contains 456 progress
and finalization cases and 48 terminal-cleanup cases. Its terminal-reply method
exercises eight ordinary/pending and write-outcome subcases per parameter set;
its three reconnect methods exercise 96 inner scenarios across 72 invocations.
Tests include both SOFH formats, three roles, flow enforcement off/on, keepalive
off/on, fragmented/buffered input, wrong-session and malformed controls, sibling
usability, diagnostic metadata and one-notification-per-pump progress.

Java development verification passes 4479 unique cases across 330 reports; the
open edition passes 4037 across 293 reports. Both builds require JNI at the
standard relocated native path. Final XML reports contain no failures, errors
or unresolved skips.
The three counters-disabled tests skip the ordinary JVM and run in their dedicated
configured JVM; final verification checks their passing results as well as the
native-load guard, rather than relying only on Maven's exit code.

Earlier runs are preserved with their status, not counted as final verification.
Java iteration 1 passed its 505-case focused selection, then its development run
was stopped when cross-review found the metadata and partial-reply defects.
Iteration 2 passed 577 focused cases and 4335 development cases; its open run was
stopped for the finalization follow-up. Iteration 3 stopped after eight focused
fixture failures: rules-off acceptors legitimately emitted RetransmitRequest
where the new fixture expected no bytes. The corrected fixture checks its exact
fields and absence of extra frames. Rust iteration 1 passed both full suites
before the follow-up. Iteration 2 stopped after two analogous fixture failures.
All these logs remain under their numbered iteration directories.

## Review and publication evidence

Independent review of the final C++ change and the final Java/Rust finalization
follow-up found no blocker. The final engine source set has 16 files. Its frozen
hashes match after restoration of the deliberate baseline overlays, and the
public-export scan reports zero findings. Full test logs, XML reports, drivers,
source snapshots and independent review notes are retained in session scratch.
The final summary is generated from those reports by `summarize-verification.py`.

Scripted tests do not claim live network failure injection, real durable-storage
fault injection, or measured throughput/percentile latency. The poll removes
accessible-control/deadline starvation, retaining the FIFO limitation described
above. The new poll work occurs only during pending recovery; setup clock reads
occur only on connection setup. No .NET or reserved C++ FIXP source was changed.
Native verification runs on Linux; no Windows runtime run is claimed for the
width correction.

Publication uses the private `atrekes/libhft-devel` remote, rebasing onto current
main before a linear push. The integration evidence verifies the tested source
hashes after rebasing and records incoming changes separately. The archive is
`/home/yann/archive/libhft/reviews/2026-10-08-codex-review-progress-1008` on BEELINK2
and hp. It retains the original and integrated histories, final source snapshots,
this record, logs/reports, and a SHA-256 manifest. Publication and archive checks
are required before removing the session worktree and build root.
