# hp FAST integer boundary review

The same two integer-boundary defects were reproduced in C++, Java, .NET and
Rust. A ten-group signed value outside int64 could wrap into an ordinary value
or NULL. Separately, maximum nullable int64 and uint64 values did not encode or
decode correctly. C++, Java and Rust have fixes with passing regression coverage.
Another session landed the mandatory signed fix for all four languages in
`23ce2db4f`; .NET nullable maxima remain unfixed under its restructuring claim.
This is a functional review, not a latency measurement or completed NIC coverage.

## Reproduction and wire rules

The reproduction at `d24cf1ebaa6af1ed90b229e8ccfb7728257c7dfa` compiled the
actual C++ and Rust primitives and invoked the built Java class and .NET assembly.
All four produced the same erroneous outcomes. The byte notation below uses
`00 × 8` for eight zero-data bytes; the final `80` is the stop byte.

| Wire bytes | Mandatory result | Nullable result |
| --- | --- | --- |
| `01 00 × 8 80` | Must reject +2^63; instead returned INT64_MIN | Must return INT64_MAX; instead returned INT64_MIN |
| `7E 00 × 8 80` | Must reject -2^64; instead returned zero | Must reject; instead returned NULL |
| `02 00 × 8 80` as unsigned | Correctly refused the 65-bit value | Must return UINT64_MAX; instead refused it |

The old ten-group signed check examined only six surplus bits. The remaining bit
in the first group becomes the destination's sign bit, which must agree too.
Thus a mandatory ten-group signed integer requires a first data group of zero
or `7F`, not one or `7E`.

The nullable maxima are valid wire values, not another overflow to reject.
[FAST 1.1 sections 10.6.1 and 10.6.1.1](https://www.fixtrading.org/wp-content/uploads/download-manager-files/FAST-Specification-1-x-1.pdf)
define two's-complement signed entities and the nullable non-negative increment,
including the possibility of an extra wire bit. The ordinary fixed-width
accumulator cannot hold that shifted maximum. Both nullable encoders previously
refused their maximum input; the signed nullable decoder instead confused the
extra bit with a negative value. These were primitive-level reproductions; no
live market-data corruption is asserted.

## Changes and regression coverage

The mandatory signed decoders now check the complete first group before
accumulating ten-byte entities. That width/sign check makes the per-group signed
overflow branch redundant, so it has been removed. Nullable decoders recognize
their exact maximum representation only after the ordinary decoder refuses it;
nullable encoders write that representation after all capacity checks. The common
decode path adds no lock, allocation or extra nullable-maximum scan. C++ nullable
scalar decoders also refuse a missing output pointer instead of dereferencing it.
No timing benefit has been measured from the removed branch.

Each surface's range regression sweeps 128 first groups against zero and all-one
suffixes, with mandatory/nullable signed/unsigned decoding: 1,024 checks at a
non-zero cursor offset. Independent maximum wire vectors also check every
truncation, every short destination, surrounding output bytes and each corrupted
suffix byte. Failed reads/writes retain their existing cursor/output contracts;
C++ leaves the value untouched for NULL, whereas Java records zero with its NULL
flag. Existing short and overlong in-range entity behavior is retained.

Before the fixes, the new C++ maximum assertion failed, two Java JUnit methods
failed, and three Rust unit cases failed. After merging the upstream signed-range
regressions, C++ passed 34 primitive cases, Rust passed 19 optimized primitive
tests, and Java passed its 26-case standalone suite plus the two dedicated JUnit
methods. The required-native Java test passed too: four JUnit methods in two
classes, no failures, errors or skips. C++ also passed Clang AddressSanitizer and
UndefinedBehaviorSanitizer. All 17 C++ FAST test binaries passed.

The full release Rust library run at `68bf4cffb` passed 990 tests with venue
codecs enabled, no failures or ignored tests. Its Rust tree is exactly
`cff2f92fe63b3f748f81124f0e5914812ee051c2`, also present at the later JNI-refresh
and focused-validation pins. A redundant Rust rebuild during the JNI refresh
was deliberately stopped; its termination log is retained, not counted as a
passing run. The final publication rebase incorporated separate ASX OUCH changes
in `50ba267bd`, so the 990 count does not describe that enlarged Rust tree.
The FAST sources remained identical to those tested.

Cross-surface comparison at `68bf4cffb` agreed on 19 frame/output lines across
four languages, with fingerprint
`39bd02d6317f9db20ed69f6c88b85d09e71c88485fd1bae5b8a5652a1ca44e3d`;
both existing native-bridge parity programs passed. Dedicated boundary probes
then passed 289 checks each through actual Java JNI and .NET P/Invoke calls.
Both use the corrected C++ primitive; this does not fix the separate .NET
managed implementation. The bridge shared-object SHA-256 is
`322dc9b269feba105efd6dcc7507feea6c84c24c585ab944dfdbb9643038371a`.
All five changed engine files passed the public-export scan with zero findings.

The source fix was published as `59e0200da`. Final focused validation at
`fd91b8697` repeated the primitive, Java required-native, sanitizer, 17-binary
and native-boundary checks. Publication rebases preserved those exact FAST and
JNI sources. JNI was rebuilt at `4376a39a4` for upstream native-method additions;
this is functional ABI validation, not a refreshed full managed suite, installed
SDK bundle, NIC measurement or tuned latency result.

## Remaining work and retained evidence

This session has not edited .NET production/test files. Their release request, alongside
the existing TLS-read ownership request, is in `docs/WIP_AGENT_CLAIMS.md`.
Ordinary-value bridge parity does not establish the still-missing .NET boundary
fix. Full boundary parity must be verified after its regression and fix land.

Evidence is under `~/archive/libhft/fast-range-review-20261002/`: the four-surface
reproduction and source harness, failing-before log and Java XML, and subsequent
validation logs, including `range-post-rebase-68bf4cffb.log`,
`range-final-focused-fd91b8697.log`, `native-boundaries-68bf4cffb.log` and the
native probe sources. Builds and compiler scratch stay under
`~/build/codex-libhft-hp/libhft`. All foreground builds/tests use an `isol` lease
and may overlap shared-core work.

The earlier TLS-managed bundle remains archived at its verified source pin. Its
staging manifest was withdrawn before these changes; the home staging helper is
not approved to install until the refreshed bundle has another verified manifest.
