fix(mesh): anchor XBG7 resources by neighbourhood -- inconsistency 125 -> 63, ships render right
anchor_pool_mesh took the FIRST candidate in file order from a container-global vertex-run scan, so a resource could be handed another resource's block whenever both shared (stride, vertex count, index count). Both blocks are real geometry and both pass every quality gate, so only position separates them. anchor_pool_mesh_near now tries candidates in order of distance from a reference, and anchor_models_filtered runs two passes: pass 1 anchors first-match to learn where resources land, pass 2 re-anchors each resource preferring the median anchor of its +/-2 descriptor neighbours. Too few anchored neighbours -> keep pass 1, so nothing regresses to guesswork. before decoded 5480/6294 shared 681 inconsistent 125 after decoded 5480/6294 shared 681 inconsistent 63 Coverage unchanged, inconsistency halved. e303_wep_01 decodes to 49x23x42 in ALL containers now, and e106 renders as a destroyer instead of a slab -- its two shared turrets symmetric at X[-203,-154] and X[154,203]. That resolves the user-reported "capital ships assemble wrong" for this cause. The filtered path needed care: models_named (what the viewer uses) dropped non-wanted resources, which would have left filtered decodes with no neighbourhood and silently kept the old behaviour. Resources are now collected regardless of the filter, but only the asked-for ones and their +/-2 neighbours are decoded in pass 1, so a filtered decode stays proportional to what was asked. 63 cases remain; mesh_consistency_disc stays ignored and now records 63, not 125. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -153,6 +153,11 @@ report needs re-grounding against a specific ship and a specific expectation.
|
||||
|
||||
---
|
||||
|
||||
## ✅ FIXED 2026-08-12 — it was a mis-decode, and the anchor now uses locality
|
||||
|
||||
> Resolution at the end of this entry. Kept in full because the two wrong turns
|
||||
> along the way (a "stray volume", then "monotonic anchoring") are the useful part.
|
||||
|
||||
## ⚠️ The format layer is NOT exonerated — but the cause is a MIS-DECODE, not a stray volume
|
||||
|
||||
**Found 2026-08-11 by finally doing the visual**, which the notes above kept
|
||||
@@ -255,3 +260,19 @@ worth fixing regardless — it is the same one-way-test shape as the earlier
|
||||
Also unchanged: only **two** cross-id placements exist fleet-wide (`e303_wep_01`
|
||||
on `e101` ×24 and `e106` ×36, across 335 assembled ships), so cross-id mounting is
|
||||
a narrow, real feature rather than a systemic guess.
|
||||
|
||||
---
|
||||
|
||||
## Resolution (2026-08-12)
|
||||
|
||||
`anchor_pool_mesh` took the **first** candidate in file order from a
|
||||
container-global scan, so a resource could be handed another resource's block
|
||||
whenever both shared `(stride, vertex count, index count)`. Fixed by anchoring
|
||||
each resource near its **descriptor neighbours** (two-pass: learn, then re-anchor).
|
||||
|
||||
- decoded **5 480 / 6 294 unchanged**, inconsistent **125 → 63**
|
||||
- `e106` renders correctly ([after](captures/e106-static-assembly-fixed.png))
|
||||
- the user-reported "capital ships assemble wrong" is **resolved** for this cause
|
||||
|
||||
Still open from this entry: `static_assembly_matches_runtime_capture` walks only
|
||||
the capture's parts, so **extra** static placements still cannot fail it.
|
||||
|
||||
BIN
docs/re/captures/e106-static-assembly-fixed.png
Normal file
BIN
docs/re/captures/e106-static-assembly-fixed.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
@@ -393,11 +393,37 @@ and prefer candidates close to the previous resource's anchor), falling back to
|
||||
first-match when there is no neighbour yet. That needs no new format knowledge,
|
||||
and it selects `52 257 440` here.
|
||||
|
||||
**Not implemented.** It changes the anchor for every one of the 6 294 resources,
|
||||
so it needs the before/after measurement — decoded count must not fall from
|
||||
5 480, and the inconsistency count should fall from 125 — plus the ignored test
|
||||
### ✅ Implemented (2026-08-12) — inconsistency halved, coverage unchanged
|
||||
|
||||
`anchor_pool_mesh_near` tries candidates in order of distance from a reference,
|
||||
and `anchor_models_filtered` runs **two passes**: pass 1 anchors first-match to
|
||||
learn where resources land, then pass 2 re-anchors each resource preferring its
|
||||
**neighbourhood** — the median anchor of its ±2 descriptor neighbours. A resource
|
||||
with too few anchored neighbours keeps pass 1's result, so nothing regresses to
|
||||
guesswork.
|
||||
|
||||
| | decoded | shared | inconsistent |
|
||||
|---|---|---|---|
|
||||
| before | 5 480 / 6 294 | 681 | **125** |
|
||||
| after | 5 480 / 6 294 | 681 | **63** |
|
||||
|
||||
**Coverage is unchanged and inconsistency halves.** `e303_wep_01` now decodes to
|
||||
49 × 23 × 42 in *all* containers, and `e106` renders as a destroyer instead of a
|
||||
slab ([before](../captures/e106-static-assembly-volume-bug.png) ·
|
||||
[after](../captures/e106-static-assembly-fixed.png)) — its two shared turrets sit
|
||||
symmetrically at X[−203,−154] and X[154,203].
|
||||
|
||||
**The filtered path needed care.** `models_named` (what the viewer's ship
|
||||
rendering uses) drops non-wanted resources, which would leave a filtered decode
|
||||
with no neighbourhood at all — and silently keep the old behaviour. Resources are
|
||||
now collected regardless of the filter, but only the asked-for ones and their ±2
|
||||
neighbours are decoded in pass 1, so a filtered decode stays proportional to what
|
||||
was asked for.
|
||||
|
||||
**63 remain.** The ignored test
|
||||
[`mesh_consistency_disc.rs`](../../crates/sylpheed-formats/tests/mesh_consistency_disc.rs)
|
||||
un-ignored once it passes.
|
||||
still asserts the target state and now records 63 rather than 125; the remaining
|
||||
cases are where the neighbourhood is itself wrong or absent.
|
||||
|
||||
### Where the mis-decode is *not*: the grouped-pool anchor
|
||||
|
||||
|
||||
Reference in New Issue
Block a user