# Rust runtime dictionary expansion depth — 2026-10-17

## Behavior and reference

The runtime XML parser already capped physical element nesting, but sibling
component definitions could form a much deeper acyclic reference chain.
Both `Builder::visit` and the separate group-delimiter component search recursed
without a depth bound. The baseline aborts on a 4,096-component chain despite
its shallow XML structure.

The combined group/component walk and delimiter search now refuse excessive
depth with `group/component nesting too deep`, propagated before validator
tables are published. The 64-call limit matches C++ `RuntimeDictionary`'s
`kMaxNestDepth` and `VisitMessageChildren` policy. Group nesting plus the active
component path measures the true walk depth without changing required scopes.
Cycle skipping, required-component AND rules, stable ordering and ordinary
XML depth handling retain their previous behavior. The new limit concerns
depth; it does not introduce a total expansion-width or table-allocation bound.

Changed engine files: `engine/rust/src/dict_xml.rs` and
`engine/rust/tests/dictionary_expansion_depth.rs`.

## Reproduction and qualification

- Baseline: `13929e3b99709ea5f4b567966f298ccac0b3c862`. Only the new fixture is added to unchanged production.
- Complete Rust stages, release fixtures and initial lint: `b39df801880de628e74c069a401a40afa8a1ce3e`.
- Combined-source follow-up: `3dbee526235d23b4b8d2cf8671a97ed20b60cfb9`.

The identical nine-case fixture covers component-only, delimiter and mixed
component/group boundaries, two 4,096-component inputs and a cyclic control.
Each depth probe runs in a child process, preserving all parent results when
an unchecked baseline exhausts its stack. Qualification disables core dumps.
Fixture SHA-256: `c342f18cf0492896f225ce48efac46bd5d34586b4093d1df2328c72171b0cce5`.

| Selection | Development | Open |
| --- | ---: | ---: |
| Unchanged-production baseline | 4 passed / 5 failed | 4 passed / 5 failed |
| Actual complete Rust test stage | 2,801 passed | 2,587 passed |
| Optimized nine-case fixture | 9 passed | 9 passed |
| Strict all-target Clippy at qualified pin | exit 0 | exit 0 |

Each baseline returns Cargo 101, with two child stack-overflow aborts and three
cleanly observed missing-refusal failures. Fixed runs have zero failed or ignored
tests; each full Rust stage includes 71 test programs. Both selected stages ran
once with no stage skipped and actual Cargo exit 0. The conformance wrapper
returns 2/PARTIAL because one stage was selected, not because a test failed;
this record does not claim a complete repository conformance run.
Warnings-denied Rustdoc also passes at the qualified pin. Rust 1.92.0 on Scan
runs the runtime checks; Rust 1.93.1 on BEELINK2 runs Clippy and Rustdoc.

### Integration with newer upstream changes

The only Rust input differences after rebase are `src/ibv.rs` and
`src/transcript.rs`, from `c0ded394f5cdd4e2387fc42dfd6550caf854845e`.
Their fragment-refusal and amortized consumed-prefix changes were reviewed;
[their owner's qualification](RECORD_2026-10-17_stream-input-failure-review.md)
retains their own baseline and whole-library unit runs. The only shared-input
change is `tools/run-conformance`'s Java provider test selection; both Rust
stage definitions are unchanged.

Fresh combined checks pass **35 development / 35 open** tests: nine new depth
regressions, six existing XML dictionary tests, nine transcript tests and eleven
ibverbs parser tests in each edition. The XML selection includes exact compiled-table
equality for all seven standard dictionaries and runtime SP1/SP2 loading. All eight
commands return 0 with zero failed/ignored tests. The additional full Clippy sweep
was cancelled while queued, before any compiler started; the strict Clippy results
above remain explicitly attached to the qualified pin.

All 402 Rust / 638 shared inputs match before and after each recorded run.
The complete-stage counts above belong to the qualified snapshot; combined
checks are reported separately. No benchmark or live NIC result is claimed.

## Resources, retained artifacts and status

Jobs use serial Cargo builds and one test thread, out-of-tree outputs and CPU
leases. BEELINK2 enforces one heavy job with 24/16 GiB start/stop available-RAM
thresholds. Scan uses 64/32 GiB thresholds and may overlap a disjoint isolated
CPU job under the host-slot policy. The supervisor preserves lease descriptors
and forwards outer signals to owned process groups. No heavy job runs on HP
for this slice.

The first open-edition Clippy attempt stopped with guard exit 75 after a foreign
C++ compiler appeared; development Clippy had already passed. The finishing
guard stopped and retried one further compiler attempt within the same lease;
its output retains that resource stop and the successful final retry. Rustdoc
then passed. Only completed compiler runs are counted as successful checks.

Raw commands, outputs, input manifests, controller sources and a Git bundle stay
outside Git at `~/archive/libhft/rust-dictionary-depth-20261017/`, verified on
BEELINK2, Scan and HP before this slice's scratch is removed.

Inventory/coverage, changed-file export scanning, fixture formatting,
206 documentation build facts and 21 document link checks pass. Static parity
scores remain 82/82 applicable APIs, 27/27 protocol rows, 43 complete, two
partial and one not-applicable subsystem. Live venue/FIXP certification is
external; configured acceptor startup and ordered early admin delivery remain
with their claimed owners.
