The Stage-02 outcome write-up ended by naming "turrets near the asset must become targets" as the fix worth ~50% of the escort damage. That was an inference from a co-presence attribution, not a measurement. Run it and it does not hold. Also corrects the run labelling: pilot.py gained the SYLPH_KILL_TURRETS gate two minutes before mission02 started, so mission02 was already a treatment run, not a second baseline. Only mission01 (0 of 3968 pilot frames targeting a turret) is the baseline. At a common t=428s: baseline 46.9% escort hull, treatment 44.5% and 53.0%. The two runs of the same arm differ by more than either differs from the baseline, and the escort still reaches zero at t~590-670s in all three. So the transferable finding is the power limit: one 430s flight cannot resolve an effect below ~9 percentage points, and every single-run pilot conclusion, including this one's, is inside it. What does reproduce: the assault is scripted (onset 166/167/166s), and the e007/e010 damage split is 50/50 in all three arms including the one that never fires at a turret -- so that attribution measures the wave script, not us. Also records that the viewer's include_external hypothesis in BACKLOG is dead (it defaults true and is threaded through unchanged).
4.6 KiB
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
§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 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.