# Grinding integration ## Current milestone: authored geometry, not playable grinding The test course now owns seven named paths in `grind_world.rs`: two flat bars, both half-pipe lips, and the three exposed platform edges. The downhill entrance is not an edge, and triangle diagonals/transition tessellation are not splines. Bar top centres and coping paths share the collision/render dimensions. Climbing geometry from the other task is preserved. `GrindGeometry` retains a relocatable Pegasus tSplineData blob. Its layout matches the existing recomp's `owned/world/src/grind_spline.cpp`: 16-byte header, 32-byte rail records, 144-byte segments, signature `2C7017070007004A`, straight segment delta at +0, origin at +48, inverse length at +64, bounds +80/+96, length +112, cumulative length +116, and owner/previous/next +120/+124/+128. IDs are stable host-authored integers, not guessed retail asset IDs. This registry is not yet connected to contact acquisition or state selection. Startup explicitly logs `native_acquisition=not_connected`. The game therefore still treats the bars as ordinary collision geometry. Do not call this playable grinding or replace the existing empty-edge providers with a proximity snap. ## Native integration audit Evidence image: TU3 `default_82000000_011B0000.bin`, base `82000000`, SHA-256 `f4aa113eb541bfba03dbc108cf5ab43f58c965b20fa3b82f9c40938a0ad841c4`. Community symbols plus generated PPC instruction comments were consulted. The disposable IDA database's decompiler misdecodes some VMX128 operations; its truncated pseudocode is not sufficient to port the nonempty branches. - `82D8A828` GrindManager input update: constructs an AABB around processed position112 with half-extent1.2 (`821659F4`), unless byte2476 bit0 disables it. - `82C1EAD8`: static asset/segment bounds collection, source order, maximum40; entries are48 bytes with endpoints and retained owner/flags. The final16 bytes must not be invented as a surface normal. - `82D875A8`: candidate acquisition/scoring. Dispatches truck/deck contact queries (`82C1FDC0`, `82C20130`, `82C1FB98`, `82C1F968`) before scoring. For example `82D89150` handles a two-truck candidate; it is not a nearest-rail angle classifier. Selection output has candidate byte384 in a416-byte record. - `82C1E2C8` is now ported in core `physics/grind_contact.rs`: the exact segment/triangle leaf used by those truck/deck queries. It retains the zero-denominator rejection and closed0..1 bounds, unlike wheel probes with their endpoint tolerance. It does not itself accept a grind. - `82D8AB08`: post-input manager publication precedes state selection. - Native selector maps actual candidate grind type0..5 to states401,400,402, 403,404,405. `player_state/selection.rs` currently publishes no candidate. - Boardslide Enter `82D41100` calls shared grind entry `82D3F318`, then clears bytes240/241. Shared entry resets board controller settings, skeleton state and the grind manager; merely allowing state400 in transition.rs is unsafe. - The active force/contact owner, output conditioner and graph attributes still need wiring. `player_state/publication.rs` currently uses default grind output; camera output has the same inactive assumption. - Air acquisition also needs the nonempty trajectory path: `82D69F80`, `82D6A168`, `82D6A398`, `82D6A840` and GrindAirAdjust `82D712E0` onward. The clone's GRIND_CONTACT_SPEC explicitly leaves parts of this arbitration unresolved, so it cannot serve as a complete implementation. Next implementation boundary: native endpoint/contact queries and candidate record/scorer, then lifecycle/constraint/output integration as one coherent vertical slice. Do not enable selector candidates before those owners exist. Validation: build only; no gameplay or automated tests, per user instruction. ## 2026-09-07 collision and contact follow-up The rail boxes were emitted with only ONE_SIDED. Native contact fixup82AD3130 rejects an edge-region contact when its convex bit is absent. Authored rail faces now set the two perimeter-edge bits on each triangle and leave the coplanar diagonal non-convex (0x60 /0xC0 for the existing triangle winding). This change applies to rail/coping/support boxes only. Gameplay confirmation is outstanding; a build does not establish that this explains every missed hit. Core truck_contacts ports82C1FDC0's two local-board probe rectangles, using TruckToWheel and DeckCenterToTruck, the -.02 start offset and -.20 depth, first-triangle priority, strict squared-distance comparison and first-entry tie retention. It remains a contact query, not an engagement decision. Checked the task Research readable game recreation and its referenced Skate3CustomEngineLayer/src/skate3_native_grind.cpp. That integration registers splines in the original guest GrindData owner; it does not contain replacement grind forces. Expand Skate 3 replay toolkit likewise supplies research and capture infrastructure rather than a standalone grind controller. The remaining native state/force and graph-attribute contracts are unresolved. Do not advertise this build as grind-ready. Build log: logs/grind-collision-build.log (successful,35 warnings); no tests executed.