From ced2f6fa3dc23741420fd062b427c53e931288e2 Mon Sep 17 00:00:00 2001 From: "Claude (auto-RE)" Date: Tue, 11 Aug 2026 23:15:22 +0000 Subject: [PATCH] re: the format layer is NOT exonerated -- assemble_ship draws a non-renderable volume Did the visual the backlog kept naming as the next step, and it overturns the conclusion. Rendering e106 from the static assembly and from the baked runtime capture: the capture has 8 placements, the static assembly 11 -- the same 8 plus e303_wep_01 x2 and a second e106_eng_01. In the render the destroyer sits inside a white slab that dwarfs it. That slab is e303_wep_01: 172 verts, 110 tris, bounds X[-1000,600] Y[-1050,1050] Z[-2400,2400] = 1600 x 2100 x 4800. A real e106 turret (wep_02_01) is 269x179x417 with 772 tris; the bridge is 105x76x305. So it is not a turret -- it reads as a collision/trigger volume, and whatever it is the game does not draw it: the e106 capture contains no e303_wep_01 at all. Why it was missed: assemble_ship treats every rou_* composite node as drawable, the cross-id mount is documented as intended, and the test asserts count("e303_wep_01") == 2. The capture's silence was explained as vbase dedup, but dedup would show one instance, not zero -- and the test walks capture parts looking them up in the static output, so EXTRA static placements cannot fail it. Same shape as the earlier include_external gap: a test that can only fail one way. Scope stated carefully: sweeping 335 ships for "ship-scale span with <400 tris" flags 20 ships and 58 placements over 28 resources, but ONLY the e106 case is proven (render + capture absence + geometry). Others may be legitimately large low-poly parts and need the same three checks. Co-Authored-By: Claude Opus 5 (1M context) --- docs/re/BACKLOG.md | 58 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/docs/re/BACKLOG.md b/docs/re/BACKLOG.md index b81f0bf6..f50fdcd4 100644 --- a/docs/re/BACKLOG.md +++ b/docs/re/BACKLOG.md @@ -150,3 +150,61 @@ comparison is no longer merely the next step — it is the only remaining one.** Render `e106` in the viewer beside `ship_render`'s output of the same `assemble_ship` result; if they agree, the bug is in neither and the original report needs re-grounding against a specific ship and a specific expectation. + +--- + +## ⚠️ The format layer is NOT exonerated — `assemble_ship` draws a non-renderable volume + +**Found 2026-08-11 by finally doing the visual**, which the notes above kept +naming as the next step. It overturns their conclusion. + +Render `e106` from the static assembly and from the baked runtime capture and +compare — `ship_render` does both: + +| | placements | parts | +|---|---|---| +| runtime capture (ground truth) | **8** | `bdy_01…04`, `brg_01`, `eng_01`, `eng_02`, `wep_02_01` | +| `assemble_ship(--static)` | **11** | the same 8, **plus `e303_wep_01` ×2** and a second `e106_eng_01` | + +The render makes it obvious: the destroyer sits inside a white slab that dwarfs +it ([capture](captures/e106-static-assembly-volume-bug.png)). That slab is +`e303_wep_01`, and its own geometry is: + +``` +e303_wep_01 172 verts, 110 tris bounds X[-1000, 600] Y[-1050, 1050] Z[-2400, 2400] 1600 x 2100 x 4800 +e106_wep_02_01 1002 verts, 772 tris 269 x 179 x 417 ← what a real e106 turret looks like +e106_brg_01 202 verts, 202 tris 105 x 76 x 305 +``` + +**110 triangles, perfectly round axis-aligned bounds, and bigger than the ship it +is mounted on.** That is not a turret. 🟡 It reads as a collision / trigger +volume, and ✅ whatever it is, **the game does not draw it**: the runtime capture +of e106 contains no `e303_wep_01` at all. + +### Why this was missed + +`assemble_ship` treats **every** `rou_*` node in the composite as a drawable +part, and the doc comment states the cross-id mount as intended behaviour — +`"INCLUDING repeated instances and cross-id turret mounts (rou_e303_wep_01_root +×2 on the e106 hull)"` — with +`ship::tests::static_assembly_matches_runtime_capture` asserting +`count("e303_wep_01") == 2`. The absence from the capture was explained away as +vbase dedup, but **dedup would show one instance, not zero**. + +The test cannot catch it either: it walks the capture's parts and looks each up +in the static output, so **extra** static placements are invisible to it. That is +the same shape of gap as the earlier `include_external` hypothesis — a test that +can only fail one way. + +### Scope, stated carefully + +Sweeping all 335 assembled ships for the signature *ship-scale span with under +400 triangles* flags **20 ships and 58 placements** over 28 distinct resources +(`e005_ant_*`, `f001_ant_*`, `f002_bdy_*`, `f301_barrel`, `f303_body`, +`e303_wep_01`, …). **Only the `e106`/`e303_wep_01` case is proven** — by render, +by capture absence, and by geometry. Some of the others may be legitimately large +low-poly parts, and each needs the same three checks before being called a bug. + +**Next:** decide the rule that separates drawable parts from volumes (candidates: +the node-name suffix, a descriptor flag, or the triangle-density heuristic), then +re-point `static_assembly_matches_runtime_capture` so it also fails on extras.