ADR-0029: prepare immutable read slots before enumeration¶
Status: accepted. All 644 provider units, 213 live integration and 61 selected EF cases pass. Matched untraced measurements reduce no-tracking allocation by 60.93%; the report (maintainer-local record) retains observations, confidence intervals, provenance and limitations.
The retained allocation profiles identify repeated driver-map copies, projection validation/hash sets/arrays and column/alias construction as the largest provider-specific no-tracking costs. A fresh baseline built from b4db72f reproduces approximately 324 MiB per 100,000-row read across three independent processes; the original benchmark workload and per-row assertions are unchanged.
Prepare a GraphRowReader from each finalized binding/projection. It owns an immutable array of aliases, EF indexes, property converters and key-validation flags. Neo4jQueryExpression prepares its reader when the query shape is built; aggregate shapes retain their existing separate path. The binding prepares a full reader once, also reused by Include. Driver IRecord.Values is consumed as a read-only map directly, without copying its dictionary or enumerating it to decode a row.
Preparation snapshots and validates projections, including hidden relationship endpoint/identity slots. Execution still checks physical cardinality and principal-label diagnostics before conversion or EF shaping, then applies the same nonempty identified-ID, required-value and canonical-key checks. Every row receives a fresh EF value buffer; no entity/state/buffer pooling or alternative state manager is introduced. Readers hold immutable finalized-model metadata and query slots, not result rows or context instances, and have no mutable per-enumeration state or process-wide cache.
The tests retain malformed-row, converter, tracking/fix-up and generated-Cypher coverage. New regressions explicitly mutate the projection source after preparation, supply a map that forbids enumeration, reuse one reader concurrently across independent rows and retain previous buffers. Optimization is accepted only after live regression and matched untraced allocation measurements, with process-level 95% intervals and explicit limits. Optional ActivitySource recording is disabled in these baseline measurements; tracing overhead is not measured by FS-11.