acdream/docs/research/2026-07-25-slice-i4-flat-bsp-differential.md
Erik f7ff9f4eea feat(physics): add differential flat BSP traversal
Port every current containment, overlap, walkable, and six-path moving-collision query to immutable integer-indexed assets behind a graph-authoritative referee. Exact synthetic, installed-DAT, complete-resolver, and zero-allocation gates prove bit-identical behavior before connected dual publication.

Co-authored-by: OpenAI Codex <codex@openai.com>
2026-07-25 15:47:58 +02:00

87 lines
3.7 KiB
Markdown

# Slice I4 - differential flat BSP traversal
**Date:** 2026-07-25
**Scope:** Modern Runtime Slice I4 only
**Behavioral boundary:** the new integer-indexed traversal is a shadow
implementation. The parsed-DAT graph remains production-authoritative until
the Slice I5 connected shadow gate and Slice I6 cutover.
## Result
`FlatBspQuery` now ports every collision entry point used by the current
runtime over immutable, integer-indexed nodes and polygon ranges:
- point-in-cell;
- sphere/cell overlap;
- static sphere/polygon overlap;
- swept sphere/polygon time-of-impact;
- walkable polygon selection;
- solid and solid-polygon traversal;
- the complete six-path moving-collision dispatcher.
The port preserves retail's traversal order, strict comparisons, early
returns, and mutable query state. The positive child remains first where
retail visits it first; the negative child observes every valid-sphere,
contact, path, slide, and candidate mutation made by the positive child.
Only `BSPQuery.PolygonHitsSpherePrecise`, which is independent of graph
storage, is shared with the existing graph oracle.
`CollisionTraversal` is the narrow temporary referee seam. Production starts
in `Graph` mode. Tests can run a cloned complete resolver in `Flat` mode, and
a missing flat asset fails explicitly instead of falling back to the graph.
Slice I6 removes this representation switch after connected acceptance.
## Retail oracle
The implementation follows the consolidated pseudocode and boundary table in
[`2026-07-25-slice-i-collision-layout-oracle.md`](2026-07-25-slice-i-collision-layout-oracle.md),
including:
- `BSPTREE::find_collisions` at `0x0053A440`;
- `BSPNODE::point_inside_cell_bsp` at `0x0053C1F0`;
- `BSPNODE::sphere_intersects_cell_bsp` at `0x0053C260`;
- `BSPNODE::sphere_intersects_poly` at `0x0053CA30`;
- `BSPNODE::sphere_intersects_solid` at `0x0053CAF0`;
- `BSPNODE::find_walkable` at `0x0053CC80`;
- `BSPNODE::sphere_intersects_solid_poly` at `0x0053CD50`;
- `BSPLEAF::find_walkable` at `0x0053D6F0`.
The same oracle records the cross-checks against ACE master
`65f092...` and Chorizite DatReaderWriter `c535987...`. Retail remains the
authority where those references differ.
## Differential evidence
The referee compares scalar results and all stateful outputs by exact float
bits. It covers selected polygons, vectors, planes, path state, collision and
object flags, contact-plane writes, final `ResolveResult`, persistent body
state, and full cell membership.
| Gate | Executions | Result |
|---|---:|---:|
| Null, on-plane, radius-equality, equal-candidate, multi-polygon, and deep-tree fixtures | 4 focused fixtures | 0 mismatches |
| Static and swept overlap randomized sweep | 10,000 paired cases | 0 mismatches |
| Walkable randomized sweep | 5,000 paired cases | 0 mismatches |
| Six dispatcher paths | 6 complete transition fixtures | 0 mismatches |
| Installed-DAT sweep across `0x8A02016E`, `0x8A02017A`, and `0xA9B4013F` | 7,500 randomized cases | 0 mismatches |
| Complete graph/flat resolver sequences | 1,200 frames | 0 mismatches |
| Warmed flat traversal | 10,000 iterations | 0 managed bytes |
The installed-DAT gate randomizes points, spheres, movement, insert paths,
orientations, scale, and boundary values. No tolerance band is used.
## Verification
- focused differential tests: 13 passed;
- complete Core suite: 3,276 passed / 2 skipped;
- `git diff --check`: no whitespace errors;
- full Release build: passed;
- complete Release suite: 8,384 passed / 5 skipped.
No divergence-register row changes are required. This slice changes the
storage representation exercised by the referee, not production gameplay
behavior. Slice I5 next publishes the prepared flat assets alongside the
current graph under one landblock generation and runs the connected shadow
gate.