From 2dba970c2983a62ba94c19df83d70b9d609edf3c Mon Sep 17 00:00:00 2001 From: sylph-decoder Date: Mon, 31 Aug 2026 02:54:46 +0000 Subject: [PATCH] re: the dialog id to pak-entry join is not positional -- hypothesis refuted GP_DIALOG has exactly 140 entries against the table's 70 records, a 2:1 ratio that would make the unbound join an ordering question. It does not hold: adjacent pairing gives identical element-name sets on 2 of 65 pairs, halves pairing on 0. GP_TITLE's language pairs share element sets exactly, so identical sets are the signature there; in GP_DIALOG almost nothing matches. Residual and unexplained: the only two adjacent pairs that DO match are entries 0/1 and 2/3, and 2/3 is the DIFFICULTY build. A reading I am not asserting: dialog text may be baked into language-specific sprites, which would explain the 63 by construction but leaves the 2 needing their own explanation. Not tested. The join stays unbound; positional ordering is now ruled out, which narrows where to look next. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v --- .../examples/dialog_pairing.rs | 47 +++++++++++++++++++ .../examples/dialog_pak_shape.rs | 29 ++++++++++++ docs/re/data/difficulty-is-a-dialog.txt | 33 +++++++++++++ 3 files changed, 109 insertions(+) create mode 100644 crates/sylpheed-formats/examples/dialog_pairing.rs create mode 100644 crates/sylpheed-formats/examples/dialog_pak_shape.rs diff --git a/crates/sylpheed-formats/examples/dialog_pairing.rs b/crates/sylpheed-formats/examples/dialog_pairing.rs new file mode 100644 index 00000000..6a44b687 --- /dev/null +++ b/crates/sylpheed-formats/examples/dialog_pairing.rs @@ -0,0 +1,47 @@ +//! Are `GP_DIALOG`'s 140 entries adjacent EN/JP pairs, one per dialog record? +//! +//! The dialog table has 70 records and the archive has 140 entries. If the +//! pairing is adjacent — (0,1), (2,3), … — then dialog index = entry / 2, and the +//! unbound id-to-entry join becomes an ordering question rather than a search. +//! +//! Test: for each pair, compare the SET of element names. GP_TITLE's EN/JP pairs +//! share their sprite sets exactly except for the title art (4/7), so identical +//! sets are the signature of a language pair. +//! +//! cargo run -p sylpheed-formats --example dialog_pairing +use sylpheed_formats::{pak::PakArchive, ui_layout}; +use std::collections::BTreeSet; +use std::path::PathBuf; + +fn names(ar: &PakArchive, i: usize) -> Option> { + let by = ar.read(&ar.entries()[i]).ok()?; + let b = ui_layout::parse_build(&by)?; + Some(b.elements.iter().map(|e| e.name.clone()).collect()) +} + +fn main() { + let root = PathBuf::from(std::env::var("SYLPHEED_DISC").expect("SYLPHEED_DISC")); + let ar = PakArchive::open(root.join("dat/GP_DIALOG.pak")).expect("GP_DIALOG"); + let n = ar.entries().len(); + let (mut adj_same, mut adj_diff, mut skipped) = (0, 0, 0); + for k in (0..n).step_by(2) { + match (names(&ar, k), names(&ar, k + 1)) { + (Some(a), Some(b)) => { + if a == b { adj_same += 1; println!(" identical pair: entries {k}/{}", k+1) } else { adj_diff += 1 } + } + _ => skipped += 1, + } + } + println!("ADJACENT pairing (2k, 2k+1): identical {adj_same} differing {adj_diff} unreadable {skipped}"); + // rival hypothesis: halves, (i, i+70) + let (mut h_same, mut h_diff, mut h_skip) = (0, 0, 0); + for k in 0..n / 2 { + match (names(&ar, k), names(&ar, k + n / 2)) { + (Some(a), Some(b)) => { + if a == b { h_same += 1 } else { h_diff += 1 } + } + _ => h_skip += 1, + } + } + println!("HALVES pairing (i, i+70): identical {h_same} differing {h_diff} unreadable {h_skip}"); +} diff --git a/crates/sylpheed-formats/examples/dialog_pak_shape.rs b/crates/sylpheed-formats/examples/dialog_pak_shape.rs new file mode 100644 index 00000000..7e0e4cfd --- /dev/null +++ b/crates/sylpheed-formats/examples/dialog_pak_shape.rs @@ -0,0 +1,29 @@ +//! How is `GP_DIALOG.pak` organised? Testing whether dialog id maps positionally. +//! +//! The dialog table gives name -> id (70 records, `DLG_SELECT_DIFFICULTY` = 2000) +//! and the disc gives a unique four-button build at GP_DIALOG entries 2/3. Nothing +//! joins them. If the archive were laid out in table order, or in id order, the +//! join would be positional — this checks. +//! +//! cargo run -p sylpheed-formats --example dialog_pak_shape +use sylpheed_formats::{pak::PakArchive, ui_layout}; +use std::path::PathBuf; + +fn main() { + let root = PathBuf::from(std::env::var("SYLPHEED_DISC").expect("SYLPHEED_DISC")); + let ar = PakArchive::open(root.join("dat/GP_DIALOG.pak")).expect("GP_DIALOG"); + let n = ar.entries().len(); + let mut builds = 0; + let mut with_btn = 0; + for e in ar.entries() { + let Ok(by) = ar.read(e) else { continue }; + if let Some(b) = ui_layout::parse_build(&by) { + builds += 1; + if b.elements.iter().any(|el| el.name.contains("btn")) { + with_btn += 1; + } + } + } + println!("entries {n}, parse as builds {builds}, of those with a btn element {with_btn}"); + println!("dialog table has 70 records; 70 x 2 (EN/JP) = 140"); +} diff --git a/docs/re/data/difficulty-is-a-dialog.txt b/docs/re/data/difficulty-is-a-dialog.txt index e3c48a0d..c8d2556e 100644 --- a/docs/re/data/difficulty-is-a-dialog.txt +++ b/docs/re/data/difficulty-is-a-dialog.txt @@ -112,3 +112,36 @@ # ⚠️ WHAT IS STILL NOT BOUND: id 2000 -> a pak entry. The table gives name -> id # and the disc gives a unique four-button build; nothing found so far connects the # two. The tie is uniqueness of geometry plus the oracle capture, not a pointer. + +################################################################################ +# ❌ REFUTED: the id -> pak-entry join is NOT positional. 2026-08-31. +# +# GP_DIALOG.pak has exactly **140 entries** and the dialog table has exactly **70 +# records** — a 2:1 ratio that looks like one EN/JP pair per dialog, which would +# make the unbound join an ordering question rather than a search. Tested, and it +# does not hold: +# +# ADJACENT pairing (2k, 2k+1) identical element-name sets: 2 of 65 +# HALVES pairing (i, i+70) identical element-name sets: 0 of 65 +# (5 pairs unreadable — entries that do not parse as builds) +# +# GP_TITLE's language pairs share their element sets exactly (except 4/7, the +# title art), so identical sets are the signature of a pair there. In GP_DIALOG +# almost nothing matches, so **the 2:1 ratio is not established as a language +# pairing** and no positional rule connects id 2000 to entries 2/3. +# +# 📌 RESIDUAL OBSERVATION, recorded because it is odd rather than because it is +# understood: the only two adjacent pairs with identical element sets are +# **entries 0/1 and 2/3** — and 2/3 is the DIFFICULTY build. Whatever makes those +# two structurally uniform in an archive where 63 of 65 pairs are not, this does +# not explain. +# +# ⚠️ A plausible reading I am NOT asserting: dialog text may be baked into +# language-specific sprites, which would make EN/JP entries differ in element +# names by construction. That is consistent with the 63, and it is one +# measurement away from being tested — but it is not tested here, and the 2 that +# DO match would then need their own explanation. +# +# => The join stays unbound. Table gives name -> id; disc gives a unique build; +# the tie is uniqueness plus the oracle capture. Positional ordering is now +# ruled out as the missing pointer, which narrows where to look next.