# SBE codec and mapped-ring review — 2026-10-14

This pass fixes six reproduced defect classes in the SBE codecs and transports.
It does not qualify the whole FIX engine. Parallel source reviews used one session
worktree; builds and tests ran sequentially on BEELINK2, capped at 16 jobs.

## Changes and reproductions

- **Declared encoder bounds (Java, .NET, Rust).** A physically large buffer with a
  short declared output window still received root-field writes, including writes
  through nested composite encoders. An incomplete root now disables those writes;
  normal encodes at nonzero offsets retain their adjacent sentinel bytes. C++
  already refused the incomplete root.
- **Retained group cursors (C++, Java).** Reading another group, variable data,
  `encodedLength`, or body-truncation status rewound an active iterator. A two-row
  group yielded its first row again instead of its second. Layout validation now
  scans separate cursors and resets only the explicitly requested group. Rewrapping
  and genuinely truncated predecessors still invalidate borrowed cursors. The
  backing-buffer mutation tests continue to require fresh validation.
- **Body evolution (all four generated languages).** The schema model discarded
  `sinceVersion` on groups and variable data. New decoders therefore reported valid
  older messages as truncated and could expose trailing bytes as newer fields.
  The model and emitters now preserve version gates. Tests cover versions 0–3,
  absence before introduction, required bytes afterward, and latest-version encoding.
  Negative and non-integer body versions are rejected by the parser and capability audit.
- **Zero-width groups (Rust).** A nonempty group with block length zero was rejected
  by its cursor but accepted by `encoded_length` and the walk to later body fields.
  Both paths now reject it; zero-count controls remain valid.
- **Closed mapped rings (Java, .NET).** Java continued to publish through a closed
  ring, including a stale consumer after replacement. .NET's counter properties
  dereferenced the cleared mapping pointer and threw `NullReferenceException`.
  Closed operations now report a closed ring; repeated close/dispose is harmless.
- **Overlapping framing buffers (Java).** Prefix-first, forward copying corrupted
  in-place payloads and overlapping views. Absolute bulk copy precedes the prefix,
  preserving heap/direct storage, read-only source views, both copy directions, and
  buffer positions. It also removes the per-byte Java copy loop.

Generator changes are the source of all regenerated output. The new body-version
fixture is checked across four emitters and included in the normal runtime fixtures.
No wire layout or public function signature changes.

## Evidence pins

- Baseline regression source: `12a18ff9a0bd6495c13a0af1fe6535bfedacb271`.
- Qualified source: `c0c94cb190e9388de1f0d10f72a070633caca3a6`, rebased onto
  `a743f1d734ee4649299038be29e5d95f52c315f7` before qualification.
- Qualified `engine/` tree: `c304d0194267d843a3b7783d53d905b3a208b107`.
- Local archive: `/home/yann/archive/libhft/reviews/2026-10-14-codex-review-codecs-1014`.
  It contains baseline/qualified/published bundles, changed-source snapshots,
  scripts, logs, Java XML reports, timing inputs, JSON summaries, and SHA-256 hashes.
  Logs stay outside Git to avoid another large evidence tree in every checkout.

Before fixes, both C++ programs failed (8 cursor assertions and 7 evolution
assertions); .NET had 12 failures and 4 passes; Rust fixtures had 5 failures and
21 passes; Rust sample-codec tests had 2 failures and 3 passes; Java had 8 failures,
1 bounds exception, and 24 passes. There were no skips. The baseline .NET native
library guard passed.

## Qualification

| Suite | Development | Open |
|---|---:|---:|
| C++ SBE/schema/compiler programs, GCC 15 C++11 | 11 | 11 |
| .NET Release SBE tests and native guard | 61 | 58 |
| Rust SBE library tests | 30 | 30 |

The Rust compiler-fixture crate passed 26 tests. The standalone Java 21 SBE module
passed 48 tests, including its transport and allocation tests; its 200,000-decode
loop allocated zero bytes. This module has no JNI dependency. Both .NET native
libraries were built in their standard development/open locations and their guards
passed. All pass/skip lists were inspected: zero failures, skips, or ignored tests.

The generator self-test and all 49 generated-output comparisons passed. The export
scan reported zero findings in 64 changed code/test files. Seven additional Java
compiler fixture programs also passed, separately from the Maven module. All 17
validation stages passed; see `qualification-summary.json` and
`java-compiler-fixtures.log` in the archive.

## Focused latency measurement

C++ `encodedLength()` now walks each group/data prefix once instead of restarting
its body walk for every trailing data field. A paired benchmark used a valid
37-byte body with two groups and three variable-data fields, old/new headers in
one executable, noinline wrappers with compiler memory barriers, and checked sums.

On BEELINK2's Ryzen 7 8745HS, GCC 15.2.0 `-O3 -march=native`, pinned to CPU 2:

- Seven alternating pairs, 10 million calls per variant per pair.
- Median before: **13.278 ns/call**; after: **4.090 ns/call**.
- Median paired before/after ratio: **3.219×**.

This measures repeated length validation of that warm fixture, excluding wrapping,
encoding, transport, and session processing. It is not an end-to-end engine latency
claim. No measured Java speedup is claimed. Raw samples, source/headers, build flags,
CPU details, and checksum controls are retained in the archive.

## Final integration and CORE registration

The publication fetch added the classic FIX field-survey optimization `223474131`
and the independently qualified FIXP finalization fixes through `3f54876b1`.
The 63 changed SBE source/test files other than the Makefile, and the entire
`sbe/` subtree, remained byte-identical to the qualified source above. The
Makefile received one additional CORE header registration described below.

The development and open Rust SBE suites were rebuilt and rerun at
`fdcdacf213f59830dceb7eb3aae83f0f106fb587`: 30 passes each, zero failures or ignored tests.
The other language results above retain their original qualification pin;
no whole-engine qualification is implied.

An upstream coordination note identified a registration omission from the prior
occupancy fix `03ac49e2d`: `libhft/StoreOccupancy.h` was tagged CORE but absent from
`CORE_TIER_HEADERS`. The tag check reproduced that failure. Adding its entry
beside `Buffer.h` made all 91 CORE tags match; the CORE compile/runtime gate also
passed. No runtime source changed for this correction. The request and temporary
claim are released now that their specified checks pass.

These three additional integration stages and the exact combined source are
retained in `integration.bundle`, `integration-source.json`, and the qualification
summary. A later fetch through `376d5ce9b` changed benchmark orchestration and
C++ example documentation, with no further runtime or generator changes.
`baseline-core-header.log` and `fixed-core-header.log` retain the tag check.
