# Rust simulator BodyLength mutation at the unsigned limit

## Reproduced baseline

At `db2166c73`, the unchanged `sim_faults::bad_body_length` parses a `u64`
then increments it with unchecked addition. Maximum-length input unwinds with
overflow checks enabled and becomes `9=0` with checks disabled. Reapplying the
fault after incrementing `u64::MAX - 1` has the same problem.

An isolated Rust test harness compiles the exact retained simulator module and
the byte-identical candidate integration fixture. Both debug (`opt-level=0`,
`overflow-checks=on`) and release (`opt-level=3`, `overflow-checks=off`) exit 101:
five new controls and the two existing simulator tests pass, while three new
boundary regressions fail. This is a module reproduction, not a complete
unchanged-engine suite. The source/table hashes and actual diagnostics are kept.

## Fix and coverage

A checked increment returns the original input when the off-by-one mutation
cannot be represented. That follows the transform's existing fallback for an
unparseable length. There is no saturation, wrap or synthesized replacement.
All representable values retain the existing mutation and the remainder of the
frame, including the stale checksum, stays byte-identical. The public signature,
dependencies and FIX message path do not change.

Eight public integration cases cover the maximum, zero-padded maximums,
composition up to the limit, decimal-width transitions, ordinary zero-padding,
binary trailing bytes, invalid/out-of-range/invalid-UTF-8 values and absent or
unterminated length fields. The existing shared CSV continues to pin normal
fault bytes across the four bindings. The unsigned-limit fallback is a Rust
robustness fix; this record does not claim that every binding's malformed-input
fallback is identical. Fixtures are in memory and create no persistent data.

## Verification

| Gate | Result |
|---|---|
| Unchanged module, debug and release | Each: 7 pass, 3 fail, 0 ignored |
| Fixed module, debug and release | Each: 10 pass, 0 fail, 0 ignored |
| New integration fixture, default and open | Each: 8 pass, 0 fail, 0 ignored |
| Complete default Rust stage | 1,964 pass, 0 fail, 1 existing ignored builders doctest |
| Complete open Rust stage | 1,777 pass, 0 fail, the same 1 ignored doctest |
| Strict all-target Clippy, -D warnings | Passed in both editions |

Final gates use candidate `be58a5c9b`, with all 360 tracked Rust and 533 shared /
reference / gate path-keyset and hash pairs checked. Each selected conformance
stage reports 1 ran, 0 failed, 0 skipped; PARTIAL means the other monorepo stages
were not selected. This is not an optional-feature, full-monorepo or live venue
certification result. Publication integrates Java Maven artifact discovery and
unrelated resolver self-test metadata: all Rust inputs and 531 shared inputs
stay byte-identical; the two shared-file diffs leave Rust stage recipes and
Cargo/build-root functions unchanged. The full proof and diffs are retained.

The unchanged baseline runs on HP. HP's candidate verifier initially queues
behind a Java benchmark campaign, so only our verifier is stopped (exit 143,
retained). Scan completes the focused cases and both module profiles; its first
full -j1 attempt yields to a Java suite and is stopped while queued. HP's full
-j1 retry yields four times to other sessions' Java/.NET work. Only our verifier
is stopped again; final complete suites and Clippy finish on Scan at -j8. The
retained capture wrapper explicitly appends -j8 to the otherwise unchanged Rust
stage command and records that actual argv. One test thread and one guarded
build/suite per host remain in effect; -j8 is below the -j16 cap and Scan has
over 100 GiB available. Interrupted attempts are not reported as passes.

Each compiler/suite uses the build-slot guard with an 8 GiB memory floor. Cargo
is offline, with debug symbols disabled. Rust/Cargo 1.92.0 runs tests. Strict
Clippy uses the already retained 1.93.1 sysroot on Scan directly; no global
toolchain configuration is changed and no compiler copy or install is needed.
No heavy job runs on BEELINK2 for this slice.

Pins, commands, exact module/fixture snapshots, baseline failures, interrupted
attempts, complete stage reports/stdout/stderr, Clippy logs, the separate
ownership diagnostic and the named candidate/publication bundle are archived
under `~/archive/libhft/rust-sim-body-length-20261011` with SHA256SUMS. Both remote
hosts keep their packets and the complete local archive gathers them together.

A whole-module rustfmt check exposes one pre-existing shared-table include
formatting difference. The complete changed function and entire new test match
rustfmt; the unrelated line is preserved. Public-export and API inventory /
generated coverage checks pass. API/session/subsystem scores stay 82 supported /
11 n/a, 27/27 yes and 43 yes / 2 partial / 1 n/a. Live production/venue and
FIXP schema certification evidence remains outstanding.

## Separate acceptor ownership reproduction

A retained three-case public-API diagnostic on Scan uses candidate `be58a5c9b`'s
unchanged acceptor/session source. The early-error control closes the peer and
passes. A factory that explicitly closes its session, opens `/dev/null` in the
reused descriptor slot, and returns an error causes the acceptor to close that
unrelated file: metadata fails with EBADF. A factory panic before session
construction leaves the accepted socket open when the caller catches the unwind:
the peer read times out instead of observing EOF. The diagnostic exits 101 with
one pass and two failures, after cleaning up its own handles. It consumes the
invalidated File owner before asserting so the demonstration does not trigger an
unrelated I/O-safety abort. No external descriptor is forcibly replaced.

Merely dropping a raw-kernel session does not close it: `Session` currently has
no `Drop` implementation. This proof concerns an explicit close and an unwind;
it does not demonstrate a standard configuration factory double-close. Removing
all error-path cleanup would leak the early-error control. No transport ownership
fix or factory API compatibility decision is claimed in this slice. The proposed
owning variant would require exhaustive external `Io` matches to handle one
extra case; that preference was requested separately. An inode probe followed by
a raw close is not a reliable ownership replacement.
