# Rust FAST runtime dispatch: dictionary lifetime after failure

## Reproduction and source

The verified runtime candidate is `997e5c140b3623a11f87d1ec247a6e443e34ccbe`.
The baseline is `6bd2d5c99`, with only the first seven public-API regressions
added. Six failed, one passed. In particular, an unknown template followed by
an explicit Trade with its shared copy field omitted reused the previous Quote
value. A malformed header followed by a carried Quote did the same. A missing
initial template ID did not fence a later explicit message. Body/output failure
already poisoned the selected dictionary but retained the old template ID.

Evidence is retained in `~/archive/libhft/rust-fast-dispatch-20261003`:
baseline source and log, runtime patch and source bundle, all gate logs, matching
Rust source hashes, a source review, and an optimized standalone harness.
The bundle requires `6bd2d5c99`; `publication.json` records the final main pins
and `SHA256SUMS` verifies the archive.

## Change and regression coverage

The shared FAST compiler's Rust dispatcher emitter now generates `invalidate`
and `is_valid` on each runtime codec. Validity checks one scalar flag per message,
independent of the number of dictionary owners. Invalidating clears carried template IDs
and invalidates every dictionary owned by the codec. Header failure, missing
initial template ID, unknown template and body failure poison the entire
runtime until an explicit `reset`. A poisoned runtime consumes no further input
and writes no further output. An encoding failure after encoding starts also
invalidates the entire runtime; template-carry admission refusals happen before
mutation and remain retryable.

The runtime consumes complete messages. Callers buffer partial transport input
before dispatching it: a failed decode is not a signal to append more bytes and
reuse the same dictionary. Low-level stop-bit streaming primitives and the
header/body codecs retain their existing APIs.

Both checked-in dispatchers, `fast_shared` and `fast_group`, were regenerated.
An AST comparison confirms `_rust_emit_dispatch` is the compiler's only changed
function. The generated field/header bodies preceding the runtime message enum are
byte-identical to their predecessors, so field operators and successful wire
layouts stay the same.

Twelve external public-API tests cover malformed/truncated and oversized-ID
headers, unknown templates, missing initial carry, body truncation, output
refusal, nonzero cursors, explicit sequence-gap invalidation, decode-to-encode
poisoning, reset recovery and retryable carry refusal. Separate group dictionaries
prove that failure in one template also fences the other. A borrowed ASCII group
message remains readable while the runtime decodes the next template after reset.

## Verification

Own verification jobs ran sequentially on HP, offline at `-j1` with
`--test-threads=1`, and with
`LIBHFT_BUILD_ROOT=/home/yann/build/codex-rust-ibv/libhft`. No heavy job was added
on BEELINK2. Full Cargo tests omit debug symbols (`CARGO_PROFILE_TEST_DEBUG=0`)
to reduce build memory; optimization and debug-assertion settings stay at their
default test values.

The initial guard yielded to other compiler and suite processes. Long-running
verification then occupied HP while leaving 12–13 GiB available. The final HP
profile bounds other observed runtime processes to 4 GiB aggregate RSS, stops its
own stage below 8 GiB available memory, and pauses for other compiler processes.
This profile is disabled on WSL; the BEELINK2 one-heavy-job rule stays strict.
Rust stages remain sequential. Interrupted attempts are retained separately and
are not green gates.
All 335 tracked Rust file hashes match the publishing worktree at the candidate.

| Gate | Result |
|---|---|
| Baseline public-API regression | 6 failed, 1 passed at `6bd2d5c99`, as expected |
| New public-API regressions, both editions | 12 passed in each |
| Full default suite, Rust/Cargo 1.92.0 | 1,039 passed, 0 failed, 1 existing ignored builders doctest |
| Full open suite, Rust/Cargo 1.92.0 | 906 passed, 0 failed, the same 1 ignored doctest |
| Strict Clippy 1.93.1, all targets, both editions | Passed with `-D warnings` |
| Optimized actual FAST modules plus new regressions, Rust 1.93.1 | 87 passed, 0 failed, 0 ignored; debug assertions disabled |
| Shared compiler tests, including every checked-in Rust codec | 147 passed |
| Rustfmt on the new integration file | Passed |
| Public-export scrub on four changed engine files | 0 findings |

After rebasing onto main, the four owned engine files are unchanged from the
fully tested candidate. The rebase adds the separately verified QuickFIX recovery
ordering/timestamp repair and its two integration files. At `afde29e53607600430f67e339752d8809bd1bc79`, the
integrated checks pass all 24 cases: 12 FAST, 6 recovery I/O and 6 recovered
replay timestamp cases. The 147 compiler tests pass again on this integrated tree.
The archive retains both the candidate and integration source reviews and logs.

This is a runtime correctness repair. Coverage scores stay unchanged; genuine
production endpoint evidence and venue/FIXP certification remain unfinished.
