The corpus recorded that some unit fields the disc leaves defaulted inherit from a sibling: Size_Y from Size_X, FCSRange from RadarRange, DefencePoint from AttackVesselPoint. Size_Y was marked the one to trust, on 9/9 support across 7 independent ships, and it is restated in INDEX.md. The premise is false. These fields are not defaulted -- they are on disc for 113-114 of 114 unit tables -- and Size_Y DIFFERS from Size_X in 90 of them. The mechanism, cross-tabulating "legacy reader missed it" against "equal on disc": pair seen+differ seen+equal miss+differ miss+equal Size_Y / Size_X 90 0 0 24 FCSRange / RadarRange 54 0 1 58 DefencePoint / AttackVesselPoint 51 0 1 61 seen+equal is 0 for all three: a value shared with a sibling is ALWAYS invisible to the string-pool reader, because the pool stores each distinct string once. And the reader almost never misses a value that differs. So "the missing value equals the sibling's" was true BY CONSTRUCTION -- the rule re-derived the very condition that made the field go missing. That is why the support looked perfect: it could not fail on the cases it was fitted to. The two miss+differ cells are its real wrong predictions, both named: UN_e104_ADAN_Carrier DefencePoint is 0.2 (rule says 0.003), and UN_e011_ADAN_Attacker_B_HF_Wayne FCSRange is 3000.0 (rule says 6000.0). Retracted in unit-struct-runtime.md (original reasoning kept below the correction), live-unit-definitions.md and INDEX.md. Pinned by a disc test that asserts the seen+equal cells stay zero, so the mechanism itself is guarded, not just the counts. Artifact: examples/sibling_rule_check.rs. This one was found by my own check after the subagent assigned to it stalled. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PMRJjbxLqZtsb5Vb7KunPE
62 lines
2.7 KiB
Rust
62 lines
2.7 KiB
Rust
//! Does the legacy reader miss a field precisely when its value is shared?
|
|
//!
|
|
//! The corpus records four "sibling default" rules (`Size_Y` inherits `Size_X`,
|
|
//! `FCSRange` inherits `RadarRange`, …) used to recover values for units never
|
|
//! visited at runtime. If the rules are really a *deduplication artefact*, then
|
|
//! the legacy reader should report the field absent exactly when the two values
|
|
//! are equal on disc — and never otherwise.
|
|
use sylpheed_formats::{IdxdObject, PakArchive};
|
|
|
|
fn main() {
|
|
let disc = std::env::var("SYLPHEED_DISC").expect("set SYLPHEED_DISC");
|
|
let arc = PakArchive::open(format!("{disc}/dat/GP_MAIN_GAME_E.pak")).expect("pak");
|
|
let pairs = [
|
|
("Size_Y", "Size_X"),
|
|
("FCSRange", "RadarRange"),
|
|
("DefencePoint", "AttackVesselPoint"),
|
|
];
|
|
// legacy-absent x equal-on-disc, as a 2x2 table per pair.
|
|
let mut tally = [[[0usize; 2]; 2]; 3];
|
|
for e in arc.entries() {
|
|
let Ok(bytes) = arc.read(e) else { continue };
|
|
if !IdxdObject::is_idxd(&bytes) {
|
|
continue;
|
|
}
|
|
let Ok(obj) = IdxdObject::parse(&bytes) else { continue };
|
|
let Some(generic) = obj.record("Generic") else { continue };
|
|
if generic.get("Size_X").is_none() {
|
|
continue;
|
|
}
|
|
for (i, (field, sibling)) in pairs.iter().enumerate() {
|
|
let (Some(a), Some(b)) = (generic.get(field), generic.get(sibling)) else {
|
|
continue;
|
|
};
|
|
let legacy_absent = obj.get_f32(field).is_none();
|
|
tally[i][usize::from(legacy_absent)][usize::from(a == b)] += 1;
|
|
// The only cases where the rule PREDICTS WRONG: the reader misses
|
|
// the field and the two values differ, so "inherit the sibling"
|
|
// substitutes a number the disc contradicts.
|
|
if legacy_absent && a != b {
|
|
println!(
|
|
" rule-wrong: {:08x} {field} = {a} but {sibling} = {b} (ID {:?})",
|
|
e.name_hash,
|
|
obj.get_raw("ID")
|
|
);
|
|
}
|
|
}
|
|
}
|
|
println!("{:<14} {:>10} {:>10} {:>10} {:>10}", "pair", "seen+diff", "seen+eq", "MISS+diff", "MISS+eq");
|
|
for (i, (field, sibling)) in pairs.iter().enumerate() {
|
|
println!(
|
|
"{:<14} {:>10} {:>10} {:>10} {:>10}",
|
|
format!("{field}/{sibling}").chars().take(14).collect::<String>(),
|
|
tally[i][0][0],
|
|
tally[i][0][1],
|
|
tally[i][1][0],
|
|
tally[i][1][1]
|
|
);
|
|
}
|
|
println!("\n'MISS+diff' > 0 refutes 'the reader only misses shared values'.");
|
|
println!("'seen+eq' > 0 refutes 'a shared value is always invisible'.");
|
|
}
|