# Slice H-b — exact bounded point-light selection ## Result `LightManager.BuildPointLightSnapshot` no longer sorts every qualifying light when more than 128 lights are eligible. It keeps the best 128 in a retained worst-first heap, sorts only those 128 for submission, and performs no allocation after warm-up. The optimization preserves the accepted pre-slice output exactly: - dynamic lights still precede static lights; - each pool is still ordered by squared player distance; - the visible-cell, lit-state, and directional-light filters are unchanged; - in-budget snapshots remain in registration order; - equal-rank overflow frames which could expose .NET's unstable sort retain the previous complete-sort path and exact object-reference order. The retail oracle and readable pseudocode are in `2026-07-25-slice-h-b-light-top-k-pseudocode.md`. Retail's own selector is a bounded ordered insertion into separate static and dynamic pools. This slice ports the bounded-work principle without claiming to close AP-85's larger pool/cap/lifecycle divergence. ## Evidence Focused conformance covers: - exact randomized differential comparison against the previous full-sort oracle; - equal-distance overflow and cap-boundary behavior; - lit, directional, dynamic, static, and visible-cell filtering; - a deterministic 463-light Town Network-scale candidate set; - zero warmed allocations on both bounded and equal-rank fallback routes. A Release diagnostic microbenchmark ran 100,000 snapshot builds with 463 eligible uniquely ranked lights: | Route | Elapsed | Managed allocation | |---|---:|---:| | previous complete sort | 1,377.578 ms | 0 bytes | | retained bounded selector | 976.993 ms | 0 bytes | That sample is a 1.410x throughput improvement, or about 29.1% less CPU time inside selection. It is a narrow microbenchmark rather than a whole-frame FPS claim; its purpose is to prove that the replacement removes work rather than merely moving it. ## Safety boundary No shader, light parameters, candidate membership, draw order, or production scene ownership changed. AP-85 remains open because retail's exact 7-dynamic/40-static pools and DBObj-resident cell lifecycle are outside this performance-only slice. G4's independent visual rollback remains: ```text git revert ef1d263337997bb030eadb7b8e71d73dc659907a ```