fix(k1): stabilize live recovery and media admission

This commit is contained in:
DCCONSTRUCTIONS
2026-08-22 00:03:01 +03:00
parent 7217244886
commit eaad9deda1
29 changed files with 1645 additions and 199 deletions
+63
View File
@@ -326,6 +326,7 @@ def test_live_rerun_process_and_close_failure_preserve_capture_then_recover(
allow_second_bridge = threading.Event()
second_bridge_ready = threading.Event()
recovery_confirmed = threading.Event()
raw_capture_completed = threading.Event()
raw_sequences: list[int] = []
should_stop_before_explicit_stop: list[bool] = []
confirmed_attempts: list[int] = []
@@ -389,6 +390,7 @@ def test_live_rerun_process_and_close_failure_preserve_capture_then_recover(
assert second_bridge_ready.wait(timeout=2.0)
raw_sequences.append(10)
enqueue(_captured_live_point_cloud(10)) # type: ignore[operator]
raw_capture_completed.set()
assert recovery_confirmed.wait(timeout=2.0)
while not should_stop(): # type: ignore[operator]
@@ -409,6 +411,7 @@ def test_live_rerun_process_and_close_failure_preserve_capture_then_recover(
)
assert recovery_confirmed.wait(timeout=3.0)
assert raw_capture_completed.wait(timeout=3.0)
snapshot = runtime.snapshot()
assert snapshot["phase"] == "live"
assert snapshot["source_ready"] is True
@@ -510,6 +513,66 @@ def test_live_latest_point_cloud_survives_pose_and_perception_pressure(
runtime.close()
def test_live_pose_is_published_during_continuous_point_cloud_pressure(
monkeypatch: pytest.MonkeyPatch,
tmp_path: Path,
) -> None:
producer_started = threading.Event()
producer_finished = threading.Event()
pose_published_during_pressure = threading.Event()
class SlowPointCloudBridge(MetricRuntimeBridgeStub):
def process(self, envelope: object) -> None:
if isinstance(envelope, DecodedPointCloudView):
# Keep another PCL waiting in the latest-wins slot. The
# scheduler must still admit pose while pressure continues.
time.sleep(0.01)
elif (
isinstance(envelope, DecodedPoseView)
and not producer_finished.is_set()
):
pose_published_during_pressure.set()
super().process(envelope)
def fake_capture_mqtt(
_host: str,
_out_dir: Path,
**callbacks: object,
) -> dict[str, object]:
callbacks["on_clock_established"]() # type: ignore[operator]
callbacks["on_ready"]() # type: ignore[operator]
enqueue = callbacks["on_message_recorded"]
producer_started.set()
for index in range(300):
enqueue(_captured_live_point_cloud(index * 2 + 1)) # type: ignore[operator]
enqueue(_captured_live_pose(index * 2 + 2)) # type: ignore[operator]
time.sleep(0.001)
producer_finished.set()
should_stop = callbacks["should_stop"]
while not should_stop(): # type: ignore[operator]
time.sleep(0.005)
return {"message_count": 600}
monkeypatch.setattr(runtime_module, "capture_mqtt", fake_capture_mqtt)
runtime = VisualizationRuntime(
bridge_factory=lambda **kwargs: SlowPointCloudBridge(kwargs["metrics"]), # type: ignore[arg-type]
normalizer=normalize_k1_message,
)
runtime.start_live(
"192.168.1.50",
tmp_path / "pose-fairness",
duration_seconds=None,
project_name="POSEFAIRNESS001",
)
assert producer_started.wait(timeout=2.0)
assert producer_finished.wait(timeout=2.0)
runtime.stop(wait_seconds=2.0)
runtime.close()
assert pose_published_during_pressure.is_set()
@pytest.mark.parametrize("attempt", [5, 1025, 10**100])
def test_live_rerun_recovery_backoff_saturates(attempt: int) -> None:
assert runtime_module._rerun_recovery_backoff_seconds(attempt) == 5.0 # noqa: SLF001