probe(physics): ACDREAM_PROBE_SUPPORT + ACDREAM_WIRE_MESH — separate #337's three candidates

The user is wedged at the top of Neftet rock plateaus, jumps sink into the
mesh, and a corpse falls straight through. ACDREAM_PROBE_REACH already ruled
out its own domain: blocked=0, every candidate tested-ok. Three candidates
remain — terrain support, a collision mesh not where its visual is, or the
transition wedging on an unobstructed path.

ACDREAM_PROBE_RESOLVE alone cannot separate them. It prints a three-value
contact-plane token, no plane normal, no plane height, no terrain sample and
no plane provenance, so all three produce the same line. Two additions:

[support] — one line per resolve for EVERY body, not just the player. A corpse
is a plain physics body with no player-specific logic, so its fall-through is
the cheapest available control on "movement code vs geometry data", and it is
invisible to any player-filtered probe. The line samples the outdoor terrain
INDEPENDENTLY at the body's own out-XY and prints the contact plane's own
height at that same XY. Two heights at one point make support=terrain /
object / none a measurement rather than an inference, and cpSrc= names the
site that asserted the plane so provenance and classification cross-check.

[geom] — once per GfxObj that comes near a mover: the object's physics-BSP
vertex cloud against its visual mesh AABB in the same local frame, through the
same prepared accessors the resolver queries. verdict=coincident REFUTES the
working hypothesis for that object outright; no-physics-bsp / empty-physics-bsp
/ displaced / extent-mismatch each name a specific data defect. Built to
refute, not to confirm — two diagnoses on this defect's lineage have already
been refuted by measurement.

ACDREAM_WIRE_MESH upgrades the existing F2 overlay, which drew a broadphase
proxy cylinder for BSP objects and so could not answer the question at all, to
the real physics-BSP polygon edges (cyan) beside the visual mesh box (magenta)
and the terrain surface (yellow). Own class per code-structure rule 1.

The provenance latch lives on PhysicsDiagnostics, not on CollisionInfo. Two
fields there first — the obvious home — broke the flat/graph differential
referee and the scratch-reset poison test, both of which compare CollisionInfo
member-for-member. Teaching either to skip a member is a one-line green fix
that puts a permanent hole in a referee whose whole job is comparing
everything. Captured as feedback_probe_state_off_compared_types.

Seven tests cover the support classifier's boundaries: a wrong classifier does
not fail to answer, it answers confidently wrong.

Gates: Release build 0 errors; complete suite 11,225 passed / 4 skipped / 0
failed from a cleaned tree — baseline 11,218/4/0 plus exactly the seven new
tests, skips unchanged.

Issue #337 filed with the symptom set, what is ruled out, and a table of what
each possible output means. All of this is TEMPORARY and recorded for
stripping with the physics-probe family.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-08-06 19:49:59 +02:00
parent 13fcf38138
commit 49a7e90652
9 changed files with 1376 additions and 1 deletions

View file

