# Rust QuickFIX replay retains original sending time after restart

Rust now recovers SendingTime from stored QuickFIX wire frames instead of
assigning zero to every recovered record. Both QuickFIX C++ and QuickFIX/J
layouts previously caused a resent application message to name the Unix epoch
as OrigSendingTime after reopening. The correction uses the append journal's
existing parser and changes only cold recovery, not the sending path or files.

## Driven metadata and wire failures

The storage reviewer supplied four public-API reproductions and retained them
under `~/archive/libhft/reviews/2026-10-03-codex-review-storage-1003/rust-review/`.
This session independently drives the finding at 202107708, after the separate
recovery I/O correction and C++ C1b have landed. The checked-in regression uses
independently constructed FIX envelopes, standard header ordering, explicit
BodyLength and checksums, rather than requiring a private transport or peer.

Save application sequence 2 with SendingTime `20261003-12:34:56.789`, close,
reopen, log on and request sequence 2. At the baseline, recovered timestamp
metadata is zero in both layouts and the complete resend frame carries
`122=19700101-00:00:00.000`. Its stored original SendingTime is still intact.
Four tests fail: metadata recovery and full resend for each physical profile.
Two absent/invalid-timestamp control tests pass. The same result is retained
from the initial fixture, then again with canonical header ordering.

## Correction and coverage

QuickFixFileStore::recover calls `frame_time` on the accepted payload before
moving it into the in-memory index. The same helper already restores sending
time in the append journal. No new parser, format, lock, allocation, sequence
policy or ABI is introduced. Parsing adds cold startup work; no measured
latency gain is claimed.

The six tests cover second and millisecond precision across two successive
reopens in both layouts, payload preservation and recovered sequence state,
and the existing zero fallback for opaque data, absent tag 52 or an invalid
timestamp. Full-session resend tests require exactly one complete frame with
valid BodyLength and CheckSum, the original MsgType, MsgSeqNum and application
payload, PossDupFlag=Y, the original SendingTime in tag 122 and the current
SendingTime in tag 52. The session remains logged on, with its expected next
outbound sequence. These wire checks are not an external peer certification.

## Verification and evidence

Rust 1.92.0, offline, under host-cpu-slot's isolated pool on hp; shared jobs may
overlap, so these are functional checks and not quiet-host latency measurements:

| Check | Development edition | Open edition |
| --- | --- | --- |
| New regression executable, six test threads | 6 passed | 6 passed |
| Full default-feature crate suite, serial cases | 1,039 passed | 906 passed |
| Previous regular body append EIO regressions | 6 passed | 6 passed |
| Previous regular header append EIO regressions | 6 passed | 6 passed |
| Strict Clippy 1.93.1, all targets, warnings as errors | passed | passed |

No tests fail. Each full suite keeps the one existing ignored builders
doctest. The full totals comprise 1,012 library plus 27 other development
tests, and 884 library plus 22 other open tests. Both include the six inherited
store-lock cases and six FIFO recovery I/O cases. Focused results overlap the
full suites. The EIO executions assert six actual injected faults per run.
Export scrub of both changed engine files reports zero findings.

The exact patch, new test copies, old failing executable and its hash, source
pin, complete logs, scripts, compiler versions and hashes of the Rust crate
and shared fixtures are retained in
`~/archive/libhft/rust-quickfix-replay-time-20261003/`. Build outputs stay under
`~/build/codex-libhft-hp/libhft`.

The correction does not expand supported timestamp precision, change fallback
semantics for missing timestamps, update installed managed/native bundles,
verify NICs or optional venue features, or finish the complete all-flavour
review. C++ already has a distinct resend fallback that copies the original
SendingTime from the frame when timestamp metadata is absent; no corresponding
defect in another flavour is inferred from the driven Rust failure.
