re: the capture names file offsets -- the twin collapse is an anchoring error

Locating each drawn buffer's positions inside Stage_S01.xpr shows vbase - offset
is one constant (0x1A94FFF4, same in two runs), so a capture gives ground truth
at file-offset granularity. Read against our anchor scan it is a defect list:
full/_m resources starting at their own _l buffer, eight drawn buffers claimed by
nobody, and the bdy_01_l/bdy_02_l twins sharing one buffer while the container
carries both halves (0x3b3ee8 and its exact X-mirror at 0x3c55d8).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-12 01:55:13 +00:00
parent aa82d293a9
commit 3245aca8cb
3 changed files with 304 additions and 1 deletions

View File

@@ -0,0 +1,15 @@
file offset vcount claimed by our decode
0x38788 181 — NOBODY
0x4b8b8 93 — NOBODY
0xb6574 41 — NOBODY
0xdbbac 77 — NOBODY
0x133da0 76 — NOBODY
0x162840 60 — NOBODY
0x3b3ee8 119 e106_bdy_01_l(119), e106_bdy_02_l(119)
0x3c55d8 119 — NOBODY
0x3dd2c4 146 e106_bdy_03(815), e106_bdy_03_l(146)
0x40763c 179 e106_bdy_04_l(179)
0x40e418 51 e106_brg_01(202), e106_brg_01_m(92)
0x444ccc 58 e106_eng_01_l(58)
0x44a32c 44 — NOBODY
0x45705c 82 e106_wep_02_01_l(82), e106_wep_02_01_m(294)

View File

@@ -582,4 +582,66 @@ resource by `vcount` plus decoded positions. The same match yields, for each
part, the `vbase` the engine used — so two resources that our decoder gives the
same geometry can be checked directly: different `vbase` in the capture ⇒ our
shared decode is wrong. That is the per-part oracle any future anchor work should
be validated against, and it needs no new capture run.
be validated against, and it needs no new capture run.
### ✅ It was run — and the capture gives file-offset ground truth
`examples/shared_vbase_check.rs` does the per-part check above, and then goes one
step further than planned. Three results, in order of strength.
**1. A draw's `vbase` *is* the container file offset plus a constant.** Vertex
POSITION is `f32×3` big-endian at vertex offset 0, so a draw's dumped positions
are a value pattern that can be searched for in the `.xpr` itself. Doing that for
every draw in `xenia_ship_capture_01/02.log` and histogramming `vbase offset`:
```
xenia_ship_capture_01.log: 11 distinct vbases located, 208 not in this container
vbase - offset = 0x1A94FFF4 ×8 ← same constant in log 02
```
The 208 "not in this container" are draws whose geometry lives in `Common.xpr`,
a weapon pack or a backdrop — expected. The eight that do belong to `Stage_S01`
share **one** constant, and the *same* constant in a second run, so the container
is uploaded contiguously and **a capture names the exact file offset of every
buffer the engine drew**. Log 03 loaded the container at a different address, so
the constant is per-run, not baked.
**2. Read against our anchor scan, that is a defect list**
([`captures/stage-s01-capture-truth-offsets.txt`](../captures/stage-s01-capture-truth-offsets.txt)):
| file offset | drawn vcount | claimed by our decode |
|---|---|---|
| `0x3b3ee8` | 119 | `e106_bdy_01_l`(119), `e106_bdy_02_l`(119) |
| `0x3c55d8` | 119 | — **nobody** |
| `0x3dd2c4` | 146 | `e106_bdy_03`(815), `e106_bdy_03_l`(146) |
| `0x40763c` | 179 | `e106_bdy_04_l`(179) ✅ |
| `0x40e418` | 51 | `e106_brg_01`(202), `e106_brg_01_m`(92) |
| `0x444ccc` | 58 | `e106_eng_01_l`(58) ✅ |
| `0x45705c` | 82 | `e106_wep_02_01_l`(82), `e106_wep_02_01_m`(294) |
| `0x38788` `0x4b8b8` `0xb6574` `0xdbbac` `0x133da0` `0x162840` `0x44a32c` | 181, 93, 41, 77, 76, 60, 44 | — **nobody** |
Two resources land exactly (`bdy_04_l`, `eng_01_l`). Everywhere else a **full or
`_m` resource starts at the offset of its own `_l` buffer** — `bdy_03` decodes
815 vertices beginning where the engine's 146-vertex LOD begins — and eight
drawn buffers are claimed by no resource at all. This is the anchor scan taking
the first candidate that validates, seen directly rather than inferred.
**3. The twin pair is an anchoring error, and the mirror is in the data.** For
`e106_bdy_01_l``e106_bdy_02_l` the capture shows **two** 119-vertex buffers
per run, `0x3b3ee8` and `0x3c55d8`; the first is byte-for-byte what we decode,
and the second is its **exact X-reflection** (every dumped position matches ours
with `x` negated). So the container carries both halves as separate baked
geometry, the engine draws each from its own buffer, and our decoder returning
one buffer for both names is the defect — which `correlate`'s mirror flag and
`ship::apply_twin_mirrors` have been compensating for downstream all along.
That settles the question this section opened with, for this pair: **not
legitimate reuse.** It also pins what the withdrawn neighbourhood-anchor fix
could not: `0x3b3ee8` stays with whichever twin we already decode there, and the
other twin must move to `0x3c55d8`. The invariant is checkable without a capture
*mirrored twins must decode to X-reflected buffers, never identical ones*.
Not settled: `e106_brg_01_b_02``e106_brg_01_l` (51 verts). A second 51-vertex
`vbase` exists in the logs but is **not** from this container, and the container
holds three near-identical 51-vertex runs, so the pair has no oracle yet.
`n006_01A``n006_01B` shows a single `vbase` in all three logs — consistent
with real reuse, but equally with only one of the two being on screen.