formats: what opt links, measured - a record-to-record reference, focus is one use of it

Two readings were on record and both were wrong in different directions: the
structure doc called it "normal state -> focused state" from a single example,
and the backlog called it "refuted as focus; unexplained otherwise".

Classified every link reachable from a declaration table: 1467 links, and ALL
1467 resolve to a RATC child of their own bundle, ALL are .rat -> .rat, none
dangle and none self-link. 1076 (73%) match the <stem>f focus pattern; the other
391 are chains between effect records - px_bunk_eff01 -> pjex_eff -> pjex_eff07,
pveff01 -> pjeff02 -> pjeff21 - which also explains why only 227 targets are
themselves declared elements: the middle of a chain is, the end is not.

So `opt ` is a record-to-record reference within the bundle, and focus is its
commonest use rather than its meaning.

Coverage is stated rather than glossed: the bundles hold 18718 raw `opt ` tags
against the 1467 classified, because opt_link reads the first tag of a DECLARED
element's record. Roughly 92% of occurrences sit deeper in the chains (or are
byte coincidences - the scan is unaligned) and are untested. The numbers are
asserted so the answer cannot drift back into an anecdote.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PMRJjbxLqZtsb5Vb7KunPE
This commit is contained in:
Sylpheed RE agent
2026-08-24 04:09:18 +00:00
parent f160b416ff
commit d9a2229217
2 changed files with 199 additions and 0 deletions

View File

@@ -0,0 +1,155 @@
//! What does the `.rat` record's `opt ` link actually point at?
//!
//! `ui-rat-layout.md` reads it as *normal state → focused state*, from one
//! example: `pgpbtn00.rat` links to `pgpbtn00f.rat`. The backlog carries the
//! opposite verdict — "refuted as focus; unexplained otherwise" — with no number
//! behind either. This settles it by classifying **every** `opt ` link on the
//! disc, so the answer is a distribution rather than an anecdote.
//!
//! Four questions per link, in order of how much they would explain:
//! 1. is the target `<source stem>f.<ext>` — the focus pattern?
//! 2. is the target another element of the SAME build?
//! 3. is it a RATC child of the bundle (a resource rather than an element)?
//! 4. otherwise: what do the leftovers look like?
use std::collections::{HashMap, HashSet};
use std::path::{Path, PathBuf};
use sylpheed_formats::{pak::PakArchive, ratc, ui_layout};
fn disc_root() -> Option<PathBuf> {
if let Ok(p) = std::env::var("SYLPHEED_DISC") {
let p = PathBuf::from(p);
if p.join("dat").is_dir() {
return Some(p);
}
}
let default = Path::new(
"/home/fabi/RE - Project Sylpheed/Project Sylpheed - Arc of Deception (USA, Europe) (En,Ja)",
);
if default.join("dat").is_dir() {
return Some(default.to_path_buf());
}
None
}
fn for_each_build(root: &Path, mut f: impl FnMut(&str, &[u8])) {
let mut paks: Vec<PathBuf> = std::fs::read_dir(root.join("dat"))
.expect("dat/")
.flatten()
.map(|e| e.path())
.filter(|p| p.extension().and_then(|s| s.to_str()) == Some("pak"))
.collect();
paks.sort();
for p in &paks {
let name = p.file_name().unwrap().to_string_lossy().to_string();
let Ok(arc) = PakArchive::open(p) else { continue };
for e in arc.entries() {
let Ok(bytes) = arc.read(e) else { continue };
if ratc::is_ratc(&bytes) {
f(&name, &bytes);
}
}
}
}
#[test]
fn every_opt_link_on_the_disc_is_classified() {
let Some(root) = disc_root() else {
eprintln!("SKIP: extracted disc not found (set SYLPHEED_DISC to enable)");
return;
};
let (mut links, mut focus_pattern, mut same_build, mut ratc_child) = (0usize, 0, 0, 0);
// `opt_link` returns the FIRST `opt ` tag in a record. If records can carry
// several, every count here understates - so count the tags themselves in
// the raw bundle rather than trusting the parser's one-per-record view.
let mut opt_tags = 0usize;
let mut self_link = 0usize;
let mut ext_pairs: HashMap<(String, String), usize> = HashMap::new();
let mut leftovers: Vec<String> = Vec::new();
for_each_build(&root, |pak, bytes| {
let Some(build) = ui_layout::parse_build(bytes) else {
return;
};
if build.from_fallback {
return;
}
let names: HashSet<String> = build
.elements
.iter()
.map(|e| e.name.to_ascii_lowercase())
.collect();
let kids: HashSet<String> = ratc::parse(bytes)
.unwrap_or_default()
.into_iter()
.map(|c| c.name.to_ascii_lowercase())
.collect();
opt_tags += bytes.windows(4).filter(|w| *w == b"opt ").count();
for el in &build.elements {
let Some(target) = el.focus_link.as_ref() else {
continue;
};
links += 1;
let src = el.name.to_ascii_lowercase();
let tgt = target.to_ascii_lowercase();
let se = src.rsplit_once('.').map(|(_, e)| e.to_string()).unwrap_or_default();
let te = tgt.rsplit_once('.').map(|(_, e)| e.to_string()).unwrap_or_default();
*ext_pairs.entry((se, te)).or_default() += 1;
if tgt == src {
self_link += 1;
}
let is_focus = src
.rsplit_once('.')
.map(|(stem, ext)| format!("{stem}f.{ext}") == tgt)
.unwrap_or(false);
if is_focus {
focus_pattern += 1;
}
if names.contains(&tgt) {
same_build += 1;
}
if kids.contains(&tgt) {
ratc_child += 1;
}
if !is_focus && leftovers.len() < 14 {
leftovers.push(format!(
"{pak}: {} -> {}{}",
el.name,
target,
if names.contains(&tgt) { " [declared element]" } else { "" }
));
}
}
});
eprintln!("opt links on the disc: {links} raw `opt ` tags in the bundles: {opt_tags}");
eprintln!(" target is <stem>f.<ext> (the focus pattern): {focus_pattern}");
eprintln!(" target is another element of the same build: {same_build}");
eprintln!(" target is a RATC child of the bundle: {ratc_child}");
eprintln!(" target is the element ITSELF: {self_link}");
let mut ep: Vec<_> = ext_pairs.iter().collect();
ep.sort_by_key(|(_, n)| std::cmp::Reverse(**n));
eprintln!(" source-ext -> target-ext: {:?}", &ep[..ep.len().min(8)]);
for l in &leftovers {
eprintln!(" NOT the f-pattern: {l}");
}
assert!(links > 0, "no opt links found — the sweep is broken");
// MEASURED 2026-08-24 and asserted, because both prior readings were wrong
// in different directions: `opt ` is not "the focused state" (that fits 73 %
// of links, not all of them) and it is not "unexplained" either — EVERY
// link resolves to a RATC child of its own bundle, and every one is
// .rat -> .rat.
assert_eq!(links, 1467, "the disc has 1467 opt links");
assert_eq!(ratc_child, links, "an opt link does not resolve to a RATC child");
assert_eq!(
ext_pairs.get(&("rat".to_string(), "rat".to_string())).copied(),
Some(links),
"an opt link points at something other than a .rat record"
);
assert_eq!(self_link, 0, "a record links to itself");
assert_eq!(focus_pattern, 1076, "the f-pattern share moved");
}

