Reserve bounded JSON arrays once

Merged
VA
3d ago
+58-16

Flat arrays in the bounded JSON decoder reserved one additional slot per element, repeatedly reallocating and copying the existing values. Count top-level elements before construction and reserve the array once, after its allocation operation is admitted. Empty arrays allocate no element storage. Share the existing nesting/string/escape-aware container scan with objects.

The shrinking allocation-count property covers flat integer arrays of 0–511 elements: one output buffer plus one allocation for nonempty array storage, with charges covering measured allocations and no retained heap after destruction. Its negative control runs the former per-element reservation loop and detects its repeated allocations. Existing exhausted-prefix properties exercise typed denial and custody cleanup; add nested/quoted-delimiter coverage and flat/nested array seeds to the existing production-API fuzz target.

Validation

Local Windows debug, canonical native feature closure, all cargo commands through Q:/lanes/lb.ps1:

  • cargo check -p acyclic-harness --lib --tests: passed; Cargo 161 s, process 372.43 s including a 210 s slot wait.
  • Focused executor::json:: suite: 16 passed in 1.24 s (1.268 s process wall), run directly from the built test binary.
  • Test build: 426.70 s on the successful attempt. The first attempt ended in rustc STATUS_ACCESS_VIOLATION with no Rust source error; one identical retry succeeded.
  • Formatting, LF/source-size checks, git diff --check, and SSH commit-signature verification pass.

Exact closure: --no-default-features --features filesystem-local,native-execution,hooks,mcp-http,mcp-stdio,mcp-oauth,objects,machines,grpc,terminal,tui,test-support,model-checking. No workspace build, alternate profile, or remote request.

Decisions

Keep the existing ownership admission and conservative object-node bound. Reuse one container scan rather than add a separate parser or staging allocation. This is the small P2 follow-up to merged #608; extraction remains subject to the protected-wave prerequisites in Q:/lanes/harness-split-plan.md.


Summary by cubic

Bounded JSON arrays now reserve their backing storage exactly once instead of growing one slot per element, which repeatedly reallocated and copied existing values. The decoder counts top-level elements before construction and charges a single allocation for nonempty arrays; empty arrays allocate no element storage, and nesting, string, and escape-aware scanning is shared with objects.

Adds a property test asserting flat arrays of 0–511 integers need only the output buffer plus one array allocation, and seeds the fuzz corpus and exhausted-prefix tests with flat and nested array cases.