Finishes #16 in the three places its earlier remedies missed. `tests/`: the last four local `disc_root()` copies now use `tests/common`, and with them goes the one real hardcoded fallback — `ui_keyframe_record_disc.rs` fell back to an absolute path on one machine, which made `unset SYLPHEED_DISC` a no-op there. Control: with the corpus absent that suite now finishes in 0.00s instead of 57.55s, so it skips rather than finding a disc of its own. `examples/`: seventeen examples defaulted to `/disc`, the mount point inside the CI container. Redundant there — `docker/ci/run` sets `SYLPHEED_DISC=/disc` — and wrong everywhere else, where a missing corpus turned into a file-not-found against a path that has never existed on the host. They now name the variable to set, like the other hundred examples already did. `docker/ci/run`: mount `$SYLPHEED_RES3D` and `$SYLPHEED_ISO` alongside the disc. Only the disc was mounted, so an in-container run sat out the res3d and iso suites while looking like a full one — the defect this issue is about, in the runner itself. Measured in the container on this desktop with all three corpora present: 45 suites / 377 passed / 0 failed / 14 ignored, and `sylpheed-corpus-report.txt` now reports PRESENT for all three rather than for the disc alone. Refs #16. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
124 lines
5.3 KiB
Rust
124 lines
5.3 KiB
Rust
//! Test the Decoder's UNTESTED reading of a residual they recorded as odd.
|
|
//!
|
|
//! `GP_DIALOG` holds 140 entries against a 70-record dialog table — a 2:1 ratio
|
|
//! that would make the id→entry join an ordering question. It does not hold:
|
|
//! adjacent pairing gives identical element-name sets on **2 of 65** pairs,
|
|
//! halves pairing on **0**. In `GP_TITLE` a language pair shares its element set
|
|
//! exactly, so identical sets are the signature there and almost nothing matches
|
|
//! here.
|
|
//!
|
|
//! The residual: the only two adjacent pairs that DO match are entries `0/1` and
|
|
//! `2/3` — and `2/3` is the DIFFICULTY build. Their plausible reading is that
|
|
//! dialog text is baked into language-specific sprites, so EN/JP entries differ
|
|
//! by construction. ⚠️ **They flagged it as untested and did not assert it**, and
|
|
//! it has a hole they named themselves: it would explain the 63 that differ and
|
|
//! leave the 2 that match needing their own explanation.
|
|
//!
|
|
//! This prints what the differences actually look like, so the reading is judged
|
|
//! against the names rather than accepted as plausible.
|
|
use std::collections::BTreeSet;
|
|
use sylpheed_formats::{pak, ratc, ui_layout};
|
|
|
|
fn main() {
|
|
let root =
|
|
std::env::var("SYLPHEED_DISC").expect("set SYLPHEED_DISC to the extracted disc root");
|
|
let ar = pak::PakArchive::open(format!("{root}/dat/GP_DIALOG.pak")).expect("GP_DIALOG.pak");
|
|
let sets: Vec<Option<BTreeSet<String>>> = ar
|
|
.entries()
|
|
.iter()
|
|
.map(|e| {
|
|
let by = ar.read(e).ok()?;
|
|
if !ratc::is_ratc(&by) {
|
|
return None;
|
|
}
|
|
let b = ui_layout::parse_build(&by)?;
|
|
Some(b.elements.iter().map(|el| el.name.clone()).collect())
|
|
})
|
|
.collect();
|
|
|
|
let (mut same, mut diff, mut pairs) = (0usize, 0usize, 0usize);
|
|
let mut shown = 0;
|
|
for i in (0..sets.len().saturating_sub(1)).step_by(2) {
|
|
let (Some(a), Some(b)) = (&sets[i], &sets[i + 1]) else {
|
|
continue;
|
|
};
|
|
pairs += 1;
|
|
if a == b {
|
|
same += 1;
|
|
println!(
|
|
" entries {i:>3}/{:<3} IDENTICAL sets, {} element(s)",
|
|
i + 1,
|
|
a.len()
|
|
);
|
|
continue;
|
|
}
|
|
diff += 1;
|
|
// The stage-dialog pairs, checked by name and by SPRITE COUNT. A
|
|
// translation of one dialog carries the same amount of text; a
|
|
// different stage does not. This is the Decoder's closing evidence for
|
|
// the 37 pairs that differ WITHOUT a button-count mismatch, re-derived
|
|
// here because it settles a bound I had recorded as unlikely to be
|
|
// tested -- and saying so is what got it tested.
|
|
if (10..=15).contains(&i) {
|
|
let sp = |x: &BTreeSet<String>| x.iter().filter(|n| n.ends_with(".t32")).count();
|
|
let stage = |x: &BTreeSet<String>| -> Vec<String> {
|
|
let mut v: Vec<String> = x
|
|
.iter()
|
|
.filter_map(|n| {
|
|
n.strip_prefix("pzstg")
|
|
.and_then(|r| r.get(..2))
|
|
.map(|s| s.to_string())
|
|
})
|
|
.collect();
|
|
v.sort();
|
|
v.dedup();
|
|
v
|
|
};
|
|
println!(
|
|
" entries {i:>3}/{:<3} stages {:?} vs {:?} sprites {} vs {}",
|
|
i + 1,
|
|
stage(a),
|
|
stage(b),
|
|
sp(a),
|
|
sp(b)
|
|
);
|
|
}
|
|
if shown < 3 {
|
|
shown += 1;
|
|
let only_a: Vec<_> = a.difference(b).cloned().collect();
|
|
let only_b: Vec<_> = b.difference(a).cloned().collect();
|
|
println!(
|
|
" entries {i:>3}/{:<3} differ: {} only-in-first, {} only-in-second",
|
|
i + 1,
|
|
only_a.len(),
|
|
only_b.len()
|
|
);
|
|
println!(" first : {:?}", &only_a[..only_a.len().min(4)]);
|
|
println!(" second : {:?}", &only_b[..only_b.len().min(4)]);
|
|
}
|
|
}
|
|
// 🔴 THE DECISIVE DETAIL, not the impressionistic one. Two languages of one
|
|
// dialog cannot differ in BUTTON COUNT. If adjacent entries do, they are
|
|
// different dialogs and the whole adjacent-pairing premise is wrong -- which
|
|
// is a stronger statement than "the language reading is untested".
|
|
let btns = |s: &Option<BTreeSet<String>>| -> usize {
|
|
s.as_ref()
|
|
.map_or(0, |x| x.iter().filter(|n| n.contains("btn")).count())
|
|
};
|
|
let mut mismatched = 0;
|
|
for i in (0..sets.len().saturating_sub(1)).step_by(2) {
|
|
if sets[i].is_none() || sets[i + 1].is_none() {
|
|
continue;
|
|
}
|
|
if btns(&sets[i]) != btns(&sets[i + 1]) {
|
|
mismatched += 1
|
|
}
|
|
}
|
|
println!("\n adjacent pairs whose BUTTON COUNTS differ: {mismatched}");
|
|
println!(" A language pair cannot. Every one of these is two different dialogs.");
|
|
println!("\n {pairs} adjacent pair(s): {same} identical, {diff} differing");
|
|
println!(" Their reading -- text baked into language-specific sprites -- predicts");
|
|
println!(" the differing names look SYSTEMATIC (a locale suffix, a parallel set).");
|
|
println!(" Judge it against the names above rather than against its plausibility.");
|
|
}
|