@ -24,6 +24,91 @@ What does NOT go here:
- Every session: scan OPEN issues at start; promote/close anything we touched during the session before ending.
- Promoting to a Phase: mark as `DONE (promoted to Phase X)` + commit SHA where the Phase entry landed.
## #337 — Neftet rock plateaus: wedged at the top, jumps sink into the mesh, corpses fall through — cause NOT yet established
**Status:** OPEN — instrumented, not diagnosed. Awaiting the live capture below.
**Severity:** HIGH — walk-through, fall-through, and a hard movement stop on world geometry.
**Filed:** 2026-08-06, user-reported in live play after #334's fix landed.
**Component:** physics / collision — possibly geometry data rather than movement code.
### Symptoms, all from the user in live play
1. Walks **up** a rock face onto a plateau fine, then **cannot pass at the top** — wedged, position frozen.
2. Jumping is **"swallowed half way by the rock"** — the body sinks into the visual geometry.
3. **A monster corpse falls straight through the rock.**
Symptom 3 is the load-bearing one. A corpse is a plain physics body with no
player-specific movement logic, so a fall-through there cannot be explained by
anything in the player's controller.
### What is already RULED OUT
`ACDREAM_PROBE_REACH` (`334-fix-gate.log`, and the earlier
`334-neftet-probe.log`). At the frozen position: `blocked=0`, and **every**
candidate returns `tested-ok` — including the landblock's own rock mesh
`gfx=0x010046DE` in cell `0x8766002B`. **No object is blocking the player.**
That probe can only see shadow objects, so it has ruled out its own domain and
can say nothing about terrain or the transition.
Two diagnoses have already been refuted by measurement on this defect's
lineage: the broadphase reach filter (#333/AP-158) and the edge-slide family.
Do not open a third by reasoning from the source.
### The remaining candidates — and what is NOT yet established
- **(a) terrain** is what supports/blocks the body (walkable slope limit,
step-up refusal, terrain Z).
- **(b)** a **collision mesh placed somewhere other than its visual**, so the
body interacts with geometry that is not where the rock is drawn.
- **(c)** the **transition wedging** despite an unobstructed path.
(b) is the current working hypothesis and is **NOT ESTABLISHED**. It is
plausible — a corpse falling through and a jump sinking in are both what
absent-or-displaced collision looks like — but no measurement supports it yet,
and the instruments below were built to REFUTE it, not to confirm it.
Possibly relevant, possibly coincidence: landblock `0x8766` carries the
**largest single collision owner in the game**, an 81-cell (9×9) footprint
measured during #334 — larger than anything else by a wide margin.
### Instruments (2026-08-06 — TEMPORARY, strip with the physics-probe family)
`ACDREAM_PROBE_RESOLVE` alone does **not** separate (a), (b) and (c): it prints
a three-value contact-plane token, no plane normal, no plane height, no terrain
sample and no plane provenance, so all three candidates produce the same line.
Two additions close that:
- **`ACDREAM_PROBE_SUPPORT=1`** → `[support]` + `[geom]`.
- `[support]`, one per resolve **per body** (players AND corpses): samples the
outdoor terrain independently at the body's own out-XY and prints the
contact plane's own height at that same XY. `support=terrain` /
`support=object` / `support=none` is then a measurement, not an inference,
and `cpSrc=` names the code site that wrote the plane so provenance and
classification cross-check each other.
- `[geom]`, once per GfxObj that comes near the mover: compares the object's
physics-BSP vertex cloud against its visual mesh AABB in the same local
frame. `verdict=coincident` **refutes (b)** for that object outright;
`no-physics-bsp` / `empty-physics-bsp` / `displaced` / `extent-mismatch`
each name a specific data defect.
- **`ACDREAM_WIRE_MESH=1`** upgrades the existing F2 collision overlay from a
broadphase proxy cylinder to the objects' real physics-BSP polygon edges
(cyan) beside their visual mesh boxes (magenta) and the terrain surface
(yellow). Settles "visual versus collision" by eye.
### How to read the capture
| Observation | What it means |
|---|---|
| `[geom] verdict=no-physics-bsp` or `empty-physics-bsp` on the rock | The rock has **no collision geometry**. All three symptoms follow; nothing on the movement side needs explaining. |
| `[geom] verdict=displaced` | **(b) confirmed.** Fix the placement/registration transform. |
| `[geom] verdict=coincident` on every nearby object | **(b) refuted.** The cause is (a) or (c); read `[support]`. |
| `[support] support=terrain` while standing on the visible plateau | (a): terrain, not the rock, is the support — terrain Z near the plateau top is the thing to look at. |
| `[support] support=object` with `cpAboveTerr` ≈ the plateau height | The rock IS supporting the body; the wedge is (c). |
| `[support] stalled=true ok=true` with `cpWalkable=true` | (c): the transition accepts the move and advances nothing. |
| `[support] support=none` on the corpse throughout its fall | Nothing ever contacts it — consistent with absent collision, and `[geom]` says whose. |
| **No `[support]` line at all** for the corpse's guid while it visibly falls | The client is not simulating that body — the descent is server-driven or presentational, and the client-side collision path is not the place to look. An absence here is a real answer, not a gap in the capture. |
| `[support] cpWalkable=false` at the freeze | Slope-limit refusal — compare `cpNz` against `floorZ` on the same line. |
## #335 — The INDOOR half of retail's part-array `find_transit_cells` is not ported: an EnvCell neighbour is admitted on a SPHERE test where retail uses a BOX
**Status:** OPEN