port: duration confirmed at 0.2 percent, window refuted, loop start now an explicit field

They timed the wraps instead of converting them -- a probe stamping read_offset
on arrival, three wraps observed, each from its own loop_end to its own
loop_start, both contexts wrapping at the same instant. Cycle 61.81 s against the
61.93 authored here: 0.2 percent, from a wall clock between decoder events versus
an autocorrelation that never touched the wave.

The window is wrong: loop_start is 11.6 percent into the stream, about ten
seconds, so this export has the right duration over the wrong window -- replaying
the intro every cycle and omitting the tail the game plays.

Not re-cut, on their instruction: the exact start is unmeasured and linearity is
refuted by a 4.4 percent rate variation within one stream. But loop_end_s alone
silently asserted a start of zero, so the entry gains loop_start_s, authored as
0.0 and flagged wrong, with -ss applied before -t so the pair is (start,
duration). Proved before it is needed: loop_start_s=10 yields -ss 10 -t 61.93 and
a 61.930 s output. Restored to 0.0, export byte-unchanged.

My smooth-join check gains a use I could not have anticipated: it explains why a
wrong ten-second window went unheard, because a cut near a zero crossing is
smooth wherever it falls.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N7FiFFFwbvG2uxdcEh8HyF
This commit is contained in:
Sylpheed port agent
2026-08-30 10:07:07 +00:00
parent ffe0280679
commit 500924be5c
3 changed files with 103 additions and 2 deletions

View File

@@ -9,7 +9,7 @@ dies, which is what this file is for.
<!-- INDEX: generated by tools/port/index-decisions -- do not hand-edit -->
137 sections. Search this before re-deriving anything.
138 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)
@@ -148,6 +148,7 @@ dies, which is what this file is for.
* [The dead-press check was passing by luck, and the luck ran out](#the-dead-press-check-was-passing-by-luck-and-the-luck-ran-out)
* [Independent confirmation of the 1.5 MB cap — the mechanism, not just the conclusion](#independent-confirmation-of-the-15-mb-cap--the-mechanism-not-just-the-conclusion)
* [The loop is a runtime field, the two readings conflict, and the port keeps what it shipped](#the-loop-is-a-runtime-field-the-two-readings-conflict-and-the-port-keeps-what-it-shipped)
* [The duration is confirmed and the window is wrong — and the start is now a visible field](#the-duration-is-confirmed-and-the-window-is-wrong--and-the-start-is-now-a-visible-field)
<!-- /INDEX -->
## P0 — the exporter, 2026-08-28
@@ -7916,3 +7917,55 @@ locator aliases.
in both cases the output was internally consistent and structured, and in both the
tell was in the rows that **agreed** — my confirming half read impossibly too, and
their control was passing a problem it never had to solve.
## The duration is confirmed and the window is wrong — and the start is now a visible field
They stopped *converting* the runtime fields and **timed** them instead: a probe
tailing the Apu debug log, stamping `read_offset` on arrival, watching **three**
wraps — each from its own `loop_end` to its own `loop_start`, with **both
contexts wrapping at the same instant every time**.
| | |
|---|---|
| observed cycle | 61.56 s, 62.06 s → **61.81 s** |
| authored here | **61.93 s** |
| difference | **0.2 %** |
✅ **The length is settled**, and by instruments sharing nothing: a wall clock
between decoder events against an autocorrelation that never touched the wave.
Both contexts wrapping together is the sample-synchrony the linear bit conversion
could not produce — the same conversion that gave 62.34 and 63.29 s for two stems
that must be synchronous, and so refuted itself.
🔴 **The window is wrong.** `loop_start` is at 3.6 M bits — **11.6 % of the
stream, about ten seconds** — not the 0.25 s their earlier tracking gave. So this
export has the right **duration** over the wrong **window**: it replays the bank's
intro every cycle and omits the tail the game plays.
📌 **My smooth-join check has a second use I could not have anticipated.** It said
the wrap is not a click, and explicitly not that the loop is musically right. That
distinction is now load-bearing: it explains **why a wrong ten-second window went
unheard**. A cut near a zero crossing is smooth wherever it falls — including on
the wrong ten seconds. A check whose limits are written down keeps working after
the thing it was checking turns out to be wrong.
### Not re-cut — and the assumption is now a field
Their instruction is to wait: the exact start is **not measured**. Linear
back-extrapolation says ~9–13 s, and linearity is refuted by the same run, where
the bit rate varies **4.4 %** within one stream.
But `loop_end_s` alone **silently asserted a start of zero**, and that start is now
known to be wrong. So the entry gains `loop_start_s`, authored as **0.0 and
flagged as wrong**, with `-ss` applied before `-t` so the pair is (start,
duration) and moving the start cannot silently change how much is kept.
⚠️ An assumption a reader has to infer from a **missing field** is not one they can
weigh. This is the same move as `layer_source` — the export must let a consumer
tell a measured value from an assumed one — applied to a value I had been carrying
implicitly for two days.
✅ The new path is **proved before it is needed**: with `loop_start_s = 10.0` the
command carries `-ss 10 -t 61.93` and the output stays 61.930 s — a window, not a
truncation. Restored to 0.0; the export is byte-unchanged. When the start is
measured this is a one-value edit, not a code change.