diff --git a/docs/re/structures/xbg7-mesh.md b/docs/re/structures/xbg7-mesh.md index 5b12d85..9e5cd60 100644 --- a/docs/re/structures/xbg7-mesh.md +++ b/docs/re/structures/xbg7-mesh.md @@ -339,6 +339,43 @@ majority is the turret the render and the runtime capture both support. 15) and nothing yet says which is right. Use the detector to flag; do not silently rewrite geometry on a vote. +### ROOT CAUSE: the candidate list is container-global + +Traced 2026-08-12. `anchor_pool_mesh` (the **per-block** path, which is the one +that handles single-sub-mesh resources like `e303_wep_01`) walks a candidate list +built by `vertex_run_starts(bytes, data_base, stride)` — **one scan of the whole +container per stride**, shared by every resource of that stride. It accepts the +**first** candidate that validates. + +So a resource is anchored to *whatever block matches its signature first in file +order*, and nothing ties that block to the resource it belongs to. Two resources +sharing `(stride, vertex count, index count)` are interchangeable to this search. + +**The wrong block is not distinguishable by quality.** Tracing the accept for +`e303_wep_01`: + +``` +Stage_S01 ACCEPT vb=4600480 pad=0 span= 49 × 23 × 42 passes 0.85 = true +Stage_S02 ACCEPT vb=18403456 pad=0 span=1600 × 2100 × 4800 passes 0.85 = true +``` + +Both clear the strict winding-consistency gate, because the wrongly-taken block +**is** real, coherent geometry — just another resource's. That rules out a whole +family of fixes: no threshold, no scoring, no "pick the best candidate" changes +this, and the earlier attempt to add best-of-N selection in the grouped-pool +anchor duly changed nothing. + +**The search space has to be constrained instead.** Two candidates, in order of +how much new format knowledge they need: + +1. **Per-resource data extents.** The XPR2 resource table gives each resource a + descriptor; if the geometry extent can be derived from it, restrict `starts` + to that range and the theft becomes impossible. +2. **Monotonic anchoring.** If resources' data blocks follow descriptor order, + then resource *k*'s `vb` must lie after resource *k−1*'s — a cheap constraint + needing no new format knowledge. Testable against the 556 resources that + already decode consistently across containers. + ### Where the mis-decode is *not*: the grouped-pool anchor An attempt to fix it by making `anchor_grouped_meshes` choose the **best-scoring**