acdream/docs/research/2026-07-31-issue273-tight-gap-support.md

4.2 KiB

Issue #273 — Holtburg tight-gap support validation

Date: 2026-07-31 Status: implementation, automated gates, and exact live gate pass Scope: grounded player step-down support at a floor edge beside a static cylinder

Captured scene

The reproducible gap is in outdoor cell 0xA9B40032, between:

  • building shell GfxObj 0x01000F69, placed at (158.178, 37.7055, 94.0) with quaternion (w=.939319, x=0, y=0, z=-.343045);
  • static post 0xCA9B4027, placed at (160.173, 34.487, 95.975), represented by its Setup-authored cylinder (radius=.282, height=5.564);
  • the local player Setup's exact two spheres (radius=.48, origins z=.475 and z=1.35).

The building's supporting ledge terminates at local x=4. The first post-side response moved the player's foot-sphere center to approximately local x=4.33. The full .48 movement sphere still overlapped the floor, so the existing step-down path accepted the candidate. Repeated frames then carried the player around the post and outside the building shell.

The fixture tests/AcDream.Core.Tests/Fixtures/issue273/0x01000F69.gfxobj.json preserves the installed DAT PhysicsBSP. The replay in Issue273HoltburgTightGapReplayTests uses the captured object placement, player spheres, static posts, and movement offsets.

Retail mechanism

The missing rule is not extra collision padding and is not a larger player sphere. It is retail's second-stage support validation:

  1. CTransition::step_down (0x0050B2A0) performs the ordinary downward collision probe.
  2. After finding a walkable contact plane, an EdgeSlide mover that is not in StepUp calls CTransition::check_walkable (0x0050AFF0). The binary sequence is test ah,2 at 0x0050B36A, which is state bit 0x200 (EdgeSlide), followed by the step_up == 0 test and call at 0x0050B380.
  3. CTransition::check_walkable first calls SPHEREPATH::check_walkables (0x0050C3E0).
  4. SPHEREPATH::check_walkables halves the saved foot-sphere radius and calls CPolygon::check_walkable (0x00538E60).
  5. If the remembered polygon does not support that smaller sphere, CTransition::check_walkable performs a downward CheckWalkable insertion. BSP leaves require both walkable_hits_sphere and CPolygon::check_small_walkable (BSPLEAF::hits_walkable, 0x0053D670).
  6. If neither check finds support, CTransition::step_down rejects the candidate and the existing edge-response chain handles it.

ACDream already had the small-radius BSP-leaf test, but DoCheckWalkable treated the mere presence of a remembered polygon as success, and the ordinary DoStepDown(..., runPlacement:false) path never called it. This let a full-radius overlap stand in for actual foot support.

Port

  • BSPQuery.CheckWalkableSupport is the shared resolved-polygon form of retail CPolygon::check_walkable.
  • SpherePath.CheckWalkables implements the retail half-radius remembered polygon check without mutating canonical sphere state.
  • Transition.DoCheckWalkable now tests the remembered polygon rather than treating a non-null polygon as sufficient.
  • Transition.DoStepDown restores the EdgeSlide/non-StepUp support gate before the existing placement-policy seam.

There are no location checks, object IDs, guessed radii, widened collision shapes, or gap-specific tolerances in the production fix.

Regression impact

The existing #271 staircase-side replay begins with its center .288 m outside a tread whose retail half-radius support boundary is .24 m. Retail may therefore stop that exact candidate. The test now preserves the original user-visible invariant—never reverse or accelerate downhill—without requiring forward progress beyond retail's support boundary. The ordinary continuous staircase replay still requires and achieves forward progress.

Gates

  • issue #273 fixture/replay: 3 passed;
  • focused BSP, step-up, edge-slide, #185/#271 family: 42 passed / 1 skipped;
  • complete Core tests: 4,111 passed / 2 skipped;
  • Release solution build: passed;
  • complete Release solution tests: 10,068 passed / 5 skipped.

The user accepted the exact in-client Holtburg gap gate on 2026-07-31: the gap blocks from the tested approach, and the adjacent movement checks remain healthy.