port: the contract I read is 3185 lines shorter than the contract
docs/port/HANDOFF.md on main is 926 lines, last touched9ca1eb5on 2026-08-29. The live one is 4111 lines at27938aa, +3930/-745 across 96 commits I have never read, several of them addressed to the port by name. The Decoder writes HANDOFF on origin/auto/no-disc-and-menu-captures; main is a hundred-odd commits behind it; I open main's copy every iteration as instructed. So the rule meant to prevent this cannot detect it. tools/port/blocked-provenance recovers each row's derivation from history rather than memory -- git log -S on the row's key phrase -- and all 27 open rows derive from9ca1eb5, because HANDOFF-on-main has not moved. A constant cannot separate a fresh row from a rotten one. Withdrawn in BLOCKED.md: 'HANDOFF has not moved in four milestones' was missing the qualifier that carried its meaning. The tool's first version silently missed its own known positive: P6 looping vs712cac8, whose 9.44 s answer this port already ships. 'looping' did not stem to 'loop', 'menu' was stoplisted, and a >=2-shared-words threshold dropped the rest. The threshold was the defect -- two common words outscored one rare one -- so ranking is now by log(N/df) with no cutoff at all, and the control passes at rank 1 of 7 without touching the stoplist. Every discard is counted: struck rows, sub-rank pairs, stoplisted words. Same rule applied to check-claims, which now reports the 40 occurrences it suppresses; the Decoder reached it the same day from the opposite failure, a silent suppression path making a clean run unfalsifiable. The reading list found two open rows already answered: the plate's pulse period (120, not 105) and the main menu having no idle self-return, which refutes the B row's own reasoning. Refutation attempted on '+0x08 is the loop length', the claim the port was about to build on. It survives: their falsifier re-run on my own read of the disc gives 0 violations in 1781 records, and on the eight records this port animates their table reproduces cell for cell. Adopted -- screen.rs exports loop_length_units and ScreenView._loop_period prefers it, announcing any disagreement rather than silently resolving it. The value does not change: authored/timing.json already had 120 from a wall-clock measurement, so a disc field and an emulator stopwatch agree while sharing no instrument. Two asks filed: the field is exposed in no public API on any ref, so the port reads four bytes it should not own; and eleven focus records declare the same 120-unit cycle while only the plate is authored to animate, which is behavioural and not mine to infer. Every asserting check passes; oracle RMSEs unchanged, as 120 == 120 predicts. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N7FiFFFwbvG2uxdcEh8HyF
This commit is contained in:
@@ -108,10 +108,44 @@ pub struct FocusElement {
|
||||
pub keyframes: Vec<Keyframe>,
|
||||
}
|
||||
|
||||
/// A nested record's declared cycle length, or `None` if the span is not one.
|
||||
///
|
||||
/// Guarded rather than trusted: the magic is checked and the header must fit,
|
||||
/// because an offset that has drifted returns a plausible number otherwise.
|
||||
fn record_loop_units(bundle: &[u8], off: usize, size: usize) -> Option<u32> {
|
||||
let span = bundle.get(off..off.checked_add(size)?)?;
|
||||
if span.len() < 12 || &span[..4] != b"RATC" {
|
||||
return None;
|
||||
}
|
||||
Some(u32::from_be_bytes(span[8..12].try_into().ok()?))
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct Focus {
|
||||
/// The `.rat` leaf this came from, e.g. `ptbtn01f.rat`.
|
||||
pub record: String,
|
||||
/// The record header's `+0x08`: **where the cycle restarts**, in keyframe
|
||||
/// units — which is not the same thing as the last keyframe's time.
|
||||
///
|
||||
/// `ptbtn00f`, the `PRESS Ⓐ` plate's glow, ramps 0→80→0 over **105** units
|
||||
/// inside a **120**-unit cycle and rests dark for the remaining 15. Deriving
|
||||
/// the period from the largest keyframe time — what the port did until now —
|
||||
/// runs it 14 % fast and deletes the dark rest entirely.
|
||||
///
|
||||
/// Decoded by the Decoder (`07e93ce`, `docs/re/structures/ui-record-loop-length.md`,
|
||||
/// delivered in HANDOFF `27938aa`) and **re-run here before adoption**, with
|
||||
/// their falsifier and their non-triviality control:
|
||||
/// `cargo run -p sylpheed-export --example record_loop_control`. Disc-wide
|
||||
/// 1 781 timed records, 92.3 % exact, 7.7 % hold, **0 declaring less than
|
||||
/// their own last pose**; on the eight records this port animates, seven
|
||||
/// exact and `ptbtn00f` the one hold.
|
||||
///
|
||||
/// ⚠️ Read here rather than through `sylpheed_formats` because the field is
|
||||
/// exposed in **no public API on any ref** — it lives in an example and a
|
||||
/// test. `parse_build` publishes each record's `(offset, size)`, so this is
|
||||
/// four big-endian bytes at a documented offset inside a span whose magic is
|
||||
/// checked, not a second decoder. **Delete it the day the crate exposes it.**
|
||||
pub loop_length_units: Option<u32>,
|
||||
/// Back-to-front, in the leaf's own declaration order.
|
||||
pub elements: Vec<FocusElement>,
|
||||
}
|
||||
@@ -453,7 +487,11 @@ pub fn export_build(
|
||||
Ok(if fes.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(Focus { record: rec.to_string(), elements: fes })
|
||||
Some(Focus {
|
||||
record: rec.to_string(),
|
||||
loop_length_units: record_loop_units(bundle, off, size),
|
||||
elements: fes,
|
||||
})
|
||||
})
|
||||
};
|
||||
|
||||
@@ -510,7 +548,11 @@ pub fn export_build(
|
||||
});
|
||||
}
|
||||
if !fes.is_empty() {
|
||||
focus = Some(Focus { record: rec, elements: fes });
|
||||
focus = Some(Focus {
|
||||
record: rec,
|
||||
loop_length_units: record_loop_units(bundle, off, size),
|
||||
elements: fes,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user