port: move to formats-pin-2026-08-30 -- the voice export is complete
The late start was a second condition on the start filter, end - s < 1_500_000, only within one bank. ADV's predecessor trailer sits 3618816 B before end, so it was rejected and start fell back to anchor, a TOC offset rather than a stream boundary -- which is why it hit regions over 1.5 MB and never single-stream ones. ADV region 3114352 -> 3618816 B, streams 2 of 3 -> 3 of 3, complete, dropping zero chunks. S00A 1 of 3 -> 2 of 3 with the third digitally silent. The runtime no longer prints an incomplete line for either. Also fixes the warning crying wolf: S00A still read KNOWN INCOMPLETE over a 93.694 s stream of exact zeroes. Exported gains content_waves and the warning, console line and manifest field all key on kept < content rather than kept < present. Second time in two iterations this warning was wrong in the cautious direction -- over-warning is what makes the next real warning unreadable. S00A is a second movie in the predicted direction: kept went 1 -> 2 because a chunk that was a different duration now matches at 93.694 s. Not independent ground truth, but a different asset and the outcome was predicted first. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N7FiFFFwbvG2uxdcEh8HyF
This commit is contained in:
4
Cargo.lock
generated
4
Cargo.lock
generated
@@ -4627,7 +4627,7 @@ dependencies = [
|
||||
"image",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sylpheed-formats 0.1.0 (git+https://git.mc02.dev/fabi/Sylpheed.git?tag=formats-pin-2026-08-29d)",
|
||||
"sylpheed-formats 0.1.0 (git+https://git.mc02.dev/fabi/Sylpheed.git?tag=formats-pin-2026-08-30)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4651,7 +4651,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sylpheed-formats"
|
||||
version = "0.1.0"
|
||||
source = "git+https://git.mc02.dev/fabi/Sylpheed.git?tag=formats-pin-2026-08-29d#e2640338e149acc903fac551f400a5319950afb5"
|
||||
source = "git+https://git.mc02.dev/fabi/Sylpheed.git?tag=formats-pin-2026-08-30#c8d3a6a15d5feb0416b2b589cb8e0c442f7422d3"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"binrw",
|
||||
|
||||
@@ -81,7 +81,7 @@ license.workspace = true
|
||||
# geometry -- does NOT reach this port from here: `sylpheed-cli` builds from the
|
||||
# WORKSPACE crate, so the reference renderer stays unrotated until the tag lands
|
||||
# on `main`. This bump is for the parser, not for the renderer.
|
||||
sylpheed-formats = { git = "https://git.mc02.dev/fabi/Sylpheed.git", tag = "formats-pin-2026-08-29d" }
|
||||
sylpheed-formats = { git = "https://git.mc02.dev/fabi/Sylpheed.git", tag = "formats-pin-2026-08-30" }
|
||||
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
|
||||
@@ -208,6 +208,12 @@ pub struct Exported {
|
||||
/// Exists so a "known incomplete" warning fires on the gap and not on the
|
||||
/// mere presence of more than one stream.
|
||||
pub kept_waves: usize,
|
||||
/// How many of `sub_waves` carry SIGNAL. A dropped stream that is digitally
|
||||
/// silent is not missing content, and a warning that fires on it is crying
|
||||
/// wolf: `S00A`'s third chunk is 93.694 s of exact zeroes, so dropping it
|
||||
/// costs nothing and saying "KNOWN INCOMPLETE" over it would train a reader
|
||||
/// to ignore the one case that means something.
|
||||
pub content_waves: usize,
|
||||
/// What the runtime should do at the end of the file, where that was
|
||||
/// authored. `None` on a cue: a cue ends.
|
||||
pub loop_mode: Option<String>,
|
||||
@@ -353,6 +359,7 @@ pub fn export_cues<S: DiscSource + ?Sized>(
|
||||
loop_mode: None,
|
||||
sub_waves: 1,
|
||||
kept_waves: 1,
|
||||
content_waves: 1,
|
||||
});
|
||||
}
|
||||
Ok(done)
|
||||
@@ -523,6 +530,7 @@ pub fn export_bgm<S: DiscSource + ?Sized>(
|
||||
loop_mode: spec.r#loop.clone(),
|
||||
sub_waves: staged.len(),
|
||||
kept_waves: 1,
|
||||
content_waves: 1,
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -915,6 +923,7 @@ pub fn export_voice<S: DiscSource + ?Sized>(
|
||||
loop_mode: None,
|
||||
sub_waves: riffs.len(),
|
||||
kept_waves: staged.len(),
|
||||
content_waves: riffs.len() - silent.len(),
|
||||
}))
|
||||
}
|
||||
|
||||
|
||||
@@ -457,7 +457,7 @@ fn run_export(disc: &Path, out: &Path, authored_dir: &Path) -> Result<()> {
|
||||
// export is known to be missing audio the game plays, and
|
||||
// the failure sounds like success: one stream decodes to
|
||||
// clean dialogue, so nobody listening finds out.
|
||||
if a.kept_waves < a.sub_waves {
|
||||
if a.kept_waves < a.content_waves {
|
||||
warnings.push(format!(
|
||||
"{}: KNOWN INCOMPLETE. This region holds {} streams and the RUNNING \
|
||||
GAME DECODES ALL OF THEM CONCURRENTLY (Canary --xma_param_probe: \
|
||||
@@ -477,7 +477,7 @@ fn run_export(disc: &Path, out: &Path, authored_dir: &Path) -> Result<()> {
|
||||
describe(&a),
|
||||
a.kept_waves,
|
||||
a.sub_waves,
|
||||
if a.kept_waves < a.sub_waves { " -- KNOWN INCOMPLETE, see warnings" } else { "" }
|
||||
if a.kept_waves < a.content_waves { " -- KNOWN INCOMPLETE, see warnings" } else { "" }
|
||||
);
|
||||
audio.push(ManifestAudio::from(a));
|
||||
}
|
||||
@@ -517,7 +517,7 @@ impl From<audio::Exported> for ManifestAudio {
|
||||
why: a.why,
|
||||
peak_dbfs: a.peak_dbfs,
|
||||
duration_s: a.duration_s,
|
||||
incomplete: (a.kept_waves < a.sub_waves).then(|| {
|
||||
incomplete: (a.kept_waves < a.content_waves).then(|| {
|
||||
format!(
|
||||
"{} of {} streams. The running game decodes all {} concurrently. \
|
||||
Nothing in the audio reveals the gap -- what plays is clean dialogue. \
|
||||
|
||||
@@ -9,7 +9,7 @@ dies, which is what this file is for.
|
||||
|
||||
<!-- INDEX: generated by tools/port/index-decisions -- do not hand-edit -->
|
||||
|
||||
129 sections. Search this before re-deriving anything.
|
||||
130 sections. Search this before re-deriving anything.
|
||||
|
||||
* [P0 — the exporter, 2026-08-28](#p0--the-exporter-2026-08-28)
|
||||
* [P1 — Godot draws the screen, 2026-08-28](#p1--godot-draws-the-screen-2026-08-28)
|
||||
@@ -140,6 +140,7 @@ dies, which is what this file is for.
|
||||
* [Their stream assignment does not fit my region — weights NOT applied](#their-stream-assignment-does-not-fit-my-region--weights-not-applied)
|
||||
* [The resolver starts late, and my "duplicate tail" was a real stream all along](#the-resolver-starts-late-and-my-duplicate-tail-was-a-real-stream-all-along)
|
||||
* [The export knew the voice was incomplete; the runtime did not say so](#the-export-knew-the-voice-was-incomplete-the-runtime-did-not-say-so)
|
||||
* [The voice export is complete — new pin, and the cause was a "within one bank" cap](#the-voice-export-is-complete--new-pin-and-the-cause-was-a-within-one-bank-cap)
|
||||
|
||||
<!-- /INDEX -->
|
||||
## P0 — the exporter, 2026-08-28
|
||||
@@ -7542,3 +7543,55 @@ why is not the same story twice** and a single sentence cannot carry both.
|
||||
*true* only for the case it was written against. It is the failure mode of every
|
||||
generic warning, and it is harder to see than a wrong number because the sentence
|
||||
is well-formed and confident in both places.
|
||||
|
||||
## The voice export is complete — new pin, and the cause was a "within one bank" cap
|
||||
|
||||
`formats-pin-2026-08-30`. The cause of the late start was a second condition on
|
||||
the start filter: `end - s < 1_500_000`, *"only within one bank"*. `ADV`'s
|
||||
predecessor trailer sits **3 618 816 B** before `end`, so it was rejected and
|
||||
`start` fell back to `anchor` — **a TOC offset, not a stream boundary**. That is
|
||||
exactly why it hit regions over 1.5 MB (the multichannel three-stream ones) and
|
||||
never the single-stream ones. 17 of 95 movies took the fallback.
|
||||
|
||||
| | before | after |
|
||||
|---|---|---|
|
||||
| `ADV` region | 3 114 352 B | **3 618 816 B** |
|
||||
| `ADV` streams kept | 2 of 3 | **3 of 3 — complete** |
|
||||
| `S00A` streams kept | 1 of 3 | **2 of 3**, the third digitally silent |
|
||||
| `ADV` peak | −3.1 dBFS | −2.84 dBFS |
|
||||
|
||||
✅ **The voice export is now complete for both movies**, closing a defect that was
|
||||
open for this entire session — and my re-reading of the "duplicate tail" as a
|
||||
start-truncated simultaneous stream is what the fix confirms. `ADV` drops **zero**
|
||||
chunks; the runtime no longer prints its incomplete line.
|
||||
|
||||
### 🔴 And the incompleteness warning was crying wolf on `S00A`
|
||||
|
||||
With `ADV` fixed, `S00A` still read **KNOWN INCOMPLETE** at 2 of 3 — because its
|
||||
third chunk is **93.694 s of exact zeroes**. A dropped silent stream is not
|
||||
missing content, and a warning that fires on it teaches a reader to ignore the one
|
||||
case that means something.
|
||||
|
||||
`Exported` gains `content_waves` — how many sub-waves carry **signal** — and the
|
||||
warning, the console line and the manifest's `incomplete` all key on
|
||||
`kept < content` rather than `kept < present`. Both movies now report no gap,
|
||||
correctly.
|
||||
|
||||
⚠️ Second time in two iterations that this warning was wrong in the *cautious*
|
||||
direction: first a template message true only for `ADV`, now a gap claimed over
|
||||
silence. Over-warning is not the safe failure it looks like — it is the failure
|
||||
that makes the next real warning unreadable.
|
||||
|
||||
### A second movie, in the predicted direction
|
||||
|
||||
They note only `ADV` has external ground truth; the other 16 rest on their own
|
||||
sweep. **`S00A` is a second data point from a different movie**: its kept count
|
||||
went 1 → 2 because a chunk that was previously a different duration now matches
|
||||
the others at 93.694 s — exactly what restoring a truncated first stream
|
||||
predicts.
|
||||
|
||||
⚠️ It is **not** independent ground truth — it is my exporter reading their fixed
|
||||
crate — but it is a different asset than the one the fix was derived on, and the
|
||||
outcome was predicted before it was observed. Recorded as that and nothing more.
|
||||
|
||||
Oracle rows unmoved; MODDING rules pass.
|
||||
|
||||
Reference in New Issue
Block a user