S1 (HIGH, crash in play): Lane's own shadow prefilter (a re-derivation of
Silhouette's centre/h) and the independent SlabAlongB 2-axis intersection test
could disagree at a float edge, rejecting a cell the shadow sum had already
counted metal for -- an empty lane after a hit passed its roll (R3 violation),
reproducible through Zone.Update. Both are replaced by one shared admission
test (Extent(c, axis), the exact support of a unit square along an axis) that
Silhouette and Lane now both call; SlabAlongB is deleted, and its geometry is
kept only as a non-rejecting AlongBearing() that computes entry/exit for
already-admitted cells (the doc's own equivalence proof -- "s in the shadow" is
exactly "the line intersects" -- makes rejection there unreachable by
construction, not merely unlikely).
S3 (allocation): Interval and LaneCell now implement IComparable<T> (same
order as the deleted IntervalByLoComparer/LaneCellComparer) so Silhouette's and
Lane's sorts use Array.Sort(T[], int, int), which resolves T's own comparison
at JIT time, instead of the (T[], int, int, IComparer<T>) overload, which
wraps even a cached singleton comparer in a fresh delegate per call.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>