# Leaf references, connectivity and portal counters Reproduce with `python3 scripts/analyze_bsp_references.py`; validate with `python3 scripts/test_bsp_references.py`. Evidence: [bsp-references.json](bsp-references.json), with eight hash-verified native graphs per Linux ELF64 engine. This extends [BSP loading](BSP_LOADING.md) and [leaf metadata](LEAF_METADATA.md). These are bounded synthetic instructions with supplied allocation returns, arrays, pointers and area labels. Original processes, allocations, errors, geometry callees and flood callees never execute. Portal PUSH instructions are explicitly replaced with NOPs at the same addresses; execution stops before POP/return, error calls or the first flood call. Connectivity starts after frame setup and stops before stack restoration. The retained flooding graphs are static evidence, not executed compositions. ## REF-001 — Reference arrays and leaf consumers (RE-325) Forty-eight paired reference-loader probes cover counts 0–9, 16 and 17, including every copy remainder and eight-word loop paths. CMod_LoadLeafBrushes requests `4 * (count + 1)` bytes; CMod_LoadLeafSurfaces requests `4 * count`. Both publish supplied allocation pointers and counts, preserve all original words in order, and omit payload copies for zero count. Repeated IDs and -1 words are copied unchanged; these deliberately supplied IDs do not establish legal map values. The spare brush word is untouched under the supplied sentinel initialization. Alignment/error paths are retained but not evaluated. No direct calls to either standalone helper appear in the retained CM_LoadMap graph. Actual inline-loading equivalence and descriptor routing for these arrays remain open; standalone helper behavior is not evidence of complete original map loading. The leaf consumer slices connect the prior disk/native projection to index arithmetic: | Native leaf offsets | Observed consumer relationship | | --- | --- | | +8 first, +12 count | brush-reference array; signed referenced ID selects `brush_base + 56 * ID` | | +16 first, +20 count | surface-reference array; signed referenced ID selects an eight-byte pointer-table entry | Forty-eight paired address slices vary first index, ordinal and supplied IDs -1/0/7. Brush slices stop before the record stamp comparison. Surface slices stop before the selected pointer's NULL test. Both read `reference[first + ordinal]`; no local index bounds checks occur inside these selected arithmetic slices. Negative-ID fixtures use explicitly supplied memory and are not valid-map or safety demonstrations. The full retained consumer graphs show brush iteration before curve/surface iteration, reference-count gates, stamp checks, content tests and geometry calls. Those bodies/order/state effects are not composed in this report. The 56-byte brush record stride is native ELF64 layout, not a brush disk-record size or Bevy asset layout. ## REF-002 — Area connectivity predicate (RE-326) Four hundred fifty paired probes cover supplied area counts 0/1/3, both indices -1 through 3, and cm_noAreas raw words 0/1/7. The observed priority is: 1. Nonzero cm_noAreas value returns true before index validation. 2. Either negative area returns false, before either upper bound is checked. 3. A nonnegative area >= area count requests Com_Error with `area >= cm.numAreas`. 4. Valid areas compare the first word of their eight-byte native records for equality. Supplied labels `[1,1,2]` establish connected versus disconnected outcomes. The record's second word is not used by this predicate. The base/count slots match the preceding leaf loader's area allocation/count state. This is label comparison, not a portal walk, line-of-sight test or independently verified connectivity generation. Label initialization/refresh must be established before applying this rule to real snapshots. ## REF-003 — Portal mutation and reflood boundary (RE-327) Eight hundred paired probes use three areas, indices -1 through 3, open words 0/1/7/-1 and initial selected counter values -1/0/1/2. The matrix contains four-byte counters indexed `area1 * count + area2`; the reverse entry is addressed separately. - Either negative index returns without mutation, even if the other index exceeds the upper bound. - Nonnegative out-of-range indices request `CM_ChangeAreaPortalState: bad area number` before mutation. - Every tested nonzero open word increments both directed entries; zero decrements both. - Self-pairs write the same cell twice. Starting at one, open produces three and close produces -1. - Closing checks the reversed entry after both decrements. Negative results request `CM_AdjustAreaPortalState: negative reference count`; both writes have already occurred at the stopped error boundary. - Successful updates increment the flood epoch and begin a label rebuild. With epoch 40 and all area stamp words explicitly seeded to zero, the first request is CM_FloodArea_r(area 0, label 1) at epoch 41. The tests compare the whole matrix, write offsets/order, guard priority, stopped error text, epoch and requested arguments. Deliberately negative initial counters characterize local paths and do not establish reachable runtime states. Error handling itself is not executed; persistence after Com_Error is not claimed. The retained CM_FloodArea_r graph uses record +0 for the label and +4 for the epoch stamp; positive matrix entries select further visits. CM_FloodAreaConnections similarly increments the epoch and scans area indices in ascending order. Complete unrolled/recursive flooding, its revisit-label consistency errors, asymmetric matrices, stale/prestamped records, count/epoch wraparound and full update-to-query composition remain open. ## Validation and next work Eight independent tests cover copy/allocation/canaries, signed consumer addressing, connectivity guard priority, complete sampled matrix mutations, self-pairs/nonzero open flags, prior-loader slot correspondence, paired outputs/trace lengths and low-byte register preservation. Small slices retain instruction addresses; larger collections retain trace lengths and hashes. The report does not copy any original asset into assets/. RE-328: prove inline/reference-loading equivalence and valid reference ranges across all BSP variants; recover complete brush/surface layouts, stamps and geometry; compose full flood generation/revisit/epoch behavior and update-to-connectivity/area-bit/snapshot consumers; connect server/QVM portal writers and lifetime/reset/serialization; obtain original-runtime and other-platform fixtures. Rust/Bevy/Solari collision and rendering implementation remain open. Follow-up: [area flooding and bit output](AREA_FLOODING.md) adds bounded generated-label/portal-update compositions and visibility packing. Complete flood/error/lifecycle/real-map/snapshot conformance remains open under RE-328/RE-332.