revert(mesh): withdraw the neighbourhood anchor -- it regressed the e106 twin mirror
The neighbourhood anchor (f18d591) and its refinement (27a0701) took cross-container inconsistency from 125 to 51 with coverage unchanged, and made e106 render as a destroyer rather than a slab. Both are reverted. ship::tests::static_assembly_matches_runtime_capture is gated on SYLPHEED_ISO, so it SKIPS in an ordinary cargo test -- which is why the regression was invisible in every suite run so far. With the ISO it fails: e106_bdy_01: static M row0 [-1.0, 0.0, 0.0] != captured [1.0, 0.0, 0.0] e106_bdy_01 and _02 are a mirrored pair whose two buffers hold the same geometry reflected in X, and BOTH resources currently decode to the SAME buffer (identical counts, span and mean_x). apply_twin_mirrors picks which instance to reflect from the sign of that mean_x, so which buffer wins flips the decision: before both twins mean_x = -66.83 -> mirror bdy_02 (matches the capture) after both twins mean_x = +66.83 -> mirror bdy_01 (contradicts it) Neither is right -- two resources sharing one decode is itself the bug and the mirror heuristic has been compensating. The capture is ground truth, so a change that contradicts it does not ship. The real fix must give each twin its own buffer first. Kept from the attempt: this test now also asserts the SET of static placements against the capture (allow-list {e303_wep_01} for vbase dedup), so extra placements can finally fail it -- the direction it could never fail in before. Docs, backlog, INDEX and the ignored test's message all corrected to say diagnosed-not-fixed rather than fixed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -20,7 +20,7 @@ Promote to a prose `structures/…md` file when a format needs behavioural notes
|
||||
| IXUD subtitle | 🟡/✅ | `sylpheed-formats/src/ixud.rs` + [movie link](movie-subtitle-link.md) | timed cues. **The movie↔subtitle↔voice link is solved — statically**, from the movie config record in `tables.pak` (schema `0x067025b9`), not from the running game as this row previously assumed: [101 movies mapped](captures/movie-subtitle-voice-map.csv), 94 with subtitles, 83 with voice, 21 with a telop overlay. 93 of 94 subtitle refs resolve in the language paks; **`SUBTITLE_S12B.tbl` is missing from all six languages** — a dangling reference on the disc. Naming is `SUBTITLE_<base>.tbl` / `VOICE_<base>` with six documented exceptions. The record's ~104 **script ids** are ❔ — positional pairing drifts by three because the IDXD pool dedupes repeated values |
|
||||
| Fonts (ttf/otf/ttc) | ✅ | `sylpheed-formats/src/font.rs` | standard OpenType, parsed via ttf-parser |
|
||||
| XBG7 mesh | 🟡/❔ | `sylpheed-formats/src/mesh.rs` + `tests/mesh_disc.rs` ([xbg7](structures/xbg7-mesh.md)) | weapons/props: declaration-driven variable stride (36 models), GPU-confirmed. **Stage containers: 5662 sub-models across 22 stages** via content-anchored grouped pools (`stage_models`). **Declined set now measured**: 6 294 resources, **5 480 decode (87.1 %), 814 declined** in 31/166 containers — and it is *not* "a few quantized hero bodies" but 492 `e*`, 142 `f*`, 73 `n*`, 23 `eff*` plus `*_dead` variants. The descriptor does **not** declare decodability (word[2] is a sub-mesh count; decoded and declined appear at every value), so the gap is the anchor scan, not an unread format flag — see [xbg7](structures/xbg7-mesh.md). **Silent mis-decodes also exist and are now measurable**: a resource shared across containers must decode to the same bounds, and **125 of 681 shared resources fail that check** with identical vertex/triangle counts — the decoder picked a different buffer of the same size. A majority vote across containers would resolve 104 of them (14 are 50/50), but that is 🟡 unvalidated beyond the one case with a render and a capture behind it |
|
||||
| Capital-ship part placement | ✅/🟡 | `sylpheed-formats/src/ship.rs` (static) + [runtime capture](ship-placement-runtime-capture.md) | Placement itself is **sound**: hull static-exact, validated against the `e106` runtime capture, and cross-id mounting is genuinely narrow (**2 pairs across 335 ships**). **The user-reported "ships assemble wrong" is NOT a placement bug** — it is an XBG7 **mis-decode** that makes one shared turret 100× too large in 3 of 14 containers ([backlog](BACKLOG.md), [xbg7](structures/xbg7-mesh.md)). Also open: `static_assembly_matches_runtime_capture` walks capture parts only, so **extra** static placements can never fail it |
|
||||
| Capital-ship part placement | ✅/🟡 | `sylpheed-formats/src/ship.rs` (static) + [runtime capture](ship-placement-runtime-capture.md) | Placement itself is **sound**: hull static-exact, validated against the `e106` runtime capture, and cross-id mounting is genuinely narrow (**2 pairs across 335 ships**). **The user-reported "ships assemble wrong" is NOT a placement bug** (a locality fix for it was written and withdrawn — it regressed the twin mirror) — it is an XBG7 **mis-decode** that makes one shared turret 100× too large in 3 of 14 containers ([backlog](BACKLOG.md), [xbg7](structures/xbg7-mesh.md)). Also open: `static_assembly_matches_runtime_capture` walks capture parts only, so **extra** static placements can never fail it |
|
||||
| Weapon fields defaulted on disc | ✅ | [runtime struct](structures/weapon-struct-runtime.md) · [DATA SHEET route](weapon-datasheet-runtime.md) | **Solved.** Canary maps guest RAM into `/dev/shm`, so the parsed `Weapon`/`Shell` objects are readable live; their layout is solved against disc ground truth (zero contradictions over 100+ records). All 126 weapons, exact numbers, no story progress needed — [4 393 values](captures/weapon-runtime-fields.csv) the disc does not carry. Supersedes the letter-bucket limit of the DATA SHEET route, which now serves as the independent cross-check |
|
||||
| Unit (craft/vessel) fields defaulted on disc | ✅/🟡 | [runtime struct](structures/unit-struct-runtime.md) | The parsed `unit\UN_*.tbl` definition object, vtable `0x820af844`, ≥`0x380` bytes, one per unit — **discovered, not assumed** (`unit_discover.py`), and distinguished from the spawned-entity class `0x820af030` by being one-per-ID and byte-constant within a run. Across runs only pointer words move — `--crosscheck` proves **no reported field offset is run-dependent** (two words, `+0x2c8`/`+0x2d0`, are stage-dependent and remain unidentified). 27 fields ✅ (21 units, 7 runs); the `Maneuver` block is **schema declaration order, 4 bytes/field, base `0x9c` with a two-slot gap after `AA_Roll_Min`** (29 anchors, 0 conflicts), which also pins 5 fields *no* disc record ever values. Angles are **radians at runtime, degrees on disc**. Unlike weapons, unit definitions are instantiated **per stage**, so coverage (21/110) grows by visiting missions — but a defaulted field is **not** a global constant: `Size_Y` provably inherits `Size_X` (7 independent units, 6 distinct values), and three more sibling rules are recorded ❔, recovering 65 values in units never visited — [values](captures/unit-runtime-fields.csv) |
|
||||
| Arsenal develop economy | ✅/❔ | [arsenal-develop-economy](arsenal-develop-economy.md) + [conditions](captures/arsenal-develop-conditions.csv) | The Arsenal reads `weapon.tbl` (item ids, in the 8-category display order) and `strings.tbl` (names, descriptions, and a **"Conditions to obtain"** block per item) out of `GP_HANGAR_ARSENAL.pak`. All **60** conditions are extracted: gates are stage completion, a predecessor item, or an **ace kill**; costs run 3 000–350 000 P and **20 items are free** once gated. `weapon.tbl`'s first record reproduces the in-game DATA SHEET exactly (Range D / Power E / Speed – / Weight 0.3 = Light / 4000 P) — later records are unreadable from the string pool alone because IDXD **dedupes repeated values**. Used to identify the save blob's index space, now **solved**: the blob follows **`strings.tbl`'s** order — the display order *plus* the cut items only the localisation file lists (`Adhesive Mine B2A`, `Ballista GSH`, …) — pinned by four hand-written probe saves (9 Stiletto, 21 Falcon, 39 Tomahawk, 48 Jamming System) and closing exactly at index 53. `weapon.tbl`'s id list is **not** the index space; that it is also 54 long is a coincidence, and the two agree only to index 32. The retail save's five unexplained owned entries are the cut items, shipped owned and never rendered |
|
||||
|
||||
Reference in New Issue
Block a user