diff --git a/AGENTS.md b/AGENTS.md index 033a390..25a7717 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -286,3 +286,15 @@ Context: 0.17.10 installed cleanly on both ends (`4bb0f4a`) and produced a high- - [x] Update operational docs and installer contract tests for the new baseline. - [x] Run focused calibration, installer, and runtime checks. - [x] Push clean semver `0.17.11` for installed client/server testing. + +## 0.17.12 Sync-Only Audio Marker Continuity Checklist + +Context: 0.17.11 installed cleanly on both ends (`092c03a`) and fixed the constant browser-visible offset: raw activity start was `-17.0ms`, median coded skew was `+13.1ms`, and no server planner freeze/drop counters moved. The run still failed because only 5 coded pairs were usable and the last two had weak confidence (`0.58`, `0.33`) while the client log showed repeated microphone stale/superseded drops. The remaining sync blocker is audio-marker continuity, not another constant offset. + +- [x] Keep 0.17.12 scoped to sync establishment; do not change video freshness or server freshness ceilings. +- [x] Stop using latest-only policy for microphone uplink packets; preserve oldest fresh audio chunks so speech/pulses stay continuous. +- [x] Keep microphone queue age bounded at `400ms` so continuity does not become unbounded backlog. +- [x] Apply the same bounded audio-continuity policy to the synthetic sync-probe audio queue. +- [x] Update contract tests to encode the new audio continuity policy. +- [x] Run focused client queue/probe contracts and package checks. +- [ ] Push clean semver `0.17.12` for installed client/server testing. diff --git a/Cargo.lock b/Cargo.lock index d8bb354..e9c4c7b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1652,7 +1652,7 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] name = "lesavka_client" -version = "0.17.11" +version = "0.17.12" dependencies = [ "anyhow", "async-stream", @@ -1686,7 +1686,7 @@ dependencies = [ [[package]] name = "lesavka_common" -version = "0.17.11" +version = "0.17.12" dependencies = [ "anyhow", "base64", @@ -1698,7 +1698,7 @@ dependencies = [ [[package]] name = "lesavka_server" -version = "0.17.11" +version = "0.17.12" dependencies = [ "anyhow", "base64", diff --git a/client/Cargo.toml b/client/Cargo.toml index f99c99a..8f2dcb3 100644 --- a/client/Cargo.toml +++ b/client/Cargo.toml @@ -4,7 +4,7 @@ path = "src/main.rs" [package] name = "lesavka_client" -version = "0.17.11" +version = "0.17.12" edition = "2024" [dependencies] diff --git a/client/src/app/uplink_media.rs b/client/src/app/uplink_media.rs index 61f48b5..945ac28 100644 --- a/client/src/app/uplink_media.rs +++ b/client/src/app/uplink_media.rs @@ -423,9 +423,9 @@ const VIDEO_UPLINK_QUEUE: crate::uplink_fresh_queue::FreshQueueConfig = #[cfg(not(coverage))] const AUDIO_UPLINK_QUEUE: crate::uplink_fresh_queue::FreshQueueConfig = crate::uplink_fresh_queue::FreshQueueConfig { - capacity: 16, + capacity: 64, max_age: Duration::from_millis(400), - policy: crate::uplink_fresh_queue::FreshQueuePolicy::LatestOnly, + policy: crate::uplink_fresh_queue::FreshQueuePolicy::DrainOldest, }; #[cfg(not(coverage))] diff --git a/client/src/sync_probe/capture.rs b/client/src/sync_probe/capture.rs index e750248..2a592d1 100644 --- a/client/src/sync_probe/capture.rs +++ b/client/src/sync_probe/capture.rs @@ -50,9 +50,9 @@ const PROBE_VIDEO_QUEUE: FreshQueueConfig = FreshQueueConfig { #[cfg(any(not(coverage), test))] const PROBE_AUDIO_QUEUE: FreshQueueConfig = FreshQueueConfig { - capacity: 32, + capacity: 64, max_age: Duration::from_millis(400), - policy: crate::uplink_fresh_queue::FreshQueuePolicy::LatestOnly, + policy: crate::uplink_fresh_queue::FreshQueuePolicy::DrainOldest, }; #[cfg(any(not(coverage), test))] diff --git a/common/Cargo.toml b/common/Cargo.toml index b252dfe..4f04824 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lesavka_common" -version = "0.17.11" +version = "0.17.12" edition = "2024" build = "build.rs" diff --git a/server/Cargo.toml b/server/Cargo.toml index a33e620..94bf844 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -10,7 +10,7 @@ bench = false [package] name = "lesavka_server" -version = "0.17.11" +version = "0.17.12" edition = "2024" autobins = false diff --git a/testing/tests/client_uplink_freshness_contract.rs b/testing/tests/client_uplink_freshness_contract.rs index 222dd64..f12bdc6 100644 --- a/testing/tests/client_uplink_freshness_contract.rs +++ b/testing/tests/client_uplink_freshness_contract.rs @@ -82,7 +82,12 @@ fn microphone_uplink_queue_freshness_budget_stays_within_live_audio_window() { max_age_ms <= 400, "AUDIO_UPLINK_QUEUE max_age is {max_age_ms}ms; keep it <= 400ms for live calls" ); - assert_queue_policy(block, "AUDIO_UPLINK_QUEUE", "LatestOnly"); + assert_queue_policy(block, "AUDIO_UPLINK_QUEUE", "DrainOldest"); + let capacity = parse_queue_capacity(block, "AUDIO_UPLINK_QUEUE"); + assert!( + capacity <= 64, + "AUDIO_UPLINK_QUEUE capacity is {capacity}; keep audio continuity bounded" + ); } #[test] @@ -107,12 +112,12 @@ fn sync_probe_video_queue_uses_same_freshness_budget() { } #[test] -fn sync_probe_audio_queue_uses_live_latest_only_policy() { +fn sync_probe_audio_queue_preserves_bounded_marker_continuity() { let block = queue_block(SYNC_PROBE_CAPTURE_SRC, "PROBE_AUDIO_QUEUE"); let max_age_ms = parse_queue_max_age_ms(block, "PROBE_AUDIO_QUEUE"); assert!( max_age_ms <= 400, - "PROBE_AUDIO_QUEUE max_age is {max_age_ms}ms; keep probe audio from preserving stale timing anchors" + "PROBE_AUDIO_QUEUE max_age is {max_age_ms}ms; keep probe audio continuity bounded" ); - assert_queue_policy(block, "PROBE_AUDIO_QUEUE", "LatestOnly"); + assert_queue_policy(block, "PROBE_AUDIO_QUEUE", "DrainOldest"); }