fix(replay): serve admitted AI overlays without revalidation
This commit is contained in:
@@ -1,7 +1,12 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import importlib.util
|
||||
import json
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
from pathlib import Path
|
||||
from types import SimpleNamespace
|
||||
|
||||
@@ -15,6 +20,44 @@ from k1link.compute.integrated_perception import (
|
||||
)
|
||||
|
||||
|
||||
def _write_result_descriptor(
|
||||
results_root: Path,
|
||||
*,
|
||||
session_id: str,
|
||||
created_at_utc: str,
|
||||
) -> Path:
|
||||
identity = {
|
||||
"schema_version": integrated_module.IDENTITY_SCHEMA,
|
||||
"job_id": f"recorded-camera-{'1' * 24}",
|
||||
"session_id": session_id,
|
||||
}
|
||||
identity_sha256 = hashlib.sha256(
|
||||
json.dumps(
|
||||
identity,
|
||||
ensure_ascii=False,
|
||||
sort_keys=True,
|
||||
separators=(",", ":"),
|
||||
).encode()
|
||||
).hexdigest()
|
||||
result_id = f"e10-integrated-perception-{identity_sha256}"
|
||||
root = results_root / result_id
|
||||
root.mkdir()
|
||||
(root / "result.json").write_text(
|
||||
json.dumps(
|
||||
{
|
||||
"schema_version": integrated_module.RESULT_SCHEMA,
|
||||
"result_id": result_id,
|
||||
"identity": identity,
|
||||
"identity_sha256": identity_sha256,
|
||||
"acceptance_state": "accepted",
|
||||
"publication_scope": "recorded-integrated-realtime-qualification-only",
|
||||
"created_at_utc": created_at_utc,
|
||||
}
|
||||
)
|
||||
)
|
||||
return root
|
||||
|
||||
|
||||
def _worker_modules() -> tuple[object, object]:
|
||||
root = Path(__file__).resolve().parents[1] / "experiments" / "perception"
|
||||
worker = root / "worker"
|
||||
@@ -41,7 +84,7 @@ def _worker_modules() -> tuple[object, object]:
|
||||
sys.path.pop(0)
|
||||
|
||||
|
||||
def test_integrated_overlay_catalog_validation_is_memoized_until_publication(
|
||||
def test_integrated_overlay_recovers_admission_from_sealed_cache_without_revalidation(
|
||||
tmp_path: Path,
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
@@ -51,32 +94,37 @@ def test_integrated_overlay_catalog_validation_is_memoized_until_publication(
|
||||
cache_root = tmp_path / "cache"
|
||||
for root in (jobs_root, results_root, lidar_packs_root):
|
||||
root.mkdir()
|
||||
job_root = jobs_root / "job-1"
|
||||
job_root.mkdir()
|
||||
first_result = results_root / f"e10-integrated-perception-{'a' * 64}"
|
||||
first_result.mkdir()
|
||||
|
||||
validation_calls = {"job": 0, "result": 0}
|
||||
job = SimpleNamespace(session_id="session-1")
|
||||
|
||||
def validate_job(_root: Path) -> object:
|
||||
validation_calls["job"] += 1
|
||||
return job
|
||||
|
||||
def validate_result(_job_root: Path, candidate: Path, _packs: Path) -> object:
|
||||
validation_calls["result"] += 1
|
||||
return SimpleNamespace(
|
||||
accepted=True,
|
||||
publication_scope="recorded-integrated-realtime-qualification-only",
|
||||
created_at_utc=candidate.name,
|
||||
result_id=candidate.name,
|
||||
result = _write_result_descriptor(
|
||||
results_root,
|
||||
session_id="session-1",
|
||||
created_at_utc="2026-07-29T12:00:00Z",
|
||||
)
|
||||
payload = b"RRF2sealed-overlay"
|
||||
recording_id = "recording-1"
|
||||
cache = cache_root / "session-1" / result.name
|
||||
cache.mkdir(parents=True)
|
||||
output = cache / f"{recording_id}.rrd"
|
||||
output.write_bytes(payload)
|
||||
(cache / f"{recording_id}.rrd.cache.json").write_text(
|
||||
json.dumps(
|
||||
{
|
||||
"schema_version": integrated_module.OVERLAY_CACHE_SCHEMA,
|
||||
"renderer_version": integrated_module.OVERLAY_RENDERER_VERSION,
|
||||
"result_id": result.name,
|
||||
"recording_id": recording_id,
|
||||
"byte_length": len(payload),
|
||||
"sha256": hashlib.sha256(payload).hexdigest(),
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
def reject_revalidation(*_args: object, **_kwargs: object) -> object:
|
||||
raise AssertionError("sealed presentation cache must not revalidate source artifacts")
|
||||
|
||||
monkeypatch.setattr(integrated_module, "validate_camera_compute_job", validate_job)
|
||||
monkeypatch.setattr(
|
||||
integrated_module,
|
||||
"validate_integrated_perception_result",
|
||||
validate_result,
|
||||
reject_revalidation,
|
||||
)
|
||||
store = IntegratedPerceptionOverlayStore(
|
||||
jobs_root=jobs_root,
|
||||
@@ -86,13 +134,75 @@ def test_integrated_overlay_catalog_validation_is_memoized_until_publication(
|
||||
ffmpeg_path=tmp_path / "ffmpeg",
|
||||
)
|
||||
|
||||
assert store._latest("session-1") is not None
|
||||
assert store._latest("session-1") is not None
|
||||
assert validation_calls == {"job": 1, "result": 1}
|
||||
assert (
|
||||
store.render(
|
||||
"session-1",
|
||||
application_id="nodedc_mission_core_recorded",
|
||||
recording_id=recording_id,
|
||||
)
|
||||
== payload
|
||||
)
|
||||
admission = json.loads((cache_root / "session-1" / "admission.json").read_text())
|
||||
assert admission["result_id"] == result.name
|
||||
assert store.status("session-1", recording_id=recording_id) == {
|
||||
"state": "ready",
|
||||
"phase": "ready",
|
||||
"elapsed_seconds": pytest.approx(0.0, abs=0.1),
|
||||
"byte_length": len(payload),
|
||||
}
|
||||
|
||||
(results_root / f"e10-integrated-perception-{'b' * 64}").mkdir()
|
||||
assert store._latest("session-1") is not None
|
||||
assert validation_calls == {"job": 2, "result": 3}
|
||||
|
||||
def test_integrated_overlay_serializes_heavy_materialization_across_sessions(
|
||||
tmp_path: Path,
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
for name in ("jobs", "results", "lidar-packs"):
|
||||
(tmp_path / name).mkdir()
|
||||
store = IntegratedPerceptionOverlayStore(
|
||||
jobs_root=tmp_path / "jobs",
|
||||
results_root=tmp_path / "results",
|
||||
lidar_packs_root=tmp_path / "lidar-packs",
|
||||
cache_root=tmp_path / "cache",
|
||||
ffmpeg_path=tmp_path / "ffmpeg",
|
||||
)
|
||||
result_id = f"e10-integrated-perception-{'a' * 64}"
|
||||
result = SimpleNamespace(
|
||||
result_id=result_id,
|
||||
created_at_utc="2026-07-29T12:00:00Z",
|
||||
)
|
||||
monkeypatch.setattr(store, "_read_admitted_cache", lambda *_args: None)
|
||||
monkeypatch.setattr(store, "_latest", lambda _session_id: result)
|
||||
monkeypatch.setattr(store, "_write_admission", lambda _result: None)
|
||||
|
||||
active = 0
|
||||
maximum_active = 0
|
||||
active_lock = threading.Lock()
|
||||
|
||||
def render_overlay(*_args: object, **_kwargs: object) -> bytes:
|
||||
nonlocal active, maximum_active
|
||||
with active_lock:
|
||||
active += 1
|
||||
maximum_active = max(maximum_active, active)
|
||||
time.sleep(0.05)
|
||||
with active_lock:
|
||||
active -= 1
|
||||
return b"RRF2materialized"
|
||||
|
||||
monkeypatch.setattr(integrated_module, "_render", render_overlay)
|
||||
with ThreadPoolExecutor(max_workers=2) as executor:
|
||||
results = tuple(
|
||||
executor.map(
|
||||
lambda item: store.render(
|
||||
item,
|
||||
application_id="nodedc_mission_core_recorded",
|
||||
recording_id=f"recording-{item}",
|
||||
),
|
||||
("session-1", "session-2"),
|
||||
)
|
||||
)
|
||||
|
||||
assert results == (b"RRF2materialized", b"RRF2materialized")
|
||||
assert maximum_active == 1
|
||||
|
||||
|
||||
def test_e10_profile_pins_integrated_realtime_budget() -> None:
|
||||
|
||||
Reference in New Issue
Block a user