View File

@@ -452,3 +452,47 @@ that a menu draws for its buttons.
**Still open:** whether the focused state is marked anywhere *else* — the `.rat`
record, the RATC child stream, or (as with the paint order) only in the game's
code. This closes the declaration table, not the question.
## 🟡 What `opt ` links — measured over the whole disc (2026-08-24)
Two readings were on record and both were wrong in different directions: this
file called it *normal state → focused state* from a single example
(`pgpbtn00.rat → pgpbtn00f.rat`), and the backlog called it "refuted as focus;
unexplained otherwise". Classifying **every** link reachable from a declaration
table (`tests/ui_opt_link_disc.rs`) gives a distribution instead:
| | |
|---|---|
| `opt ` links classified | **1 467** |
| resolve to a **RATC child of the same bundle** | **1 467 — all of them** |
| `.rat` → `.rat` | **1 467 — all of them** |
| match the focus pattern `<stem>f.<ext>` | **1 076 (73 %)** |
| whose target is *also* a declared element | 227 |
| link to themselves | **0** |
So `opt ` is a **record→record reference within the bundle**: a record naming
another record it uses. It never dangles, never points at a sprite, and never
points at itself. Focus is the commonest *use* of that mechanism, not its
meaning.
**What the other 27 % are: chains.** The non-`f` targets are effect records
referring to further effect records, and following them shows depth:
```
px_bunk_eff01.rat → pjex_eff.rat → pjex_eff07.rat
px_bunk_eff01.rat → pjnet_bg.rat → pjnet_loop1.rat
pveff01.rat → pjeff02.rat → pjeff21.rat
pjeff03.rat → pjeff03_sub.rat
```
Note the middle name in each chain *is* a declared element while the third is
not — which is exactly why only 227 targets are elements.
⚠️ **Coverage, stated because it bounds all of the above.** The bundles contain
**18 718** raw `opt ` byte-tags against the **1 467** links classified here.
`opt_link()` reads the **first** tag of the record belonging to a **declared
element**, so roughly 92 % of occurrences sit on records deeper in the chain (or
are byte coincidences in binary data — the scan is unaligned). What those say is
untested. The claims above are about the links a screen's element table can
reach, which is what a compositor follows; they are not a statement about every
`opt ` in the file.