# RE backlog Open items that are *not* being worked right now. Each entry says what is wrong or unknown, what evidence exists, and what the first step would be. Move an item into `INDEX.md` (with a `structures/…md` or a parser + test) once it is actually settled. --- ## Capital ships assemble wrong in the viewer **Reported:** 2026-07-30, by the user. **Status:** πŸ”Ž **diagnosed 2026-08-10 β€” the format layer is exonerated.** Runtime captures of three classes (`f105`, `e105`, `e106`) at controlled range reproduce `assemble_ship` to ≀0.43 units in translation and to 0.000 in rotation for every part that does not move; see [`ship-placement-capture-generalisation.md`](ship-placement-capture-generalisation.md) Β§4. So look at **the viewer**: first that it passes `include_external = true` (`iso_loader.rs:4012` β€” with `false` an e106 loses its bridge and both nacelles, 5 parts instead of 11), then its own transform stack. One real format-side bug was found on the way and is **fixed**: index-less parts (`e105_brg`) never matched their `GN_Bridge_01` hardpoint, so 34 (stage, ship) entries β€” `e102`, `e104`, `e105` across Stages 02–29 β€” assembled without a bridge. The other apparent exception (`e105_eng_01` rotation) was an aggregation artefact and is 0.000. The original report and its reasoning follow. The reborn viewer builds capital ships from the split XBG7 parts via `sylpheed-formats::ship::assemble_ship`, and they come out **wrong** β€” parts in the wrong place / wrong orientation. **Why this is a real finding and not a known limitation:** the RE write-up [`ship-placement-runtime-capture.md`](ship-placement-runtime-capture.md) declares static assembly βœ… **exact** as of 2026-07-26 β€” 9-channel joint tables `[TX TY TZ RY RX RZ SX SY SZ]`, Euler `RyΒ·RxΒ·Rz`, with `ship::tests::static_assembly_matches_runtime_capture` asserting static == runtime capture (T < 1.0, R < 0.02). So either the viewer is not using that path, or the claim generalises worse than the test suggests. **The likely gap:** that test is **one ship** β€” the `e106` destroyer, 8 parts plus two nacelles, two turrets and the hull mirror. Nothing pins the other classes. Rules that were derived from `e106` and could easily be `e106`-specific: - the engine cluster rig mounted at `GN_Engine_01` (two mirrored nacelles + centre); - "X-reflect the shared-geometry twin whose lateral offset opposes the geometry's dominant side" β€” a heuristic, not a decoded flag; - cross-id turret instancing (Γ—2). **First step (the oracle already exists):** re-run the runtime capture on a *different* capital ship and diff static vs captured, exactly as `e106` was done β€” F10 in the `capture-ship-placement` build of `xenia-canary-native` dumps the ship shader's `c0..c2` WorldViewProjection rows per part; `WV_ref⁻¹ Β· WV_p` is the ship-space rigid transform, which is ground truth. Pick a class whose rig differs from `e106` (different engine count, a ship with no `sld`, a carrier). Then extend `static_assembly_matches_runtime_capture` into a per-ship table so a regression in one class cannot hide behind `e106` passing. **Also worth ruling out first, cheaply:** that the viewer's own transform stack (scale, handedness, node-instance recursion) is not re-breaking a correct assembly β€” compare the viewer's placement against `assemble_ship`'s output directly before blaming the format layer. --- ## Viewer: `include_external` is already on β€” that hypothesis is dead **Checked 2026-08-11.** The item above names "first that it passes `include_external = true` (`iso_loader.rs:4012`)" as the cheap first step. It does: `ShipBrowser::show_external` defaults to `true` (`iso_loader.rs:643`), the checkbox reads it (`ui.rs:1593`) and it is threaded through `RequestShipRender` β†’ `build_ship_model` β†’ `assemble_ship` unchanged (`ui.rs:1689`, `iso_loader.rs:4012`). So a ship rendered by the viewer is the full external assembly, not the bare hull. The viewer also does not have a transform stack of its own to blame: it bakes `ScenePart::apply` straight into the vertices and rotates normals by the same `p.m` (`iso_loader.rs:4030-4062`), so its placement is `assemble_ship`'s output by construction. What remains unexcluded, in order of cheapness: the mirror handling (`det < 0` reverses triangle winding only β€” a reflected part keeps its reflected geometry), `Xbg7Model::models_named` resolving the wrong sub-model when a resource name repeats, and the exhaust cones. **Next step is a visual**: the diagnosis has run out of things it can settle by reading, so the viewer needs to be run against a known-good class (`e106`) and its render compared with `ship_render`'s. --- ## Viewer: the duplicate-resource-name hypothesis is dead too **Checked 2026-08-11.** The diagnosis above left three candidates for why capital ships assemble wrong in the viewer: mirror handling, `Xbg7Model::models_named` resolving the wrong sub-model when a resource name repeats, and the exhaust cones. The second is now **refuted**, and comprehensively. `build_ship_model` resolves each placement with `base.iter().find(|m| m.name == p.resource)` (`iso_loader.rs:4041`) β€” first match wins β€” so a repeated resource name inside a container would silently draw the wrong geometry. It cannot happen: decoding **every** XBG7 resource in **all 22 stage containers** gives **4 603 resources and zero repeated names**. ``` Stage_S01 62/62 Stage_S07 323/323 Stage_S13 290/290 Stage_S25 351/351 Stage_S02 304/304 Stage_S08 388/388 Stage_S14 22/22 Stage_S26 318/318 Stage_S03 214/214 Stage_S09 316/316 Stage_S15 386/386 Stage_S27 321/321 Stage_S04 179/179 Stage_S10 7/7 Stage_S16 65/65 Stage_S28 118/118 Stage_S05 92/92 Stage_S11 157/157 Stage_S24 162/162 Stage_S29 386/386 Stage_S06 266/266 Stage_S12 376/376 ``` Per-ship it is tighter still: `e106` wants 9 distinct names and decodes exactly 9 models for 11 placements; `e105` 9 for 9; `f105` 5 for 6. Every placement resolves to the one model it names. **So two of the three candidates are gone** (this one and `include_external`), leaving **mirror handling** and **the exhaust cones** β€” and the still-untried visual comparison, which remains the right next step.