From fd34d350f25c63d0b6b6d72a8f44772fc9711cb6 Mon Sep 17 00:00:00 2001 From: "Claude (auto-RE)" Date: Wed, 12 Aug 2026 03:44:29 +0000 Subject: [PATCH] test: lock in the twin invariant -- 0 unrelated pairs disc-wide, 1 known collapse twin_mirror_audit applies the capture-derived rule to all 166 containers: of 34 equal-count twin pairs, 18 are exact X-mirrors, 15 related another way, 1 identical, 0 unrelated. Two calibration fixes were needed first (authored halves need a tolerance, and a mirrored pair may be stored in another vertex order). The one collapse, n206_01/_02, is a grouped-pool pair -- the path distinct assignment excludes -- so it names the next target. Added a disc-gated regression test; refreshed the stale ignore message on the consistency test. Co-Authored-By: Claude Opus 5 (1M context) --- .../sylpheed-formats/examples/find_mirror.rs | 44 +++++++ .../examples/twin_mirror_audit.rs | 110 ++++++++++++++++++ .../tests/mesh_consistency_disc.rs | 44 ++++++- docs/re/structures/xbg7-mesh.md | 30 +++++ 4 files changed, 227 insertions(+), 1 deletion(-) create mode 100644 crates/sylpheed-formats/examples/find_mirror.rs create mode 100644 crates/sylpheed-formats/examples/twin_mirror_audit.rs diff --git a/crates/sylpheed-formats/examples/find_mirror.rs b/crates/sylpheed-formats/examples/find_mirror.rs new file mode 100644 index 0000000..8914bc4 --- /dev/null +++ b/crates/sylpheed-formats/examples/find_mirror.rs @@ -0,0 +1,44 @@ +//! Does the container hold an X-mirrored copy of a resource's decoded buffer? +//! +//! The twin invariant (see `twin_mirror_audit`) flags `…_01`/`…_02` pairs that +//! decode to unrelated geometry. If the mirror of one twin's buffer exists +//! somewhere else in the container, that offset is where the other twin belongs +//! and the pair is a mis-anchor; if it does not exist, the pair is simply not a +//! mirrored pair. +//! +//! Usage: find_mirror ... +use sylpheed_formats::mesh::Xbg7Model; +use std::collections::HashSet; + +fn main() { + let a: Vec = std::env::args().collect(); + let bytes = std::fs::read(&a[1]).expect("container"); + let want: HashSet = a[2..].iter().cloned().collect(); + let models = Xbg7Model::models_named(&bytes, &want, &|| false); + let be = |at: usize| f32::from_be_bytes(bytes[at..at + 4].try_into().unwrap()); + + for m in &models { + let pos: Vec<[f32; 3]> = m.meshes.iter().flat_map(|s| s.positions.clone()).take(8).collect(); + if pos.len() < 8 { + continue; + } + let anchored = m.meshes[0].vbuf_offset.unwrap_or(0); + let (mut direct, mut mirror) = (Vec::new(), Vec::new()); + for o in (0..bytes.len().saturating_sub(12 + 8 * 24)).step_by(4) { + for (flip, out) in [(1.0f32, &mut direct), (-1.0f32, &mut mirror)] { + if (0..8).all(|k| { + let at = o + k * 24; + (be(at) - flip * pos[k][0]).abs() <= 1e-4 + && (be(at + 4) - pos[k][1]).abs() <= 1e-4 + && (be(at + 8) - pos[k][2]).abs() <= 1e-4 + }) { + out.push(o); + } + } + } + println!( + "{:<20} anchored 0x{anchored:x} direct copies {:x?} mirrored copies {:x?}", + m.name, direct, mirror + ); + } +} diff --git a/crates/sylpheed-formats/examples/twin_mirror_audit.rs b/crates/sylpheed-formats/examples/twin_mirror_audit.rs new file mode 100644 index 0000000..ecb9ade --- /dev/null +++ b/crates/sylpheed-formats/examples/twin_mirror_audit.rs @@ -0,0 +1,110 @@ +//! Do port/starboard twins decode to mirror images of each other? +//! +//! A runtime capture proved the container stores both halves of the `e106` hull +//! as separate, X-reflected buffers. That gives a **capture-free invariant**: +//! a `…_01`/`…_02` pair of equal vertex count should decode to geometry that is +//! an exact X-mirror — never to identical geometry (that is the collapse the +//! distinct-assignment fix targets), and never to something unrelated (that is a +//! mis-anchor no count-based metric can see). +//! +//! Usage: twin_mirror_audit +use sylpheed_formats::mesh::Xbg7Model; +use std::collections::BTreeMap; + +fn key(p: [f32; 3]) -> (i64, i64, i64) { + ( + (p[0] * 1e3).round() as i64, + (p[1] * 1e3).round() as i64, + (p[2] * 1e3).round() as i64, + ) +} + +/// Elementwise equality with a tolerance. Truncating keys is too strict for a +/// mirrored pair: the halves are authored, not bit-negated, so they differ in +/// the last digits and an exact key test reports them as unrelated. +fn near(p: [f32; 3], q: [f32; 3]) -> bool { + (0..3).all(|c| (p[c] - q[c]).abs() <= 1e-3 * (1.0 + q[c].abs())) +} + +fn main() { + let dir = std::env::args().nth(1).expect("resource3d dir"); + let mut files: Vec<_> = std::fs::read_dir(&dir) + .unwrap() + .flatten() + .map(|e| e.path()) + .filter(|p| p.extension().and_then(|s| s.to_str()) == Some("xpr")) + .collect(); + files.sort(); + + let (mut same, mut mirrored, mut unrelated, mut related) = (0usize, 0usize, 0usize, 0usize); + let mut examples: Vec = Vec::new(); + for f in &files { + let Ok(bytes) = std::fs::read(f) else { continue }; + let models = Xbg7Model::anchor_models_cancellable(&bytes, 0.0, &|| false); + let by_name: BTreeMap<&str, &Xbg7Model> = + models.iter().map(|m| (m.name.as_str(), m)).collect(); + for m in &models { + let Some(stem) = m.name.strip_suffix("_01") else { continue }; + let Some(t) = by_name.get(format!("{stem}_02").as_str()) else { continue }; + let a: Vec<[f32; 3]> = m.meshes.iter().flat_map(|s| s.positions.clone()).collect(); + let b: Vec<[f32; 3]> = t.meshes.iter().flat_map(|s| s.positions.clone()).collect(); + if a.len() != b.len() || a.is_empty() { + continue; + } + let ident = a.iter().zip(&b).all(|(p, q)| near(*p, *q)); + let mirr = a.iter().zip(&b).all(|(p, q)| near([-p[0], p[1], p[2]], *q)); + // A pair that is neither may still be RELATED: mirrored on another + // axis, or the same point cloud in a different vertex order. Only a + // pair that is none of these is evidence of a mis-anchor. + let mirr_y = a.iter().zip(&b).all(|(p, q)| near([p[0], -p[1], p[2]], *q)); + let mirr_z = a.iter().zip(&b).all(|(p, q)| near([p[0], p[1], -p[2]], *q)); + let set = |v: &Vec<[f32; 3]>| { + let mut s: Vec<_> = v.iter().map(|p| key(*p)).collect(); + s.sort_unstable(); + s + }; + let same_cloud = set(&a) == set(&b); + // …and the same point cloud after mirroring, for a pair whose + // halves are authored in different vertex order. + let mirrored_cloud = { + let am: Vec<[f32; 3]> = a.iter().map(|p| [-p[0], p[1], p[2]]).collect(); + set(&am) == set(&b) + }; + if !ident && !mirr && (mirr_y || mirr_z || same_cloud || mirrored_cloud) { + related += 1; + continue; + } + if ident { + same += 1; + if examples.len() < 6 { + examples.push(format!( + "identical: {} / {}_02 in {}", + m.name, + stem, + f.file_name().unwrap().to_string_lossy() + )); + } + } else if mirr { + mirrored += 1; + } else { + unrelated += 1; + if examples.len() < 6 { + examples.push(format!( + "unrelated: {} / {}_02 in {}", + m.name, + stem, + f.file_name().unwrap().to_string_lossy() + )); + } + } + } + } + println!("twin pairs of equal vertex count: {}", same + mirrored + unrelated + related); + println!(" exact X-mirror (expected) : {mirrored}"); + println!(" IDENTICAL (collapse) : {same}"); + println!(" related other way (Y/Z mirror, reordered): {related}"); + println!(" unrelated (mis-anchor?) : {unrelated}"); + for e in examples { + println!(" e.g. {e}"); + } +} diff --git a/crates/sylpheed-formats/tests/mesh_consistency_disc.rs b/crates/sylpheed-formats/tests/mesh_consistency_disc.rs index 845cb48..639a972 100644 --- a/crates/sylpheed-formats/tests/mesh_consistency_disc.rs +++ b/crates/sylpheed-formats/tests/mesh_consistency_disc.rs @@ -53,7 +53,7 @@ fn span(m: &Xbg7Model) -> Option<[i64; 3]> { } #[test] -#[ignore = "known-failing: 125 of 681 shared resources decode inconsistently. A neighbourhood anchor took this to 51 but regressed the e106 twin-mirror decision and was withdrawn — see docs/re/structures/xbg7-mesh.md"] +#[ignore = "known-failing: 62 of 714 shared resources decode inconsistently (was 125 of 681; distinct anchor assignment + the 0.42 connectivity cap fixed the rest). Note this metric is the WEAKER witness — a systematic mis-anchor is consistent — see docs/re/structures/xbg7-mesh.md"] fn shared_resources_decode_identically_in_every_container() { let Some(root) = disc_root() else { eprintln!("SKIP: extracted disc not found (set SYLPHEED_DISC to enable)"); @@ -102,3 +102,45 @@ fn shared_resources_decode_identically_in_every_container() { bad.len() ); } + +/// Port/starboard twins must not decode to the *same* buffer. +/// +/// A runtime capture showed the container stores both halves of the `e106` hull +/// as separate X-reflected buffers, so a `…_01`/`…_02` pair of equal vertex +/// count should come out mirrored (or related by another axis / vertex order) — +/// never identical, which is the collapse distinct assignment fixes. Disc-wide +/// this holds for every such pair except `n206`, whose twins are grouped-pool +/// resources (4 sub-meshes) and so are excluded from distinct assignment; that +/// one is the remaining known case, asserted explicitly so it cannot grow. +#[test] +fn twin_pairs_do_not_share_a_buffer() { + let Some(root) = disc_root() else { + eprintln!("SKIP: extracted disc not found (set SYLPHEED_DISC to enable)"); + return; + }; + let mut files: Vec = std::fs::read_dir(root.join("hidden/resource3d")) + .expect("resource3d/") + .flatten() + .map(|e| e.path()) + .filter(|p| p.extension().and_then(|s| s.to_str()) == Some("xpr")) + .collect(); + files.sort(); + + let mut collapsed: Vec = Vec::new(); + for f in &files { + let Ok(bytes) = std::fs::read(f) else { continue }; + let models = Xbg7Model::anchor_models_cancellable(&bytes, 0.0, &|| false); + let by_name: BTreeMap<&str, &Xbg7Model> = + models.iter().map(|m| (m.name.as_str(), m)).collect(); + for m in &models { + let Some(stem) = m.name.strip_suffix("_01") else { continue }; + let Some(t) = by_name.get(format!("{stem}_02").as_str()) else { continue }; + let (a, b) = (m.meshes[0].vbuf_offset, t.meshes[0].vbuf_offset); + if a.is_some() && a == b { + collapsed.push(format!("{}/{stem}_02 in {}", m.name, f.file_name().unwrap().to_string_lossy())); + } + } + } + collapsed.retain(|c| !c.starts_with("n206_01")); + assert!(collapsed.is_empty(), "twin pairs sharing one buffer: {collapsed:?}"); +} diff --git a/docs/re/structures/xbg7-mesh.md b/docs/re/structures/xbg7-mesh.md index ae2bd71..84d7f42 100644 --- a/docs/re/structures/xbg7-mesh.md +++ b/docs/re/structures/xbg7-mesh.md @@ -930,6 +930,36 @@ of one buffer, a resource landing on a **mirrored** copy would be a real defect and would look identical to a correct decode in every count-based metric. Only a capture (or the twin-pair invariant) can catch it. +### The twin invariant, checked disc-wide (2026-08-12) + +The capture gave a rule that needs no capture to apply: a `…_01`/`…_02` pair of +equal vertex count should decode to **mirrored** geometry, never to the same +buffer. `examples/twin_mirror_audit.rs` applies it to all 166 containers: + +| twin pairs of equal vertex count | 34 | +|---|---| +| exact X-mirror | **18** | +| related another way (Y/Z mirror, or the same cloud in another vertex order) | 15 | +| identical — a collapse | **1** | +| unrelated — no relation at all | **0** | + +Two calibration notes, because the first run of this audit got both wrong. +Comparing quantised keys **exactly** reported four false "unrelated" pairs +(`e101_eng_01/_02`): the halves are authored, not bit-negated, so they differ in +the last digits — a tolerance is required. And a mirrored pair may be stored in a +**different vertex order**, so the multiset has to be compared mirrored as well +as directly. With both fixed, nothing on the disc is unrelated. + +The single collapse is `n206_01`/`n206_02` (`Stage_S08`), both anchored at +`0x33b6e54` while the container holds a second direct copy at `0x342d984` and +mirrors at `0x33b7754`/`0x342e284`. It survives because both twins are +**grouped-pool** resources (4 sub-meshes), and distinct assignment excludes that +path — so this is the concrete next target, and the fix direction is to extend +distinctness across grouped models. + +`tests/mesh_consistency_disc.rs::twin_pairs_do_not_share_a_buffer` locks this in: +no twin pair may share a buffer, with `n206` the one asserted exception. + Not settled: `e106_brg_01_b_02` ≡ `e106_brg_01_l` (51 verts). A second 51-vertex `vbase` exists in the logs but is **not** from this container, and the container holds three near-identical 51-vertex runs, so the pair has no oracle yet.