from __future__ import annotations import importlib.util import sys from pathlib import Path from types import ModuleType import pytest def _worker_module() -> ModuleType: worker_root = Path(__file__).parents[1] / "experiments" / "perception" / "worker" path = worker_root / "run_e9_multirate_perception.py" sys.path.insert(0, str(worker_root)) try: spec = importlib.util.spec_from_file_location("e9_multirate_worker", path) assert spec is not None and spec.loader is not None module = importlib.util.module_from_spec(spec) sys.modules[spec.name] = module spec.loader.exec_module(module) return module finally: sys.path.pop(0) def _profile_path() -> Path: return ( Path(__file__).parents[1] / "experiments" / "perception" / "worker" / "e9_multirate_perception_profile.json" ) def _semantic(worker: ModuleType, *, index: int, session_seconds: float) -> object: return worker.SemanticResult( frame_index=index, source_frame_index=1000 + index, session_seconds=session_seconds, completed_monotonic=10.0, completion_age_ms=180.0, mask_sha256="a" * 64, class_pixels={"road": 100}, class_fractions={"road": 0.5}, ) def test_e9_profile_pins_independent_bounded_rates() -> None: worker = _worker_module() profile, digest = worker._read_profile(_profile_path()) assert len(digest) == 64 assert profile["replay"]["detector_queue_capacity"] == 2 assert profile["replay"]["semantic_queue_capacity"] == 1 assert profile["replay"]["semantic_sample_every_frames"] == 5 assert profile["replay"]["semantic_ttl_ms"] == 750.0 def test_e9_semantic_binding_exposes_fresh_stale_and_unavailable() -> None: worker = _worker_module() semantic = _semantic(worker, index=5, session_seconds=20.0) assert ( worker._semantic_binding( None, frame_session_seconds=20.1, ttl_ms=750.0, )["status"] == "unavailable" ) assert ( worker._semantic_binding( semantic, frame_session_seconds=20.7, ttl_ms=750.0, )["status"] == "fresh" ) assert ( worker._semantic_binding( semantic, frame_session_seconds=20.8, ttl_ms=750.0, )["status"] == "stale" ) def test_e9_latest_semantic_rejects_time_reversal() -> None: worker = _worker_module() latest = worker.LatestSemantic() latest.publish(_semantic(worker, index=5, session_seconds=20.0)) with pytest.raises(RuntimeError, match="not monotonic"): latest.publish(_semantic(worker, index=4, session_seconds=19.9))