media: migrate early zero video offset

This commit is contained in:
Brad Stein 2026-05-01 19:49:23 -03:00
parent 23002bbbfa
commit cdaf79bc49
2 changed files with 34 additions and 2 deletions

View File

@ -221,4 +221,4 @@ Context: 0.16.x proved that queue tweaks and static calibration cannot guarantee
- 2026-05-01: Added `GetUpstreamSync` RPC, `lesavka-relayctl upstream-sync`, launcher diagnostics text, and mirrored-probe before/after planner snapshots so 0.17 probe runs report the exact planner state under test.
- 2026-05-01: Validation green: `cargo test -p lesavka_server --lib --bins`, `cargo test -p lesavka_testing`, `cargo test -p lesavka_client --bins --lib`, and targeted installer/RPC/layout contracts.
- 2026-05-01: First installed 0.17.0 mirrored browser probe on client/server commit `3920e0a` failed honestly: planner reported fresh live state (`live_lag_ms=10`, `skew_ms=+20.7`) but browser-observed paired pulses showed audio late by median `+349.1ms`, p95 `429.1ms`, with 6 video freezes/skew drops. Replayed artifact after analyzer hardening now reports `gross_failure` instead of false raw-start `catastrophic_failure`.
- 2026-05-01: Patch follow-up models the observed MJPEG/UVC browser egress delta by defaulting video playout offset to `+350ms` and preserving the 1s freshness ceiling. Raw activity-start evidence is now ignored for verdict/calibration when it disagrees with paired pulses that are already failing directly.
- 2026-05-01: Patch follow-up models the observed MJPEG/UVC browser egress delta by defaulting video playout offset to `+350ms` and preserving the 1s freshness ceiling. Raw activity-start evidence is now ignored for verdict/calibration when it disagrees with paired pulses that are already failing directly. Existing early-0.17 `audio=0/video=0` factory/env calibration files migrate to the new `video=+350ms` default on load.

View File

@ -245,7 +245,8 @@ fn migrate_legacy_snapshot(mut state: CalibrationSnapshot) -> CalibrationSnapsho
.contains("loaded upstream A/V calibration defaults");
let untouched_legacy_audio = (matches!(
state.default_audio_offset_us,
LEGACY_FACTORY_MJPEG_AUDIO_OFFSET_US
FACTORY_MJPEG_AUDIO_OFFSET_US
| LEGACY_FACTORY_MJPEG_AUDIO_OFFSET_US
| PREVIOUS_FACTORY_MJPEG_AUDIO_OFFSET_US
| PREVIOUS_TUNED_MJPEG_AUDIO_OFFSET_US
) || clamped_previous_baseline)
@ -486,6 +487,37 @@ mod tests {
});
}
#[test]
fn load_migrates_early_zero_video_factory_mjpeg_baseline() {
let file = NamedTempFile::new().expect("temp calibration file");
std::fs::write(
file.path(),
r#"
profile="mjpeg"
default_audio_offset_us=0
default_video_offset_us=0
active_audio_offset_us=0
active_video_offset_us=0
source="factory"
confidence="factory"
detail="loaded upstream A/V calibration defaults"
"#,
)
.expect("early zero calibration seed");
let path = file.path().to_string_lossy().to_string();
temp_env::with_var("LESAVKA_CALIBRATION_PATH", Some(path.as_str()), || {
let runtime = Arc::new(UpstreamMediaRuntime::new());
let store = CalibrationStore::load(runtime.clone());
let state = store.current();
assert_eq!(state.active_audio_offset_us, 0);
assert_eq!(state.default_audio_offset_us, 0);
assert_eq!(state.active_video_offset_us, 350_000);
assert_eq!(state.default_video_offset_us, 350_000);
assert_eq!(state.source, "factory");
assert_eq!(runtime.playout_offsets(), (350_000, 0));
});
}
#[test]
fn load_keeps_manual_legacy_sized_calibration() {
let file = NamedTempFile::new().expect("temp calibration file");