feat(perception): integrate calibrated operator pipeline

Add calibrated K1 projection, recorded and near-live perception qualification, unified Rerun operator layers, bounded replay admission, audited viewer controls, worker experiments, and lab evidence.
This commit is contained in:
DCCONSTRUCTIONS
2026-07-23 00:23:28 +03:00
parent ada2a55ee6
commit b53d6d5a45
221 changed files with 55923 additions and 1357 deletions
+30
View File
@@ -0,0 +1,30 @@
calibrated: true
camera_0:
camera_model: kb4
camera_pose: [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]
distortion: [-0.02, -0.0015, -0.002, 0.001]
image_height: 3000
image_width: 4000
intrinsic: [968, 968, 2000, 1500]
camera_1:
camera_model: kb4
camera_pose: [-1, 0, 0, 0, 0, 1, 0, 0, 0, 0, -1, -0.07, 0, 0, 0, 1]
distortion: [-0.021, -0.0014, -0.0019, 0.0009]
image_height: 3000
image_width: 4000
intrinsic: [970, 971, 1980, 1510]
camera_2:
camera_model: kb4
camera_pose: [1, 0, 0, 0.036, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]
distortion: [-0.002, 0.004, 0.003, -0.001]
image_height: 800
image_width: 1280
intrinsic: [386, 386, 640, 400]
camera_3:
camera_model: kb4
camera_pose: [-1, 0, 0, 0.036, 0, 1, 0, 0, 0, 0, -1, -0.07, 0, 0, 0, 1]
distortion: [-0.0021, 0.0041, 0.0031, -0.0011]
image_height: 800
image_width: 1280
intrinsic: [387, 387, 641, 401]
version: V2.2.0_alpha
@@ -0,0 +1,3 @@
calibrated: true
transform: [1, 0, 0, -0.007, 0, 0, -1, -0.0948, 0, 1, 0, -0.0372, 0, 0, 0, 1]
version: V2.2.0_alpha
+199
View File
@@ -0,0 +1,199 @@
from __future__ import annotations
import hashlib
import json
import zipfile
from pathlib import Path
from typing import Any
import pytest
from PIL import Image, ImageDraw
from test_perception_qualification import _evaluation_fixture
from k1link.compute import (
AnnotationWorkspaceError,
prepare_annotation_workspace,
prepare_recorded_evaluation_pack,
validate_annotation_workspace,
)
from k1link.device_plugins.xgrids_k1.analyze.valid_fov import validate_k1_valid_fov_mask
def _canonical_json(value: object) -> bytes:
return json.dumps(
value,
ensure_ascii=False,
sort_keys=True,
separators=(",", ":"),
allow_nan=False,
).encode("utf-8")
def _sha256(path: Path) -> str:
return hashlib.sha256(path.read_bytes()).hexdigest()
def _write_json(path: Path, payload: object) -> None:
path.write_text(json.dumps(payload, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
def _artifact(path: Path, root: Path) -> dict[str, Any]:
return {
"path": path.relative_to(root).as_posix(),
"byte_length": path.stat().st_size,
"sha256": _sha256(path),
}
def _prelabel_fixture(pack_root: Path, valid_fov_root: Path, output_root: Path) -> Path:
pack = json.loads((pack_root / "manifest.json").read_text(encoding="utf-8"))
valid_fov = validate_k1_valid_fov_mask(valid_fov_root)
staging = output_root / "staging"
(staging / "instance-prelabels").mkdir(parents=True)
(staging / "semantic-prelabels").mkdir()
with Image.open(valid_fov.mask_path) as opened:
valid_mask = opened.copy()
rows: list[dict[str, Any]] = []
for order, source in enumerate(pack["identity"]["frames"], start=1):
instance = Image.new("I;16", (valid_fov.width, valid_fov.height), 0)
ImageDraw.Draw(instance).rectangle((390, 290, 409, 309), fill=1)
instance.save(staging / "instance-prelabels" / f"image-{order:03d}.png")
semantic = Image.composite(
Image.new("L", (valid_fov.width, valid_fov.height), 7),
Image.new("L", (valid_fov.width, valid_fov.height), 0),
valid_mask,
)
ImageDraw.Draw(semantic).rectangle((390, 290, 409, 309), fill=4)
semantic.save(staging / "semantic-prelabels" / f"image-{order:03d}.png")
rows.append(
{
"schema_version": "missioncore.perception-evaluation-prelabel-frame/v1",
"image_id": source["image_id"],
"frame_index": source["frame_index"],
"session_seconds": source["session_seconds"],
"role": source["role"],
"group_id": source["group_id"],
"instances": [
{
"instance_id": 1,
"draft_category_id": 4,
"draft_category": "car",
"source_model_category_id": 3,
"source_model_category": "car",
"score": 0.9,
"box_xyxy": [390.0, 290.0, 410.0, 310.0],
"mask_pixels": 400,
"review_state": "unreviewed-model-draft",
}
],
"review_state": "unreviewed-model-draft",
}
)
(staging / "frames.jsonl").write_text(
"".join(json.dumps(row, separators=(",", ":")) + "\n" for row in rows),
encoding="utf-8",
)
identity = {
"schema_version": "missioncore.perception-evaluation-prelabels-identity/v1",
"evaluation_pack_id": pack["generation_id"],
"evaluation_identity_sha256": pack["identity_sha256"],
"valid_fov_generation_id": valid_fov.generation_id,
"pipeline": "fixture/v1",
}
identity_sha256 = hashlib.sha256(_canonical_json(identity)).hexdigest()
result_id = f"evaluation-prelabels-{identity_sha256}"
artifacts = [
_artifact(path, staging) for path in sorted(staging.rglob("*")) if path.is_file()
]
_write_json(
staging / "result.json",
{
"schema_version": "missioncore.perception-evaluation-prelabels/v1",
"result_id": result_id,
"identity_sha256": identity_sha256,
"identity": identity,
"review_state": "unreviewed-model-draft",
"artifacts": artifacts,
},
)
final = output_root / result_id
staging.rename(final)
return final
def _workspace_fixture(tmp_path: Path) -> tuple[Path, Path, Path, Path]:
job_root, qualification_root, valid_fov_root, frames_root, timeline_path, requests = (
_evaluation_fixture(tmp_path)
)
pack = prepare_recorded_evaluation_pack(
job_root=job_root,
qualification_root=qualification_root,
valid_fov_root=valid_fov_root,
decoded_frames_root=frames_root,
timeline_path=timeline_path,
output_root=tmp_path / "evaluation-packs",
selection=requests,
decoder_version="fixture-decoder/v1",
selection_document_sha256="1" * 64,
producer_files=(("fixture.py", "2" * 64),),
)
prelabels = _prelabel_fixture(pack.root, valid_fov_root, tmp_path / "prelabels")
return pack.root, prelabels, valid_fov_root, tmp_path / "annotation-workspaces"
def test_annotation_workspace_is_reproducible_and_remains_unreviewed(tmp_path: Path) -> None:
pack_root, prelabels_root, valid_fov_root, output_root = _workspace_fixture(tmp_path)
first = prepare_annotation_workspace(
evaluation_pack_root=pack_root,
prelabels_root=prelabels_root,
valid_fov_root=valid_fov_root,
output_root=output_root,
producer_files=(("fixture.py", "3" * 64),),
)
repeated = prepare_annotation_workspace(
evaluation_pack_root=pack_root,
prelabels_root=prelabels_root,
valid_fov_root=valid_fov_root,
output_root=output_root,
producer_files=(("fixture.py", "3" * 64),),
)
assert repeated == first
assert first.frame_count == 22
assert first.draft_instance_count == 22
manifest = json.loads(first.manifest_path.read_text(encoding="utf-8"))
assert manifest["ground_truth"] is False
assert manifest["state"] == "prepared-unreviewed-model-draft"
review = json.loads(first.review_template_path.read_text(encoding="utf-8"))
assert {row["review_status"] for row in review["frames"]} == {"unreviewed"}
with zipfile.ZipFile(first.instance_archive_path) as archive:
coco = json.loads(archive.read("annotations/instances_default.json"))
assert len(coco["images"]) == 22
assert len(coco["annotations"]) == 22
assert all(sum(row["segmentation"]["counts"]) == 800 * 600 for row in coco["annotations"])
assert all(row["area"] == 400 for row in coco["annotations"])
assert (
validate_annotation_workspace(
first.root,
evaluation_pack_root=pack_root,
prelabels_root=prelabels_root,
valid_fov_root=valid_fov_root,
)
== first
)
def test_annotation_workspace_rejects_changed_archive(tmp_path: Path) -> None:
pack_root, prelabels_root, valid_fov_root, output_root = _workspace_fixture(tmp_path)
result = prepare_annotation_workspace(
evaluation_pack_root=pack_root,
prelabels_root=prelabels_root,
valid_fov_root=valid_fov_root,
output_root=output_root,
producer_files=(("fixture.py", "3" * 64),),
)
result.semantic_archive_path.write_bytes(b"changed")
with pytest.raises(AnnotationWorkspaceError, match="artifact changed"):
validate_annotation_workspace(result.root)
+36 -1
View File
@@ -1,7 +1,14 @@
import asyncio
from bleak.backends.device import BLEDevice
from bleak.backends.scanner import AdvertisementData
from pytest import MonkeyPatch
from k1link.device_plugins.xgrids_k1.ble.scanner import advertisement_record
from k1link.device_plugins.xgrids_k1.ble.scanner import (
advertisement_record,
discovered_device,
scan,
)
def test_advertisement_record_marks_k1_candidate() -> None:
@@ -37,3 +44,31 @@ def test_advertisement_record_marks_synthetic_xgr_name_as_k1_candidate() -> None
record = advertisement_record(device, advertisement)
assert record["k1_name_candidate"] is True
def test_scan_retains_the_live_corebluetooth_handle(
monkeypatch: MonkeyPatch,
) -> None:
device = BLEDevice("LIVE-UUID", "XGR-LIVE", details=object())
advertisement = AdvertisementData(
local_name="XGR-LIVE",
manufacturer_data={},
service_data={},
service_uuids=[],
tx_power=0,
rssi=-41,
platform_data=(),
)
async def fake_discover(**_kwargs: object) -> dict[str, tuple[BLEDevice, AdvertisementData]]:
return {"LIVE-UUID": (device, advertisement)}
monkeypatch.setattr(
"k1link.device_plugins.xgrids_k1.ble.scanner.BleakScanner.discover",
fake_discover,
)
result = asyncio.run(scan(1.0))
assert result["devices"][0]["macos_uuid"] == "LIVE-UUID"
assert discovered_device("LIVE-UUID") is device
+79
View File
@@ -10,6 +10,7 @@ from pathlib import Path
import pytest
import k1link.web.camera_archive as camera_archive_module
from k1link.device_plugins.xgrids_k1.archive import discover_legacy_viewer_sessions
from k1link.web.camera_archive import (
CAMERA_ARCHIVE_SCHEMA,
@@ -81,6 +82,84 @@ def test_camera_archive_writes_canonical_segments_and_seals_summary(tmp_path: Pa
assert writer.close() == summary
def test_recovery_accepts_sealed_index_larger_than_old_duration_cap_without_loading_video(
tmp_path: Path,
monkeypatch: pytest.MonkeyPatch,
) -> None:
sessions_root = tmp_path / "sessions"
epoch = (
sessions_root
/ "20260720T065719Z_viewer_live"
/ "media"
/ "sensor.camera.right"
/ "epoch-1"
)
segments = epoch / "segments"
segments.mkdir(parents=True)
init = b"sealed-init"
(epoch / "init.mp4").write_bytes(init)
segment_count = 560
segment = b"x"
segment_sha256 = hashlib.sha256(segment).hexdigest()
index_sha256 = hashlib.sha256()
with (epoch / "index.jsonl").open("wb") as stream:
for sequence in range(1, segment_count + 1):
(segments / f"{sequence}.m4s").write_bytes(segment)
line = (
json.dumps(
{
"schema_version": "missioncore.camera-recording-index/v1",
"sequence": sequence,
"kind": "media",
"path": f"segments/{sequence}.m4s",
"length": 1,
"sha256": segment_sha256,
"padding": "p" * 60_000,
},
separators=(",", ":"),
)
+ "\n"
).encode()
index_sha256.update(line)
stream.write(line)
assert (epoch / "index.jsonl").stat().st_size > 32 * 1024 * 1024
(epoch / "summary.json").write_text(
json.dumps(
{
"schema_version": CAMERA_ARCHIVE_SCHEMA,
"source_id": "sensor.camera.right",
"codec_epoch": 1,
"status": "complete",
"segment_count": segment_count,
"entry_count": segment_count,
"media_segment_count": segment_count,
"valid_bytes": len(init) + segment_count,
"init_sha256": hashlib.sha256(init).hexdigest(),
"stream_sha256": hashlib.sha256(init + segment * segment_count).hexdigest(),
"index_sha256": index_sha256.hexdigest(),
"synchronization": "host-arrival-best-effort",
"commit_policy": CAMERA_COMMIT_POLICY,
"artifacts": {
"init": "init.mp4",
"segments": "segments",
"index": "index.jsonl",
},
}
),
encoding="utf-8",
)
def fail_if_recovery_reads_video(_segments_fd: int) -> object:
raise AssertionError("a clean sealed archive must not enter payload recovery")
monkeypatch.setattr(
camera_archive_module,
"_read_recovery_segment_catalog",
fail_if_recovery_reads_video,
)
assert recover_incomplete_camera_archives(sessions_root) == ()
def test_camera_archive_rejects_media_without_init_and_existing_epoch(tmp_path: Path) -> None:
session = tmp_path / "session"
session.mkdir()
+302
View File
@@ -5,12 +5,19 @@ import json
from pathlib import Path
from typing import Any
import numpy as np
import pytest
import k1link.compute.fusion_epoch as fusion_module
import k1link.compute.perception_epoch as epoch_module
import k1link.compute.results as result_module
from k1link.compute import (
RecordedCalibratedFusionStore,
RecordedPerceptionEpochStore,
RecordedPerceptionOverlayStore,
prepare_camera_compute_job,
validate_recorded_calibrated_fusion,
validate_recorded_perception_epoch_result,
validate_recorded_perception_result,
)
from k1link.sessions import SessionIntegrityError
@@ -164,6 +171,166 @@ def _result(tmp_path: Path, job: Any) -> Path:
return root
def _epoch_result(tmp_path: Path, job: Any) -> Path:
identity = {
"schema_version": "missioncore.recorded-perception-identity/v2",
"job_id": job.job_id,
"input_sha256": job.input_sha256,
"calibration": {
"content_identity_sha256": "b" * 64,
"camera_slot": "camera_1",
},
"configuration": {"pipeline": "synthetic-panoptic/v1"},
"models": {"instance": {"id": "synthetic"}},
"publication": {
"video_encoder": "synthetic",
"video_media_type": "video/mp4",
"mask_archive_media_type": "application/gzip",
},
}
identity_sha256 = hashlib.sha256(_canonical_json(identity)).hexdigest()
result_id = f"result-{identity_sha256}"
root = tmp_path / "results" / job.job_id / result_id
root.mkdir(parents=True)
frame = {
"schema_version": "missioncore.panoptic-frame/v1",
"frame_index": 0,
"sequence": 1,
"session_seconds": job.timeline_start_seconds,
"instances": [],
"semantic_classes": [],
}
(root / "frames.jsonl").write_text(
json.dumps(frame, separators=(",", ":")) + "\n",
encoding="utf-8",
)
(root / "perception.mp4").write_bytes(b"synthetic-mp4")
(root / "masks.tar.gz").write_bytes(b"synthetic-masks")
(root / "gpu-telemetry.jsonl").write_text("{}\n", encoding="utf-8")
report = {
"schema_version": "missioncore.perception-run-report/v1",
"state": "published",
"result_id": result_id,
"input": {"job_id": job.job_id, "input_sha256": job.input_sha256},
"metrics": {
"frames_expected": 1,
"frames_processed": 1,
"frames_failed": 0,
"frames_skipped": 0,
},
}
(root / "run-report.json").write_text(json.dumps(report) + "\n", encoding="utf-8")
artifact_contracts = (
("panoptic-overlay-video", "perception.mp4", "video/mp4", None),
("panoptic-mask-archive", "masks.tar.gz", "application/gzip", None),
(
"panoptic-frame-metadata",
"frames.jsonl",
"application/x-ndjson",
"missioncore.panoptic-frame/v1",
),
("worker-gpu-telemetry", "gpu-telemetry.jsonl", "application/x-ndjson", None),
(
"perception-run-report",
"run-report.json",
"application/json",
"missioncore.perception-run-report/v1",
),
)
artifacts = []
for kind, name, media_type, schema_version in artifact_contracts:
path = root / name
descriptor = {
"kind": kind,
"path": name,
"media_type": media_type,
"byte_length": path.stat().st_size,
"sha256": hashlib.sha256(path.read_bytes()).hexdigest(),
}
if schema_version is not None:
descriptor["schema_version"] = schema_version
artifacts.append(descriptor)
result = {
"schema_version": "missioncore.recorded-perception-result/v2",
"result_id": result_id,
"identity_sha256": identity_sha256,
"identity": identity,
"created_at_utc": "2026-07-20T00:00:00.000Z",
"job_id": job.job_id,
"input_sha256": job.input_sha256,
"session_id": job.session_id,
"source_id": job.source_id,
"codec_epoch": job.codec_epoch,
"timestamp_basis": "session-time-seconds",
"timeline_start_seconds": job.timeline_start_seconds,
"timeline_end_seconds": job.timeline_end_seconds,
"frames_processed": job.segment_count,
"artifacts": artifacts,
}
(root / "result.json").write_text(json.dumps(result) + "\n", encoding="utf-8")
return root
def _fusion_result(tmp_path: Path, job: Any, perception_root: Path) -> Path:
perception_result_id = perception_root.name
identity = {
"schema_version": "missioncore.recorded-calibrated-fusion-identity/v1",
"job_id": job.job_id,
"input_sha256": job.input_sha256,
"perception_result_id": perception_result_id,
"calibration_sha256": "b" * 64,
"camera_slot": "camera_1",
"configuration": {"pipeline": "synthetic-fusion/v1"},
}
identity_sha256 = hashlib.sha256(_canonical_json(identity)).hexdigest()
fusion_id = f"fusion-{identity_sha256}"
root = tmp_path / "fusions" / job.job_id / fusion_id
root.mkdir(parents=True)
np.savez_compressed(
root / "fusion.npz",
frame_times_ns=np.asarray([0], dtype=np.int64),
point_offsets=np.asarray([0, 2], dtype=np.int64),
points=np.asarray([[1, 2, 3], [4, 5, 6]], dtype=np.float32),
point_colors=np.asarray([[1, 2, 3], [4, 5, 6]], dtype=np.uint8),
box_offsets=np.asarray([0, 1], dtype=np.int64),
box_centers=np.asarray([[1, 2, 3]], dtype=np.float32),
box_half_sizes=np.asarray([[0.5, 0.5, 0.5]], dtype=np.float32),
box_colors=np.asarray([[1, 2, 3, 96]], dtype=np.uint8),
)
(root / "box-labels.json").write_text('["person · 2.0 m · 5 pts"]', encoding="utf-8")
(root / "fusion-frames.jsonl").write_text(
'{"frame_index":0,"state":"fused"}\n',
encoding="utf-8",
)
artifacts = [
{
"name": path.name,
"byte_length": path.stat().st_size,
"sha256": hashlib.sha256(path.read_bytes()).hexdigest(),
}
for path in (
root / "fusion.npz",
root / "box-labels.json",
root / "fusion-frames.jsonl",
)
]
manifest = {
"schema_version": "missioncore.recorded-calibrated-fusion/v1",
"fusion_id": fusion_id,
"identity_sha256": identity_sha256,
"identity": identity,
"created_at_utc": "2026-07-20T01:00:00.000Z",
"session_id": job.session_id,
"source_id": job.source_id,
"frame_count": job.segment_count,
"timeline_start_seconds": job.timeline_start_seconds,
"timeline_end_seconds": job.timeline_end_seconds,
"artifacts": artifacts,
}
(root / "manifest.json").write_text(json.dumps(manifest) + "\n", encoding="utf-8")
return root
def test_result_is_bound_to_job_and_cache_reuses_complete_overlay(
tmp_path: Path,
monkeypatch: pytest.MonkeyPatch,
@@ -210,3 +377,138 @@ def test_result_rejects_changed_detection_payload(tmp_path: Path) -> None:
detection_path.write_bytes(detection_path.read_bytes().replace(b"0.75", b"0.76"))
with pytest.raises(SessionIntegrityError, match="artifact identity changed"):
validate_recorded_perception_result(job.job_root, result_root)
def test_full_epoch_result_publishes_native_panoptic_video(
tmp_path: Path,
monkeypatch: pytest.MonkeyPatch,
) -> None:
job = _job(tmp_path)
result_root = _epoch_result(tmp_path, job)
result = validate_recorded_perception_epoch_result(job.job_root, result_root)
assert result.calibration_slot == "camera_1"
assert result.artifact("panoptic-overlay-video").byte_length == len(b"synthetic-mp4")
monkeypatch.setattr(
epoch_module.RecordedPerceptionEpochStore,
"_probe_video",
lambda *_: (0.5, "h264", 800, 600),
)
store = RecordedPerceptionEpochStore(
jobs_root=tmp_path / "jobs",
results_root=tmp_path / "results",
ffprobe_path=Path(__file__),
)
video = store.video("session-1")
assert video is not None
assert video.result_id == result.result_id
assert video.public_source_id == "recorded.perception.left"
assert video.timeline_start_seconds == 0
assert video.timeline_end_seconds == 0.5
def test_full_epoch_store_reuses_unchanged_validated_result(
tmp_path: Path,
monkeypatch: pytest.MonkeyPatch,
) -> None:
job = _job(tmp_path)
_epoch_result(tmp_path, job)
validation_calls = 0
validate = epoch_module.validate_recorded_perception_epoch_result
def count_validation(job_root: Path, result_root: Path) -> Any:
nonlocal validation_calls
validation_calls += 1
return validate(job_root, result_root)
monkeypatch.setattr(
epoch_module,
"validate_recorded_perception_epoch_result",
count_validation,
)
monkeypatch.setattr(
epoch_module.RecordedPerceptionEpochStore,
"_probe_video",
lambda *_: (0.5, "h264", 800, 600),
)
store = RecordedPerceptionEpochStore(
jobs_root=tmp_path / "jobs",
results_root=tmp_path / "results",
ffprobe_path=Path(__file__),
)
assert store.video("session-1") is not None
assert store.video("session-1") is not None
assert validation_calls == 1
def test_full_epoch_result_rejects_changed_frame_metadata(tmp_path: Path) -> None:
job = _job(tmp_path)
result_root = _epoch_result(tmp_path, job)
frame_path = result_root / "frames.jsonl"
frame_path.write_text("{}\n", encoding="utf-8")
with pytest.raises(SessionIntegrityError, match="artifact identity changed"):
validate_recorded_perception_epoch_result(job.job_root, result_root)
def test_calibrated_fusion_is_bound_to_full_epoch_and_reuses_render_cache(
tmp_path: Path,
monkeypatch: pytest.MonkeyPatch,
) -> None:
job = _job(tmp_path)
perception_root = _epoch_result(tmp_path, job)
fusion_root = _fusion_result(tmp_path, job, perception_root)
fusion = validate_recorded_calibrated_fusion(
job.job_root,
tmp_path / "results",
fusion_root,
)
assert fusion.perception_result_id == perception_root.name
assert fusion.frame_count == 1
rendered = fusion_module._render_fusion(
fusion,
application_id="nodedc_mission_core_recorded",
recording_id="recording-render-proof",
)
assert rendered.startswith(b"RRF2")
calls = 0
def render(*_: object, **__: object) -> bytes:
nonlocal calls
calls += 1
return b"RRF2synthetic-fusion"
monkeypatch.setattr(fusion_module, "_render_fusion", render)
store = RecordedCalibratedFusionStore(
jobs_root=tmp_path / "jobs",
perception_results_root=tmp_path / "results",
fusion_results_root=tmp_path / "fusions",
cache_root=tmp_path / "fusion-cache",
)
first = store.render(
"session-1",
application_id="nodedc_mission_core_recorded",
recording_id="recording-1",
)
second = store.render(
"session-1",
application_id="nodedc_mission_core_recorded",
recording_id="recording-1",
)
assert first == second == b"RRF2synthetic-fusion"
assert calls == 1
def test_calibrated_fusion_rejects_changed_array_artifact(tmp_path: Path) -> None:
job = _job(tmp_path)
perception_root = _epoch_result(tmp_path, job)
fusion_root = _fusion_result(tmp_path, job, perception_root)
with (fusion_root / "fusion.npz").open("ab") as stream:
stream.write(b"changed")
with pytest.raises(SessionIntegrityError, match="artifact identity changed"):
validate_recorded_calibrated_fusion(
job.job_root,
tmp_path / "results",
fusion_root,
)
+319
View File
@@ -0,0 +1,319 @@
from __future__ import annotations
import importlib.util
import sys
from pathlib import Path
import numpy as np
from k1link.compute.integrated_perception import _CuboidPresentationState
def _worker_modules() -> tuple[object, object]:
root = Path(__file__).resolve().parents[1] / "experiments" / "perception"
worker = root / "worker"
sys.path.insert(0, str(root))
sys.path.insert(0, str(worker))
try:
fusion_spec = importlib.util.spec_from_file_location(
"e10_test_fusion", root / "e10_fusion_runtime.py"
)
assert fusion_spec is not None and fusion_spec.loader is not None
fusion = importlib.util.module_from_spec(fusion_spec)
sys.modules[fusion_spec.name] = fusion
fusion_spec.loader.exec_module(fusion)
runner_spec = importlib.util.spec_from_file_location(
"e10_test_runner", worker / "run_e10_integrated_perception.py"
)
assert runner_spec is not None and runner_spec.loader is not None
runner = importlib.util.module_from_spec(runner_spec)
sys.modules[runner_spec.name] = runner
runner_spec.loader.exec_module(runner)
return fusion, runner
finally:
sys.path.pop(0)
sys.path.pop(0)
def test_e10_profile_pins_integrated_realtime_budget() -> None:
_fusion, runner = _worker_modules()
profile_path = (
Path(__file__).resolve().parents[1]
/ "experiments"
/ "perception"
/ "worker"
/ "e10_integrated_perception_profile.json"
)
profile, digest = runner.read_profile(profile_path)
assert len(digest) == 64
assert profile["replay"] == {
"speed": 1.0,
"detector_queue_capacity": 2,
"semantic_queue_capacity": 1,
"semantic_sample_every_frames": 5,
"semantic_ttl_ms": 750.0,
}
assert profile["acceptance"]["detector_minimum_effective_fps"] == 9.5
assert profile["acceptance"]["maximum_p95_world_state_age_ms"] == 175.0
assert profile["acceptance"]["minimum_lidar_fused_frames"] == 450
def test_e10_semantic_loss_profile_is_explicit_and_fail_closed() -> None:
_fusion, runner = _worker_modules()
profile_path = (
Path(__file__).resolve().parents[1]
/ "experiments"
/ "perception"
/ "worker"
/ "e10_semantic_loss_profile.json"
)
profile, digest = runner.read_profile(profile_path)
assert len(digest) == 64
assert profile["mode"] == "semantic-loss-negative-control"
assert profile["semantic_loss"]["stop_after_completed_results"] == 20
assert profile["acceptance"]["minimum_stale_detector_frames"] == 450
assert profile["replay"]["semantic_ttl_ms"] == 750.0
def test_e10_full_session_profile_pins_complete_camera_epoch() -> None:
_fusion, runner = _worker_modules()
profile_path = (
Path(__file__).resolve().parents[1]
/ "experiments"
/ "perception"
/ "worker"
/ "e10_full_session_profile.json"
)
profile, digest = runner.read_profile(profile_path)
assert len(digest) == 64
assert profile["mode"] == "full-session-qualification"
assert profile["selection"] == {
"required_frame_count": 4489,
"required_source_start_frame_index": 0,
"required_source_end_frame_index": 4488,
"minimum_source_span_seconds": 448.0,
}
assert profile["acceptance"]["detector_maximum_drop_fraction"] == 0.0
assert profile["acceptance"]["minimum_lidar_fused_frames"] == 3500
def test_e13_profile_pins_provenance_marked_amodal_completion() -> None:
_fusion, runner = _worker_modules()
profile_path = (
Path(__file__).resolve().parents[1]
/ "experiments"
/ "perception"
/ "worker"
/ "e13_amodal_cuboid_profile.json"
)
profile, digest = runner.read_profile(profile_path)
assert len(digest) == 64
assert profile["mode"] == "pilot"
assert profile["cuboid_completion"]["mode"] == "class-prior-amodal-v1"
assert profile["cuboid_completion"]["classes"]["car"]["nominal_size_m"] == [
4.5,
1.85,
1.55,
]
assert profile["cuboid_completion"]["temporal"]["confirmation_hits"] == 3
def test_e14_profile_combines_full_session_and_amodal_gates() -> None:
_fusion, runner = _worker_modules()
profile_path = (
Path(__file__).resolve().parents[1]
/ "experiments"
/ "perception"
/ "worker"
/ "e14_full_session_amodal_profile.json"
)
profile, digest = runner.read_profile(profile_path)
assert len(digest) == 64
assert profile["mode"] == "full-session-qualification"
assert profile["selection"] == {
"required_frame_count": 4489,
"required_source_start_frame_index": 0,
"required_source_end_frame_index": 4488,
"minimum_source_span_seconds": 448.0,
}
assert profile["cuboid_completion"]["mode"] == "class-prior-amodal-v1"
assert profile["cuboid_completion"]["failure_policy"] == "reject"
assert profile["acceptance"]["minimum_lidar_fused_frames"] == 3500
assert profile["acceptance"]["minimum_accepted_cuboids"] == 1500
def test_recorded_cuboid_presentation_holds_one_failed_association_then_expires() -> None:
state = _CuboidPresentationState(hold_ns=500_000_000)
accepted = {
"association_group": "vehicle",
"clustered_points": 14,
"cuboid_status": "accepted-class-prior-amodal-v1",
"distance_smoothed_m": 8.25,
"label": "car",
"track_id": 7,
}
initial = state.update(
1_000_000_000,
[accepted],
np.asarray([[1.0, 2.0, 3.0]], dtype=np.float32),
np.asarray([[2.25, 0.925, 0.775]], dtype=np.float32),
np.asarray([[0.0, 0.0, 0.0, 1.0]], dtype=np.float32),
np.asarray([[118, 204, 132, 88]], dtype=np.uint8),
)
assert initial is not None
assert initial[4] == ["vehicle #7 car · 8.2 m · 14 pts"]
rejected = {"cuboid_status": "rejected-no-semantic-lidar-support", "track_id": 7}
held = state.update(
1_200_000_000,
[rejected],
np.empty((0, 3), dtype=np.float32),
np.empty((0, 3), dtype=np.float32),
np.empty((0, 4), dtype=np.float32),
np.empty((0, 4), dtype=np.uint8),
)
assert held is not None
assert held[4] == ["vehicle #7 car · 8.2 m · 14 pts · hold 200 ms"]
assert int(held[3][0, 3]) < 88
expired = state.update(
1_600_000_001,
[],
np.empty((0, 3), dtype=np.float32),
np.empty((0, 3), dtype=np.float32),
np.empty((0, 4), dtype=np.float32),
np.empty((0, 4), dtype=np.uint8),
)
assert expired is None
def test_e13_completes_a_visible_car_face_away_from_the_sensor() -> None:
fusion, runner = _worker_modules()
profile, _digest = runner.read_profile(
Path(__file__).resolve().parents[1]
/ "experiments"
/ "perception"
/ "worker"
/ "e13_amodal_cuboid_profile.json"
)
y = np.linspace(-0.8, 0.8, 12)
z = np.linspace(0.35, 1.3, 5)
support = np.asarray(
[[10.0 + 0.01 * (index % 2), side, height] for index, side in enumerate(y) for height in z],
dtype=np.float64,
)
ground = np.asarray(
[[x, side, 0.0] for x in np.linspace(8.0, 12.0, 8) for side in (-1.5, 0.0, 1.5)],
dtype=np.float64,
)
observed = fusion._cuboid(support, profile["association"], "vehicle")
assert observed is not None
tracker = fusion.CuboidCompletionTracker(profile["cuboid_completion"])
completed = tracker.complete(
track_id=4,
label="car",
support_points_map=support,
all_points_map=np.concatenate((support, ground)),
sensor_position_map=(0.0, 0.0, 0.0),
session_seconds=1.0,
observed_cuboid=observed,
)
assert completed is not None
assert completed.orientation_source == "support-face-normal"
completed_size = np.asarray(completed.cuboid.half_size) * 2.0
assert completed_size[0] == 4.5
assert 1.85 <= completed_size[1] <= 2.0
assert completed_size[2] == 1.55
assert completed.cuboid.center_map[0] > 12.0
assert completed.ground_z_map == 0.0
assert completed.completion_fraction > 0.8
assert completed.support_coverage_fraction >= 0.75
def test_e13_temporal_filter_reduces_cuboid_center_jitter() -> None:
fusion, runner = _worker_modules()
profile, _digest = runner.read_profile(
Path(__file__).resolve().parents[1]
/ "experiments"
/ "perception"
/ "worker"
/ "e13_amodal_cuboid_profile.json"
)
tracker = fusion.CuboidCompletionTracker(profile["cuboid_completion"])
base = np.asarray(
[
[x, 2.0 + 0.02 * (index % 2), z]
for index, x in enumerate(np.linspace(8.0, 11.5, 20))
for z in (0.4, 0.9, 1.3)
],
dtype=np.float64,
)
ground = np.asarray([[x, y, 0.0] for x in np.linspace(7.0, 13.0, 10) for y in (0.5, 2.0, 3.5)])
outputs = []
for frame, lateral_jitter in enumerate((0.0, 0.4, 0.2), start=1):
support = base + np.asarray([0.0, lateral_jitter, 0.0])
observed = fusion._cuboid(support, profile["association"], "vehicle")
assert observed is not None
value = tracker.complete(
track_id=9,
label="car",
support_points_map=support,
all_points_map=np.concatenate((support, ground)),
sensor_position_map=(0.0, 0.0, 0.0),
session_seconds=frame * 0.1,
observed_cuboid=observed,
)
assert value is not None
outputs.append(value)
lateral_shift = abs(outputs[1].cuboid.center_map[1] - outputs[0].cuboid.center_map[1])
assert lateral_shift < 0.4
assert outputs[-1].temporal_status == "confirmed"
def test_e10_semantic_binding_is_explicit_about_freshness() -> None:
_fusion, runner = _worker_modules()
assert runner.semantic_binding(None, 2.0, 750.0) == ("unavailable", None)
value = runner.SemanticResult(
frame_index=1,
source_frame_index=1001,
session_seconds=1.0,
completion_age_ms=200.0,
completed_monotonic=3.0,
mask=np.zeros((600, 800), dtype=np.uint8),
mask_sha256="0" * 64,
class_pixels={},
)
assert runner.semantic_binding(value, 1.7, 750.0) == ("fresh", 700.0)
assert runner.semantic_binding(value, 1.8, 750.0) == (
"stale",
800.0,
)
def test_e10_projection_keeps_only_nearest_point_per_pixel() -> None:
fusion, _runner = _worker_modules()
profile = fusion.ProjectionProfile(
width=800,
height=600,
intrinsic_fx_fy_cx_cy=(100.0, 100.0, 400.0, 300.0),
distortion_kb4=(0.0, 0.0, 0.0, 0.0),
t_camera_from_lidar=np.eye(4, dtype=np.float64),
)
points = np.asarray([[0.0, 0.0, 2.0], [0.0, 0.0, 3.0]], dtype=np.float64)
pixels, depths, source, _lidar = fusion.project_points(
points,
(0.0, 0.0, 0.0),
(0.0, 0.0, 0.0, 1.0),
profile,
)
assert pixels.shape == (1, 2)
assert depths.tolist() == [2.0]
assert source.tolist() == [0]
+96
View File
@@ -0,0 +1,96 @@
from __future__ import annotations
import importlib.util
import json
import sys
from pathlib import Path
import numpy as np
import pytest
def _module() -> object:
path = (
Path(__file__).resolve().parents[1]
/ "experiments"
/ "perception"
/ "prepare_e15_projection_pack.py"
)
spec = importlib.util.spec_from_file_location("e15_projection_pack_test", 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
def test_projection_pack_contains_calibration_only(tmp_path: Path) -> None:
module = _module()
calibration_sha256 = "a" * 64
source = tmp_path / "source-pack"
source.mkdir()
arrays = source / "lidar-pack.npz"
np.savez(
arrays,
frame_indices=np.asarray([0]),
cloud_points_map=np.asarray([[99.0, 99.0, 99.0]]),
intrinsic_fx_fy_cx_cy=np.asarray([1.0, 2.0, 3.0, 4.0]),
distortion_kb4=np.asarray([0.1, 0.2, 0.3, 0.4]),
t_camera_from_lidar=np.eye(4),
)
manifest = {
"pack_id": "source-pack",
"identity_sha256": "b" * 64,
"identity": {
"calibration_sha256": calibration_sha256,
"source_id": "sensor.camera.right",
"camera_slot": "camera_1",
},
"artifact": {"sha256": module._sha256(arrays)},
}
(source / "manifest.json").write_text(json.dumps(manifest))
output = module.build_projection_pack(
source,
tmp_path / "output",
expected_calibration_sha256=calibration_sha256,
)
document = module.validate_projection_pack(output, calibration_sha256)
assert document["classification"] == "calibration-only-no-recorded-sensor-frames"
with np.load(output / "projection.npz", allow_pickle=False) as packed:
assert set(packed.files) == module.PACK_ARRAYS
assert "cloud_points_map" not in packed.files
assert "frame_indices" not in packed.files
def test_projection_pack_rejects_changed_calibration(tmp_path: Path) -> None:
module = _module()
source = tmp_path / "source-pack"
source.mkdir()
arrays = source / "lidar-pack.npz"
np.savez(
arrays,
intrinsic_fx_fy_cx_cy=np.ones(4),
distortion_kb4=np.ones(4),
t_camera_from_lidar=np.eye(4),
)
(source / "manifest.json").write_text(
json.dumps(
{
"identity": {
"calibration_sha256": "a" * 64,
"source_id": "sensor.camera.right",
"camera_slot": "camera_1",
},
"artifact": {"sha256": module._sha256(arrays)},
}
)
)
with pytest.raises(RuntimeError, match="calibration binding changed"):
module.build_projection_pack(
source,
tmp_path / "output",
expected_calibration_sha256="b" * 64,
)
+132
View File
@@ -0,0 +1,132 @@
from __future__ import annotations
import importlib.util
import json
import sys
from argparse import Namespace
from pathlib import Path
import pytest
def _module() -> object:
perception = Path(__file__).resolve().parents[1] / "experiments" / "perception"
worker = perception / "worker"
sys.path.insert(0, str(perception))
sys.path.insert(0, str(worker))
try:
spec = importlib.util.spec_from_file_location(
"e15_shadow_inference_test",
worker / "run_e15_shadow_inference.py",
)
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)
sys.path.pop(0)
def test_e15_profile_pins_replay_shadow_authority_and_bounded_runtime() -> None:
module = _module()
profile_path = (
Path(__file__).resolve().parents[1]
/ "experiments"
/ "perception"
/ "worker"
/ "e15_shadow_inference_profile.json"
)
profile, digest = module.read_live_profile(profile_path)
assert len(digest) == 64
assert profile["mode"] == "replay-shadow-gate"
assert profile["authority"] == {
"commands_enabled": False,
"navigation_or_safety_accepted": False,
}
assert profile["transport"] == {
"wire_schema": "missioncore.live-perception-wire/v1",
"camera_media": "persistent-fmp4-pyav",
"pyav_version": "18.0.0",
"maximum_media_buffer_bytes": 8 * 1024 * 1024,
"camera_metadata_capacity": 16,
}
assert profile["scheduling"] == {
"detector_queue_capacity": 2,
"semantic_queue_capacity": 1,
"semantic_sample_every_frames": 5,
"semantic_ttl_ms": 750.0,
"sensor_wait_ms": 90.0,
}
assert profile["acceptance"]["minimum_fused_fraction"] == 0.85
assert profile["acceptance"]["maximum_p95_world_state_age_ms"] == 200.0
def test_e15_profile_rejects_command_authority(tmp_path: Path) -> None:
module = _module()
source = (
Path(__file__).resolve().parents[1]
/ "experiments"
/ "perception"
/ "worker"
/ "e15_shadow_inference_profile.json"
)
value = json.loads(source.read_text())
value["authority"]["commands_enabled"] = True
changed = tmp_path / "unsafe-profile.json"
changed.write_text(json.dumps(value))
with pytest.raises(RuntimeError, match="profile contract"):
module.read_live_profile(changed)
def test_persistent_worker_request_is_single_run_d_backed_and_token_bounded(
tmp_path: Path,
) -> None:
module = _module()
service = Namespace(
output_root=tmp_path,
listen_host="127.0.0.1",
listen_port=18020,
command="serve",
marker="preserved",
)
run = module._persistent_run_arguments(
service,
{
"request_id": "physical-k1-shadow-001",
"output_name": "physical-k1-shadow-001",
"token": "a" * 64,
},
)
assert run.command == "run"
assert run.output == tmp_path / "physical-k1-shadow-001"
assert run.token == "a" * 64
assert run.token_stdin is False
assert run.marker == "preserved"
assert not hasattr(run, "listen_host")
assert not hasattr(run, "output_root")
with pytest.raises(RuntimeError, match="request contract"):
module._persistent_run_arguments(
service,
{
"request_id": "physical-k1-shadow-002",
"output_name": "physical-k1-shadow-002",
"token": "short",
},
)
with pytest.raises(RuntimeError, match="request contract"):
module._persistent_run_arguments(
service,
{
"request_id": "physical-k1-shadow-003",
"output_name": "../escape",
"token": "b" * 64,
},
)
+98
View File
@@ -0,0 +1,98 @@
from __future__ import annotations
import importlib.util
import json
import sys
from pathlib import Path
import pytest
_RUNTIME_PATH = (
Path(__file__).resolve().parents[1]
/ "experiments"
/ "perception"
/ "worker"
/ "e15_shadow_runtime.py"
)
_SPEC = importlib.util.spec_from_file_location("e15_shadow_runtime_test", _RUNTIME_PATH)
assert _SPEC is not None and _SPEC.loader is not None
_RUNTIME = importlib.util.module_from_spec(_SPEC)
sys.modules[_SPEC.name] = _RUNTIME
_SPEC.loader.exec_module(_RUNTIME)
CameraFragmentMetadata = _RUNTIME.CameraFragmentMetadata
IncrementalMediaBuffer = _RUNTIME.IncrementalMediaBuffer
PersistentFmp4Decoder = _RUNTIME.PersistentFmp4Decoder
ShadowRuntimeError = _RUNTIME.ShadowRuntimeError
def _metadata(sequence: int) -> CameraFragmentMetadata:
return CameraFragmentMetadata(
ingress_sequence=sequence,
source_sequence=sequence,
captured_at_epoch_ns=sequence * 100_000_000,
worker_received_monotonic=0.0,
)
def test_incremental_media_buffer_is_bounded_and_fail_closed() -> None:
source = IncrementalMediaBuffer(1024)
source.append(b"a" * 800)
with pytest.raises(ShadowRuntimeError, match="hard bound"):
source.append(b"b" * 300)
snapshot = source.snapshot()
assert snapshot["maximum_depth_bytes"] == 800
assert snapshot["failed"] is True
with pytest.raises(ShadowRuntimeError, match="source failed"):
source.read(100)
def test_persistent_decoder_rejects_camera_fragment_gaps_before_decode() -> None:
decoder = PersistentFmp4Decoder(on_frame=lambda _frame: None)
decoder.start()
decoder.feed_init(b"not-a-real-init")
decoder.feed_segment(_metadata(1), b"first")
with pytest.raises(ShadowRuntimeError, match="sequence gap"):
decoder.feed_segment(_metadata(3), b"third")
decoder.finish_input()
with pytest.raises(ShadowRuntimeError, match="decoder failed"):
decoder.join()
def test_persistent_decoder_streams_real_fmp4_epoch() -> None:
pytest.importorskip("av")
repository = Path(__file__).resolve().parents[1]
epoch = (
repository
/ ".runtime"
/ "mission-core"
/ "evidence"
/ "sessions"
/ "20260720T065719Z_viewer_live"
/ "media"
/ "sensor.camera.right"
/ "epoch-1"
)
if not epoch.is_dir():
pytest.skip("canonical RAVNOVES00 camera epoch is unavailable")
rows = [json.loads(line) for line in (epoch / "index.jsonl").read_text().splitlines()[:10]]
decoded = []
decoder = PersistentFmp4Decoder(on_frame=decoded.append)
decoder.start()
decoder.feed_init((epoch / "init.mp4").read_bytes())
for row in rows:
decoder.feed_segment(
CameraFragmentMetadata(
ingress_sequence=int(row["sequence"]),
source_sequence=int(row["sequence"]),
captured_at_epoch_ns=int(row["host_epoch_ns"]),
worker_received_monotonic=0.0,
),
(epoch / row["path"]).read_bytes(),
)
decoder.finish_input()
decoder.join()
assert len(decoded) == 10
assert [frame.metadata.source_sequence for frame in decoded] == list(range(1, 11))
assert all(frame.image.shape == (600, 800, 3) for frame in decoded)
assert decoder.snapshot()["media"]["depth_bytes"] == 0
+38
View File
@@ -0,0 +1,38 @@
from __future__ import annotations
import importlib.util
import sys
from pathlib import Path
def _module() -> object:
path = (
Path(__file__).resolve().parents[1]
/ "experiments"
/ "perception"
/ "prepare_e15_worker_package.py"
)
spec = importlib.util.spec_from_file_location("e15_worker_package_test", 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
def test_e15_worker_package_is_minimal_hash_addressed_projection(tmp_path: Path) -> None:
module = _module()
repository = Path(__file__).resolve().parents[1]
package = module.build_worker_package(repository / "src", tmp_path)
manifest = module.validate_worker_package(package)
assert package.name == f"e15-worker-package-{manifest['identity_sha256']}"
assert manifest["identity"]["classification"] == (
"minimal-live-worker-import-projection"
)
assert len(manifest["artifacts"]) == 11
assert not (package / "k1link" / "device_plugins" / "xgrids_k1" / "mqtt").exists()
assert "observation" not in (
package / "k1link" / "device_plugins" / "xgrids_k1" / "__init__.py"
).read_text()
+107
View File
@@ -0,0 +1,107 @@
from __future__ import annotations
import importlib.util
import math
import sys
from pathlib import Path
from types import ModuleType
import numpy as np
import pytest
WORKER_ROOT = (
Path(__file__).parents[1] / "experiments" / "perception" / "worker"
)
PROFILE_PATH = WORKER_ROOT / "e3_k1_camera1_profile.json"
def _worker_module() -> ModuleType:
path = WORKER_ROOT / "run_e3_rectified_segmentation.py"
sys.path.insert(0, str(WORKER_ROOT))
spec = importlib.util.spec_from_file_location("e3_rectified_segmentation", path)
assert spec is not None and spec.loader is not None
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
return module
def test_e3_profile_is_pinned_to_camera1_kb4_and_exact_model() -> None:
worker = _worker_module()
profile, digest = worker._profile(PROFILE_PATH)
assert len(digest) == 64
assert profile["source"]["calibration_slot"] == "camera_1"
assert profile["source"]["distortion_kb4"] == pytest.approx(
[
-0.023164451386679667,
-0.0014974198594105452,
-0.001039213149441563,
-0.000035237331915978814,
]
)
assert profile["model"]["revision"] == "8d6b6d1a3f7b50d441afd7d247c2ed10db186e8f"
assert profile["model"]["files"]["model.safetensors"]["sha256"] == (
"c265da9a74f58f5c3f4826d23ca4ca78beac0b106cca5842beca61580de5b782"
)
def test_kb4_inverse_round_trips_valid_field_angles() -> None:
worker = _worker_module()
profile, _digest = worker._profile(PROFILE_PATH)
coefficients = np.asarray(profile["source"]["distortion_kb4"])
theta = np.linspace(0.0, math.radians(96.4), 512)
squared = theta * theta
distorted = theta * (
1.0
+ coefficients[0] * squared
+ coefficients[1] * squared**2
+ coefficients[2] * squared**3
+ coefficients[3] * squared**4
)
recovered = worker._invert_kb4(distorted, coefficients)
assert recovered == pytest.approx(theta, abs=1e-10)
def test_five_view_rectification_covers_the_k1_valid_circle() -> None:
worker = _worker_module()
profile, _digest = worker._profile(PROFILE_PATH)
width, height = profile["source"]["resolution"]
_fx, _fy, cx, cy = profile["source"]["intrinsic_fx_fy_cx_cy"]
y, x = np.mgrid[:height, :width]
valid_mask = np.hypot(x - cx, y - cy) <= 293.0
maps = worker._rectification_maps(profile, valid_mask)
assert maps["coverage"]["coverage_fraction"] == 1.0
assert maps["coverage"]["covered_pixel_count"] == int(valid_mask.sum())
assert maps["coverage"]["overlap_count"]["min"] >= 1
assert maps["coverage"]["overlap_count"]["max"] <= 3
def test_tile_fusion_uses_the_selected_view_and_masks_outside_fov() -> None:
worker = _worker_module()
valid_mask = np.asarray([[True, True], [False, True]])
maps = {
"selected_tile": np.asarray([[0, 1], [-1, 1]], dtype=np.int8),
"tiles": [
{
"tile_map_x": np.zeros((2, 2), dtype=np.float32),
"tile_map_y": np.zeros((2, 2), dtype=np.float32),
},
{
"tile_map_x": np.ones((2, 2), dtype=np.float32),
"tile_map_y": np.ones((2, 2), dtype=np.float32),
},
],
}
semantics = [
np.asarray([[4, 4], [4, 4]], dtype=np.uint8),
np.asarray([[7, 7], [7, 7]], dtype=np.uint8),
]
result = worker._fuse_tiles(semantics, maps, valid_mask)
assert result.tolist() == [[4, 7], [0, 7]]
+106
View File
@@ -0,0 +1,106 @@
from __future__ import annotations
import importlib.util
import json
import sys
from pathlib import Path
from types import ModuleType
import numpy as np
import pytest
def _worker_module() -> ModuleType:
worker_root = Path(__file__).parents[1] / "experiments" / "perception" / "worker"
path = worker_root / "run_e4_full_session_segmentation.py"
spec = importlib.util.spec_from_file_location("e4_full_session_worker", path)
assert spec is not None and spec.loader is not None
sys.path.insert(0, str(worker_root))
try:
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
finally:
sys.path.remove(str(worker_root))
return module
def _profile() -> dict[str, object]:
path = (
Path(__file__).parents[1]
/ "experiments"
/ "perception"
/ "worker"
/ "e3_k1_camera1_profile.json"
)
value = json.loads(path.read_text(encoding="utf-8"))
assert isinstance(value, dict)
return value
def test_e4_accepts_the_sealed_camera1_valid_fov() -> None:
worker = _worker_module()
root = (
Path(__file__).parents[1]
/ ".runtime"
/ "compute-experiments"
/ "e1"
/ "valid-fov"
/ "valid-fov-mask-b4dd8ddf2b87c1d520ee8a0868c4fea062d7c14d1bae73ccabd3abe1f3acbac2"
)
if not root.is_dir():
pytest.skip("real sealed LAB E1 valid-FOV artifact is unavailable")
mask, identity = worker._load_valid_fov(
root,
{"input": {"source_id": "sensor.camera.right"}},
_profile(),
)
assert mask.shape == (600, 800)
assert mask.dtype == np.bool_
assert int(mask.sum()) == 270_606
assert identity["valid_pixel_count"] == 270_606
def test_e4_rejects_valid_fov_from_another_camera() -> None:
worker = _worker_module()
root = (
Path(__file__).parents[1]
/ ".runtime"
/ "compute-experiments"
/ "e1"
/ "valid-fov"
/ "valid-fov-mask-b4dd8ddf2b87c1d520ee8a0868c4fea062d7c14d1bae73ccabd3abe1f3acbac2"
)
if not root.is_dir():
pytest.skip("real sealed LAB E1 valid-FOV artifact is unavailable")
with pytest.raises(RuntimeError, match="valid-FOV binding"):
worker._load_valid_fov(
root,
{"input": {"source_id": "sensor.camera.left"}},
_profile(),
)
def test_e4_overlay_preserves_pixels_outside_semantic_mask() -> None:
worker = _worker_module()
image = np.full((2, 3, 3), 100, dtype=np.uint8)
semantic = np.asarray([[0, 4, 0], [7, 0, 1]], dtype=np.uint8)
overlay = worker._overlay(image, semantic)
assert np.array_equal(overlay[semantic == 0], image[semantic == 0])
assert np.all(np.any(overlay[semantic > 0] != image[semantic > 0], axis=1))
def test_e4_class_fractions_use_only_valid_fov_pixels() -> None:
worker = _worker_module()
semantic = np.asarray([[0, 4, 4], [7, 0, 1]], dtype=np.uint8)
valid = np.asarray([[False, True, True], [True, False, True]])
names = {index: f"class-{index}" for index in range(16)}
classes = worker._class_document(semantic, valid, names)
assert {item["id"]: item["pixels"] for item in classes} == {1: 1, 4: 2, 7: 1}
assert sum(float(item["fraction_of_valid_fov"]) for item in classes) == 1.0
+160
View File
@@ -0,0 +1,160 @@
from __future__ import annotations
import importlib.util
import json
import math
import sys
from pathlib import Path
from types import ModuleType
import numpy as np
import pytest
def _worker_module() -> ModuleType:
worker_root = Path(__file__).parents[1] / "experiments" / "perception" / "worker"
path = worker_root / "run_e5_instance_tracking.py"
sys.path.insert(0, str(worker_root))
try:
spec = importlib.util.spec_from_file_location("e5_instance_tracking_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"
/ "e5_yolox_bytetrack_profile.json"
)
def _detection(*, score: float, x: float = 100, class_id: int = 0) -> dict[str, object]:
return {
"class_id": class_id,
"label": "person" if class_id == 0 else "car",
"score": score,
"bbox_xyxy": [x, 100.0, x + 60.0, 220.0],
"valid_fov_fraction": 1.0,
}
def test_profile_is_pinned_and_semantically_valid() -> None:
worker = _worker_module()
profile, digest = worker._read_profile(_profile_path())
assert len(digest) == 64
assert profile["model"]["id"] == "yolox_s"
assert profile["model"]["model_sha256"] == (
"c5c2d13e59ae883e6af3b45daea64af4833a4951c92d116ec270d9ddbe998063"
)
assert profile["tracking"]["algorithm"] == "bytetrack-style-two-stage-iou/v1"
assert profile["detection"]["target_class_ids"] == [0, 1, 2, 3, 5, 7]
def test_profile_rejects_duplicate_target_classes(tmp_path: Path) -> None:
worker = _worker_module()
profile = json.loads(_profile_path().read_text(encoding="utf-8"))
profile["detection"]["target_class_ids"] = [0, 0]
path = tmp_path / "profile.json"
path.write_text(json.dumps(profile), encoding="utf-8")
with pytest.raises(RuntimeError, match="target class"):
worker._read_profile(path)
def test_valid_fraction_uses_box_area_and_center_gate() -> None:
worker = _worker_module()
mask = np.zeros((10, 10), dtype=bool)
mask[2:8, 2:8] = True
integral = np.pad(mask.astype(np.int64), ((1, 0), (1, 0))).cumsum(0).cumsum(1)
fraction, center_inside, area = worker._valid_fraction(
np.asarray([1.0, 1.0, 5.0, 5.0]), integral
)
assert area == 16
assert fraction == pytest.approx(9 / 16)
assert center_inside is True
def test_yolox_decode_and_fov_filter_admit_one_person() -> None:
worker = _worker_module()
profile = json.loads(_profile_path().read_text(encoding="utf-8"))
output = np.zeros((1, 8400, 85), dtype=np.float32)
output[0, 0, :4] = [40.0, 30.0, math.log(10.0), math.log(10.0)]
output[0, 0, 4] = 0.9
output[0, 0, 5] = 0.9
detections, rejected = worker._detections(
output,
profile,
np.ones((600, 800), dtype=bool),
)
assert rejected == {}
assert len(detections) == 1
assert detections[0]["label"] == "person"
assert detections[0]["score"] == pytest.approx(0.81)
assert detections[0]["bbox_xyxy"] == pytest.approx([350.0, 250.0, 450.0, 350.0])
def test_nms_suppresses_lower_score_box_contained_inside_object() -> None:
worker = _worker_module()
boxes = np.asarray(
[
[0.0, 0.0, 100.0, 100.0],
[10.0, 10.0, 60.0, 60.0],
]
)
scores = np.asarray([0.9, 0.5])
assert worker._nms(boxes, scores, 0.45, 0.8) == [0]
def test_two_stage_tracker_keeps_id_through_low_score_detection() -> None:
worker = _worker_module()
profile = json.loads(_profile_path().read_text(encoding="utf-8"))
tracker = worker.TwoStageTracker(profile["tracking"])
assert tracker.update([_detection(score=0.8)], 0) == []
second = tracker.update([_detection(score=0.7, x=103)], 1)
third = tracker.update([_detection(score=0.15, x=106)], 2)
assert [track.track_id for track in second] == [1]
assert [track.track_id for track in third] == [1]
assert third[0].hits == 3
assert tracker.created == 1
def test_tracker_does_not_cross_match_classes() -> None:
worker = _worker_module()
profile = json.loads(_profile_path().read_text(encoding="utf-8"))
tracker = worker.TwoStageTracker(profile["tracking"])
tracker.update([_detection(score=0.8)], 0)
tracks = tracker.update([_detection(score=0.8, class_id=2)], 1)
assert tracks == []
assert tracker.created == 2
assert {track.class_id for track in tracker.tracks} == {0, 2}
def test_clip_timeline_may_start_at_nonzero_source_index(tmp_path: Path) -> None:
worker = _worker_module()
path = tmp_path / "timeline.jsonl"
rows = [
{"frame_index": 0, "source_frame_index": 1000, "session_seconds": 135.1},
{"frame_index": 1, "source_frame_index": 1001, "session_seconds": 135.2},
]
path.write_text("\n".join(json.dumps(row) for row in rows) + "\n", encoding="utf-8")
assert worker._read_timeline(path, 2) == rows
+269
View File
@@ -0,0 +1,269 @@
from __future__ import annotations
import importlib.util
import json
import sys
from collections import defaultdict, deque
from pathlib import Path
from types import ModuleType
import numpy as np
def _module() -> ModuleType:
path = (
Path(__file__).parents[1]
/ "experiments"
/ "perception"
/ "fuse_e6_tracking_lidar.py"
)
spec = importlib.util.spec_from_file_location("e6_tracking_lidar", 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
def _profile_path() -> Path:
return (
Path(__file__).parents[1]
/ "experiments"
/ "perception"
/ "e6_tracking_lidar_profile.json"
)
def test_profile_pins_e4_e5_and_tight_sync_gate() -> None:
module = _module()
profile, digest = module._read_profile(_profile_path())
assert len(digest) == 64
assert profile["inputs"]["tracking_result_id"].startswith("e5-tracking-")
assert profile["inputs"]["semantic_result_id"].startswith("result-")
assert profile["temporal"]["maximum_lidar_camera_delta_ms"] == 100.0
assert profile["projection"]["occlusion_policy"] == (
"nearest-depth-per-rounded-pixel"
)
def test_profile_rejects_unsafe_sync_window(tmp_path: Path) -> None:
module = _module()
profile = json.loads(_profile_path().read_text(encoding="utf-8"))
profile["temporal"]["maximum_lidar_camera_delta_ms"] = 500.0
path = tmp_path / "profile.json"
path.write_text(json.dumps(profile), encoding="utf-8")
try:
module._read_profile(path)
except RuntimeError as exc:
assert "contract" in str(exc)
else:
raise AssertionError("unsafe synchronization window was accepted")
def test_depth_buffer_keeps_nearest_point_per_rounded_pixel() -> None:
module = _module()
pixels = np.asarray([[10.2, 20.2], [10.4, 20.4], [12.0, 20.0]])
depths = np.asarray([7.0, 3.0, 5.0])
selected = module._visible_projection_indices(pixels, depths)
assert selected.tolist() == [1, 2]
def test_depth_cluster_prefers_largest_contiguous_group() -> None:
module = _module()
depths = np.asarray([2.0, 2.1, 8.0, 8.1, 8.2])
selected = module._depth_cluster(
np.arange(5, dtype=np.int64),
depths,
minimum_gap_m=0.5,
gap_fraction=0.06,
)
assert selected.tolist() == [2, 3, 4]
def test_box_candidates_apply_inner_roi() -> None:
module = _module()
pixels = np.asarray([[0.0, 0.0], [5.0, 5.0], [50.0, 50.0], [99.0, 99.0]])
inset = {
"horizontal_fraction": 0.05,
"top_fraction": 0.04,
"bottom_fraction": 0.02,
}
selected = module._box_candidates((0.0, 0.0, 100.0, 100.0), pixels, inset)
assert selected.tolist() == [1, 2]
def test_vehicle_group_nms_suppresses_overlapping_car_truck_tracks() -> None:
module = _module()
tracks = [
{
"track_id": 1,
"label": "car",
"score": 0.9,
"bbox_xyxy": [0.0, 0.0, 100.0, 100.0],
},
{
"track_id": 2,
"label": "truck",
"score": 0.4,
"bbox_xyxy": [2.0, 2.0, 102.0, 102.0],
},
{
"track_id": 3,
"label": "person",
"score": 0.8,
"bbox_xyxy": [2.0, 2.0, 102.0, 102.0],
},
]
selected = module._suppress_duplicate_vehicle_tracks(
tracks,
vehicle_labels={"car", "truck", "bus"},
iou_threshold=0.55,
)
assert [item["track_id"] for item in selected] == [1, 3]
def test_spatial_cluster_separates_distant_same_depth_surfaces() -> None:
module = _module()
points = np.asarray(
[[0.0, 0.0, 0.0], [0.2, 0.1, 0.1], [5.0, 0.0, 0.0], [5.2, 0.1, 0.0]]
)
selected = module._spatial_cluster(
np.arange(4, dtype=np.int64),
points,
radius_m=0.5,
)
assert selected.size == 2
assert set(selected.tolist()) in ({0, 1}, {2, 3})
def test_semantic_supported_track_produces_point_cuboid_and_distance() -> None:
module = _module()
profile = json.loads(_profile_path().read_text(encoding="utf-8"))
semantic = np.zeros((600, 800), dtype=np.uint8)
semantic[100:200, 100:200] = 1
pixels = np.asarray([[120.0, 120.0], [130.0, 130.0], [140.0, 140.0]])
depths = np.asarray([5.0, 5.1, 5.2])
points = np.asarray(
[[1.0, 2.0, 0.2], [1.2, 2.1, 0.8], [1.4, 2.2, 1.6]],
dtype=np.float64,
)
tracks = [
{
"track_id": 7,
"label": "person",
"score": 0.9,
"bbox_xyxy": [100.0, 100.0, 200.0, 200.0],
}
]
result = module._fuse_tracks(
tracks=tracks,
semantic_map=semantic,
pixels_xy=pixels,
depths_m=depths,
projected_source_indices=np.arange(3, dtype=np.int64),
points_map=points,
points_lidar=points,
profile=profile,
distance_history=defaultdict(lambda: deque(maxlen=5)),
)
assert len(result) == 1
assert result[0].cuboid is not None
assert result[0].clustered_points == 3
assert result[0].distance_median_m is not None
assert result[0].distance_smoothed_m == result[0].distance_median_m
def test_semantic_mismatch_never_extrudes_rectangle_into_cuboid() -> None:
module = _module()
profile = json.loads(_profile_path().read_text(encoding="utf-8"))
pixels = np.asarray([[120.0, 120.0], [130.0, 130.0], [140.0, 140.0]])
points = np.asarray(
[[1.0, 2.0, 0.2], [1.2, 2.1, 0.8], [1.4, 2.2, 1.6]],
dtype=np.float64,
)
result = module._fuse_tracks(
tracks=[
{
"track_id": 7,
"label": "person",
"score": 0.9,
"bbox_xyxy": [100.0, 100.0, 200.0, 200.0],
}
],
semantic_map=np.full((600, 800), 4, dtype=np.uint8),
pixels_xy=pixels,
depths_m=np.asarray([5.0, 5.1, 5.2]),
projected_source_indices=np.arange(3, dtype=np.int64),
points_map=points,
points_lidar=points,
profile=profile,
distance_history=defaultdict(lambda: deque(maxlen=5)),
)
assert result[0].cuboid is None
assert result[0].status == "rejected-no-semantic-lidar-support"
def test_distance_innovation_rejects_background_jump_for_same_track() -> None:
module = _module()
profile = json.loads(_profile_path().read_text(encoding="utf-8"))
semantic = np.zeros((600, 800), dtype=np.uint8)
semantic[100:200, 100:200] = 1
pixels = np.asarray([[120.0, 120.0], [130.0, 130.0], [140.0, 140.0]])
tracks = [
{
"track_id": 7,
"label": "person",
"score": 0.9,
"bbox_xyxy": [100.0, 100.0, 200.0, 200.0],
}
]
history = defaultdict(lambda: deque(maxlen=5))
near = np.asarray(
[[2.0, 0.0, 0.2], [2.1, 0.1, 0.8], [2.2, 0.2, 1.5]],
dtype=np.float64,
)
far = near + np.asarray([6.0, 0.0, 0.0])
first = module._fuse_tracks(
tracks=tracks,
semantic_map=semantic,
pixels_xy=pixels,
depths_m=np.asarray([2.0, 2.1, 2.2]),
projected_source_indices=np.arange(3, dtype=np.int64),
points_map=near,
points_lidar=near,
profile=profile,
distance_history=history,
)
second = module._fuse_tracks(
tracks=tracks,
semantic_map=semantic,
pixels_xy=pixels,
depths_m=np.asarray([8.0, 8.1, 8.2]),
projected_source_indices=np.arange(3, dtype=np.int64),
points_map=far,
points_lidar=far,
profile=profile,
distance_history=history,
)
assert first[0].cuboid is not None
assert second[0].cuboid is None
assert second[0].status == "rejected-distance-innovation"
+109
View File
@@ -0,0 +1,109 @@
from __future__ import annotations
import importlib.util
import json
import sys
from pathlib import Path
from types import ModuleType
import numpy as np
import pytest
def _worker_module() -> ModuleType:
worker_root = Path(__file__).parents[1] / "experiments" / "perception" / "worker"
path = worker_root / "run_e8_realtime_tracking.py"
sys.path.insert(0, str(worker_root))
try:
spec = importlib.util.spec_from_file_location("e8_realtime_tracking_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(name: str = "e8_realtime_tracking_profile.json") -> Path:
return Path(__file__).parents[1] / "experiments" / "perception" / "worker" / name
def _envelope(worker: ModuleType, index: int) -> object:
return worker.FrameEnvelope(
frame_index=index,
path=Path(f"frame-{index:06d}.png"),
timeline={"source_frame_index": 1000 + index},
scheduled_monotonic=float(index),
decoded_monotonic=float(index),
image=np.zeros((1, 1, 3), dtype=np.uint8),
decode_ms=1.0,
source_release_lag_ms=0.0,
)
def test_e8_profile_pins_realtime_policy_and_e5_model() -> None:
worker = _worker_module()
profile, digest = worker._read_profile(_profile_path())
assert len(digest) == 64
assert profile["model"]["id"] == "yolox_s"
assert profile["realtime"]["queue_policy"] == "bounded-latest-wins"
assert profile["realtime"]["queue_capacity"] == 2
assert profile["acceptance"]["minimum_effective_fps"] == 9.5
assert profile["acceptance"]["expect_overload"] is False
def test_e8_overload_profile_requires_observed_overload() -> None:
worker = _worker_module()
profile, _digest = worker._read_profile(
_profile_path("e8_realtime_tracking_overload_profile.json")
)
assert profile["mode"] == "overload-negative-control"
assert profile["realtime"]["consumer_delay_ms"] == 140.0
assert profile["acceptance"]["expect_overload"] is True
def test_e8_profile_rejects_unbounded_queue(tmp_path: Path) -> None:
worker = _worker_module()
profile = json.loads(_profile_path().read_text(encoding="utf-8"))
profile["realtime"]["queue_capacity"] = 0
path = tmp_path / "profile.json"
path.write_text(json.dumps(profile), encoding="utf-8")
with pytest.raises(RuntimeError, match="scheduling"):
worker._read_profile(path)
def test_e8_latest_wins_queue_discards_oldest_frame() -> None:
worker = _worker_module()
queue = worker.LatestWinsQueue(capacity=2)
queue.publish(_envelope(worker, 1))
queue.publish(_envelope(worker, 2))
queue.publish(_envelope(worker, 3))
queue.close()
assert queue.take().frame_index == 2
assert queue.take().frame_index == 3
assert queue.take() is None
assert queue.snapshot() == {
"capacity": 2,
"final_depth": 0,
"maximum_depth": 2,
"published": 3,
"consumed": 2,
"dropped_overflow": 1,
"closed": True,
}
def test_e8_health_uses_explicit_freshness_thresholds() -> None:
worker = _worker_module()
realtime = {"stale_after_ms": 150.0, "unavailable_after_ms": 500.0}
assert worker._health(149.9, realtime) == "healthy"
assert worker._health(150.0, realtime) == "stale"
assert worker._health(500.0, realtime) == "unavailable"
+97
View File
@@ -0,0 +1,97 @@
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))
+17
View File
@@ -67,3 +67,20 @@ def test_metrics_distinguish_preview_drops_and_pipeline_latency() -> None:
assert snapshot["last_point_count"] == 42
assert snapshot["mqtt_to_publish_ms"] == 12.346
assert snapshot["decode_publish_ms"] == 1.234
def test_metrics_report_live_ai_latency_rate_staleness_and_drops() -> None:
metrics = BridgeMetrics()
metrics.perception_dropped()
metrics.published_perception(
captured_at_epoch_ns=1_000_000_000,
published_at_epoch_ns=1_125_000_000,
published_monotonic_ns=2_000_000_000,
)
snapshot = metrics.snapshot()
assert snapshot["perception_frames"] == 1
assert snapshot["perception_dropped"] == 1
assert snapshot["perception_end_to_end_ms"] == 125.0
assert snapshot["perception_end_to_end_p95_ms"] == 125.0
+337
View File
@@ -0,0 +1,337 @@
from __future__ import annotations
import json
import struct
import numpy as np
import pytest
from k1link.compute.live_perception import (
LIVE_INGRESS_WIRE_SCHEMA,
LatestWinsQueue,
LivePerceptionIngress,
WorldStateProjector,
classify_health,
decode_live_perception_result,
encode_live_perception_result,
)
def test_live_ingress_keeps_modalities_separately_bounded_and_ordered() -> None:
ingress = LivePerceptionIngress()
ingress.open_consumer("worker-1")
ingress.begin_session("session-1")
for sequence in range(5):
assert ingress.publish(
modality="camera-frame",
source_id="sensor.camera.right",
source_sequence=sequence,
captured_at_epoch_ns=100 + sequence,
received_monotonic_ns=200 + sequence,
payload=f"camera-{sequence}".encode(),
)
for sequence in range(3):
assert ingress.publish(
modality="lidar",
source_id="lixel/application/report/lio_pcl",
source_sequence=sequence,
captured_at_epoch_ns=300 + sequence,
received_monotonic_ns=400 + sequence,
payload=f"lidar-{sequence}".encode(),
)
for sequence in range(20):
assert ingress.publish(
modality="pose",
source_id="lixel/application/report/lio_pose",
source_sequence=sequence,
captured_at_epoch_ns=500 + sequence,
received_monotonic_ns=600 + sequence,
payload=f"pose-{sequence}".encode(),
)
snapshot = ingress.snapshot()
assert snapshot["queues"]["camera-frame"]["depth"] == 2
assert snapshot["queues"]["camera-frame"]["dropped_overflow"] == 3
assert snapshot["queues"]["lidar"]["depth"] == 2
assert snapshot["queues"]["lidar"]["dropped_overflow"] == 1
assert snapshot["queues"]["pose"]["depth"] == 16
assert snapshot["queues"]["pose"]["dropped_overflow"] == 4
events = []
while (event := ingress.take_next("worker-1", timeout=0)) is not None:
events.append(event)
assert events[0].modality == "control"
assert [event.ingress_sequence for event in events] == sorted(
event.ingress_sequence for event in events
)
assert [event.source_sequence for event in events if event.modality == "camera-frame"] == [
3,
4,
]
assert [event.source_sequence for event in events if event.modality == "lidar"] == [1, 2]
assert [event.source_sequence for event in events if event.modality == "pose"] == list(
range(4, 20)
)
def test_live_ingress_wire_is_self_delimiting_and_explicitly_non_authoritative() -> None:
ingress = LivePerceptionIngress()
ingress.open_consumer("worker-1")
ingress.begin_session("session-1")
assert ingress.publish(
modality="camera-init",
source_id="sensor.camera.right",
source_sequence=0,
captured_at_epoch_ns=123,
received_monotonic_ns=456,
payload=b"init",
)
ingress.take_next("worker-1", timeout=0)
event = ingress.take_next("worker-1", timeout=0)
assert event is not None
encoded = event.wire_bytes()
header_bytes = struct.unpack("!I", encoded[:4])[0]
header = json.loads(encoded[4 : 4 + header_bytes])
assert header["schema_version"] == LIVE_INGRESS_WIRE_SCHEMA
assert header["payload_bytes"] == 4
assert header["commands_enabled"] is False
assert header["navigation_or_safety_accepted"] is False
assert encoded[4 + header_bytes :] == b"init"
def test_live_ingress_rejects_oversize_without_affecting_other_modalities() -> None:
ingress = LivePerceptionIngress()
ingress.begin_session("session-1")
assert not ingress.publish(
modality="camera-frame",
source_id="sensor.camera.right",
source_sequence=1,
captured_at_epoch_ns=1,
received_monotonic_ns=1,
payload=b"x" * (1024 * 1024 + 1),
)
assert ingress.publish(
modality="pose",
source_id="RealtimePath",
source_sequence=2,
captured_at_epoch_ns=2,
received_monotonic_ns=2,
payload=b"pose",
)
snapshot = ingress.snapshot()
assert snapshot["queues"]["camera-frame"]["rejected_oversize"] == 1
assert snapshot["queues"]["pose"]["published"] == 1
def test_live_ingress_allows_only_one_worker_consumer() -> None:
ingress = LivePerceptionIngress()
ingress.open_consumer("worker-1")
with pytest.raises(RuntimeError, match="already has a consumer"):
ingress.open_consumer("worker-2")
ingress.close_consumer("worker-1")
ingress.open_consumer("worker-2")
def test_live_result_round_trip_keeps_video_mask_boxes_and_shadow_authority() -> None:
mask = np.zeros((600, 800), dtype=np.uint8)
mask[100:120, 200:240] = 4
encoded = encode_live_perception_result(
frame_index=12,
source_frame_index=44,
session_seconds=1.25,
captured_at_epoch_ns=123_000_000,
image_jpeg=b"\xff\xd8test\xff\xd9",
segmentation_mask=mask,
objects=[
{
"track_id": 7,
"label": "car",
"score": 0.91,
"bbox_xyxy": [10, 20, 110, 80],
"cuboid_center_map": [1, 2, 0.5],
"cuboid_half_size": [2.25, 0.925, 0.775],
"cuboid_quaternion_xyzw": [0, 0, 0, 1],
}
],
delivery={"health": "healthy", "result_age_ms": 49.0},
)
frame = decode_live_perception_result(encoded)
assert frame.frame_index == 12
assert frame.source_frame_index == 44
assert frame.image_jpeg == b"\xff\xd8test\xff\xd9"
assert frame.segmentation_mask is not None
assert np.array_equal(frame.segmentation_mask, mask)
assert frame.objects[0]["bbox_xyxy"] == [10.0, 20.0, 110.0, 80.0]
assert frame.objects[0]["cuboid_center_map"] == [1.0, 2.0, 0.5]
assert frame.delivery["health"] == "healthy"
def test_live_result_rejects_tampering_and_partial_cuboid() -> None:
with pytest.raises(ValueError, match="cuboid is incomplete"):
encode_live_perception_result(
frame_index=0,
source_frame_index=0,
session_seconds=0.0,
captured_at_epoch_ns=1,
image_jpeg=b"\xff\xd8x\xff\xd9",
segmentation_mask=None,
objects=[
{
"track_id": 1,
"label": "car",
"score": 0.5,
"bbox_xyxy": [0, 0, 1, 1],
"cuboid_center_map": [0, 0, 0],
}
],
delivery={"health": "degraded"},
)
encoded = encode_live_perception_result(
frame_index=0,
source_frame_index=0,
session_seconds=0.0,
captured_at_epoch_ns=1,
image_jpeg=b"\xff\xd8x\xff\xd9",
segmentation_mask=None,
objects=[],
delivery={"health": "healthy"},
)
changed = bytearray(encoded)
changed[-3] ^= 0x01
with pytest.raises(ValueError, match="contract is invalid"):
decode_live_perception_result(bytes(changed))
def test_latest_wins_queue_never_exceeds_capacity() -> None:
queue = LatestWinsQueue[int](capacity=2)
queue.publish(1)
queue.publish(2)
queue.publish(3)
assert queue.take_next(timeout=0) == 2
assert queue.take_next(timeout=0) == 3
snapshot = queue.snapshot()
assert snapshot.maximum_depth == 2
assert snapshot.depth == 0
assert snapshot.dropped_overflow == 1
assert snapshot.dropped_superseded == 0
assert snapshot.dropped_total == 1
def test_closed_empty_queue_returns_none() -> None:
queue = LatestWinsQueue[str](capacity=1)
queue.close()
assert queue.take_next(timeout=0) is None
assert queue.snapshot().closed is True
def test_health_distinguishes_depth_degradation_from_staleness() -> None:
assert classify_health(
source_available=True,
fusion_state="fused",
result_age_ms=25.0,
stale_after_ms=300.0,
unavailable_after_ms=1000.0,
) == ("healthy", ())
assert classify_health(
source_available=True,
fusion_state="depth-unavailable-sync-gate",
result_age_ms=25.0,
stale_after_ms=300.0,
unavailable_after_ms=1000.0,
) == ("degraded", ("depth-unavailable-sync-gate",))
assert classify_health(
source_available=True,
fusion_state="fused",
result_age_ms=350.0,
stale_after_ms=300.0,
unavailable_after_ms=1000.0,
) == ("stale", ("result-age-exceeded",))
assert classify_health(
source_available=False,
fusion_state="fused",
result_age_ms=0.0,
stale_after_ms=300.0,
unavailable_after_ms=1000.0,
) == ("unavailable", ("source-unavailable",))
def test_world_state_contains_metric_position_size_range_and_velocity() -> None:
projector = WorldStateProjector(velocity_history_limit_s=1.0)
accepted = {
"track_id": 7,
"label": "car",
"association_group": "vehicle",
"score": 0.8,
"clustered_points": 12,
"distance_smoothed_m": 5.0,
"cuboid_status": "accepted-point-supported-oriented-p05-p95",
"cuboid_center_map": [1.0, 2.0, 0.5],
"cuboid_half_size": [2.0, 1.0, 0.75],
"cuboid_quaternion_xyzw": [0.0, 0.0, 0.0, 1.0],
}
base = {
"frame_index": 0,
"source_frame_index": 1000,
"session_seconds": 10.0,
"state": "fused",
"objects": [
accepted,
{**accepted, "track_id": 9, "cuboid_status": "rejected-distance-innovation"},
],
}
first = projector.project(
frame=base,
lidar_positions={7: [4.0, 0.0, 0.0]},
clearance={"front_m": 4.0},
)
states = [first]
for index, elapsed in enumerate((0.2, 0.4, 0.6), start=1):
states.append(
projector.project(
frame={
**base,
"frame_index": index,
"session_seconds": 10.0 + elapsed,
"objects": [
{
**accepted,
"cuboid_center_map": [1.0 + 2.0 * elapsed, 2.0, 0.5],
}
],
},
lidar_positions={7: [3.0, 0.0, 0.0]},
clearance={"front_m": 3.0},
)
)
second = states[-1]
assert first["object_count"] == 1
assert first["objects"][0]["size_m"] == [4.0, 2.0, 1.5]
assert first["objects"][0]["position_lidar_m"] == [4.0, 0.0, 0.0]
assert first["objects"][0]["velocity_map_mps"] is None
assert second["objects"][0]["velocity_map_mps"] == pytest.approx([2.0, 0.0, 0.0])
assert second["objects"][0]["speed_mps"] == pytest.approx(2.0)
assert second["objects"][0]["velocity_status"] == "diagnostic-robust-history"
def test_world_state_declares_missing_vehicle_body_transform() -> None:
state = WorldStateProjector().project(
frame={
"frame_index": 0,
"source_frame_index": 1,
"session_seconds": 1.0,
"state": "depth-unavailable-sync-gate",
"objects": [],
},
lidar_positions={},
clearance={"state": "unavailable"},
)
assert state["coordinate_frames"]["sensor_relative"] == "k1-lidar"
assert state["coordinate_frames"]["vehicle_body"].startswith("unavailable")
+99
View File
@@ -0,0 +1,99 @@
from __future__ import annotations
import asyncio
import stat
import threading
from pathlib import Path
import numpy as np
from k1link.compute.live_perception import (
LivePerceptionIngress,
encode_live_perception_result,
)
from k1link.device_plugins.xgrids_k1.live_perception_shadow import (
build_live_perception_shadow_router,
ensure_live_shadow_token,
)
def test_shadow_token_is_stable_and_private(tmp_path: Path) -> None:
path, token = ensure_live_shadow_token(tmp_path)
repeated_path, repeated_token = ensure_live_shadow_token(tmp_path)
assert repeated_path == path
assert repeated_token == token
assert stat.S_IMODE(path.stat().st_mode) == 0o600
assert stat.S_IMODE(path.parent.stat().st_mode) == 0o700
def test_shadow_router_exposes_only_the_exclusive_binary_stream() -> None:
ingress = LivePerceptionIngress()
router = build_live_perception_shadow_router(
ingress,
"test-plugin",
bearer_token="x" * 43,
)
assert len(router.routes) == 1
assert router.routes[0].path == (
"/api/v1/device-plugins/test-plugin/live-perception-shadow"
)
def test_shadow_router_accepts_only_validated_diagnostic_results_back() -> None:
ingress = LivePerceptionIngress()
received: list[bytes] = []
published = threading.Event()
def receive_result(payload: bytes) -> bool:
received.append(payload)
published.set()
return True
router = build_live_perception_shadow_router(
ingress,
"test-plugin",
bearer_token="x" * 43,
result_receiver=receive_result,
)
ingress.begin_session("session-1")
encoded = encode_live_perception_result(
frame_index=0,
source_frame_index=0,
session_seconds=0.0,
captured_at_epoch_ns=1,
image_jpeg=bytes.fromhex("ffd878ffd9"),
segmentation_mask=np.zeros((600, 800), dtype=np.uint8),
objects=[],
delivery={"health": "healthy"},
)
class FakeWebSocket:
def __init__(self) -> None:
self.headers = {"authorization": f"Bearer {'x' * 43}"}
self.messages = [
{"type": "websocket.receive", "bytes": encoded},
{"type": "websocket.disconnect"},
]
self.sent: list[bytes] = []
self.accepted = False
async def accept(self) -> None:
self.accepted = True
async def receive(self) -> dict[str, object]:
await asyncio.sleep(0)
return self.messages.pop(0)
async def send_bytes(self, payload: bytes) -> None:
self.sent.append(payload)
async def close(self, **_: object) -> None:
return
websocket = FakeWebSocket()
asyncio.run(router.routes[0].endpoint(websocket)) # type: ignore[attr-defined]
assert websocket.accepted is True
assert published.is_set()
assert received == [encoded]
+118
View File
@@ -0,0 +1,118 @@
from __future__ import annotations
import threading
import time
from k1link.compute.live_perception import LiveSensorSynchronizer
from k1link.data_plane import ConsumerFrameContext, DecodedPointCloudView, DecodedPoseView
def _context(sequence: int, epoch_ns: int) -> ConsumerFrameContext:
return ConsumerFrameContext(
sequence=sequence,
captured_at_epoch_ns=epoch_ns,
received_monotonic_ns=epoch_ns,
processing_started_monotonic_ns=epoch_ns,
encoded_size_bytes=1,
live=True,
)
def _points(sequence: int, epoch_ns: int) -> DecodedPointCloudView:
return DecodedPointCloudView(
context=_context(sequence, epoch_ns),
frame_id="map",
positions_xyz=((1.0, 2.0, 3.0),),
intensities=b"\x01",
)
def _pose(sequence: int, epoch_ns: int) -> DecodedPoseView:
return DecodedPoseView(
context=_context(sequence, epoch_ns),
frame_id="map",
child_frame_id="sensor",
position_xyz=(0.0, 0.0, 0.0),
orientation_xyzw=(0.0, 0.0, 0.0, 1.0),
)
def test_live_sensor_synchronizer_selects_nearest_bounded_pair() -> None:
synchronizer = LiveSensorSynchronizer(
maximum_lidar_camera_delta_ms=100,
maximum_pose_point_delta_ms=100,
)
synchronizer.publish_point_cloud(_points(1, 1_000_000_000))
synchronizer.publish_point_cloud(_points(2, 1_090_000_000))
synchronizer.publish_pose(_pose(1, 1_020_000_000))
synchronizer.publish_pose(_pose(2, 1_095_000_000))
binding = synchronizer.bind_camera(1_080_000_000)
assert binding.state == "fused-ready"
assert binding.point_cloud is not None
assert binding.point_cloud.context.sequence == 2
assert binding.pose is not None
assert binding.pose.context.sequence == 2
assert binding.lidar_camera_delta_ms == 10.0
assert binding.pose_point_delta_ms == 5.0
def test_live_sensor_synchronizer_reports_each_fail_closed_boundary() -> None:
synchronizer = LiveSensorSynchronizer(
maximum_lidar_camera_delta_ms=20,
maximum_pose_point_delta_ms=10,
)
assert synchronizer.bind_camera(1_000_000_000).state == "lidar-unavailable"
synchronizer.publish_point_cloud(_points(1, 900_000_000))
assert (
synchronizer.bind_camera(1_000_000_000).state
== "lidar-camera-delta-exceeded"
)
synchronizer.publish_point_cloud(_points(2, 1_000_000_000))
assert synchronizer.bind_camera(1_000_000_000).state == "pose-unavailable"
synchronizer.publish_pose(_pose(1, 1_100_000_000))
assert synchronizer.bind_camera(1_000_000_000).state == "pose-point-delta-exceeded"
def test_live_sensor_synchronizer_waits_only_for_bounded_inflight_pair() -> None:
synchronizer = LiveSensorSynchronizer(
maximum_lidar_camera_delta_ms=100,
maximum_pose_point_delta_ms=100,
)
def publish() -> None:
time.sleep(0.02)
synchronizer.publish_point_cloud(_points(1, 1_000_000_000))
synchronizer.publish_pose(_pose(1, 1_000_000_000))
thread = threading.Thread(target=publish)
thread.start()
started = time.monotonic()
binding = synchronizer.bind_camera(1_000_000_000, wait_seconds=0.2)
elapsed = time.monotonic() - started
thread.join()
assert binding.state == "fused-ready"
assert 0.01 <= elapsed < 0.15
def test_live_sensor_synchronizer_storage_never_exceeds_capacity() -> None:
synchronizer = LiveSensorSynchronizer(
maximum_lidar_camera_delta_ms=100,
maximum_pose_point_delta_ms=100,
capacity_per_modality=3,
retention_seconds=100,
)
for sequence in range(1, 8):
synchronizer.publish_point_cloud(_points(sequence, sequence * 1_000_000))
synchronizer.publish_pose(_pose(sequence, sequence * 1_000_000))
snapshot = synchronizer.snapshot()
assert snapshot["point_depth"] == 3
assert snapshot["pose_depth"] == 3
assert snapshot["evicted_points"] == 4
assert snapshot["evicted_poses"] == 4
+88
View File
@@ -0,0 +1,88 @@
from __future__ import annotations
import json
from pathlib import Path
import pytest
from k1link.compute.live_perception import TELEMETRY_SCHEMA, WORLD_STATE_SCHEMA
from k1link.compute.live_replay_qualification import (
_validate_telemetry_rows,
_validate_world_rows,
)
from k1link.sessions import SessionIntegrityError
def _world_row() -> dict[str, object]:
return {
"schema_version": WORLD_STATE_SCHEMA,
"frame_index": 3,
"source_frame_index": 1003,
"session_seconds": 12.3,
"coordinate_frames": {
"world": "k1-map",
"sensor_relative": "k1-lidar",
"vehicle_body": "unavailable-no-rig-to-vehicle-transform",
},
"fusion_state": "fused",
"objects": [
{
"track_id": 7,
"range_m": 4.0,
"position_map_m": [1.0, 2.0, 3.0],
"position_lidar_m": [4.0, 0.0, 0.0],
"size_m": [4.0, 2.0, 1.5],
"velocity_map_mps": None,
"velocity_status": "unavailable-insufficient-history",
"geometry": "point-supported-visible-surface-envelope",
}
],
"object_count": 1,
"clearance": {"state": "observed"},
"delivery": {"health": "healthy", "result_age_ms": 12.0},
}
def test_world_and_telemetry_rows_preserve_exact_frame_binding(tmp_path: Path) -> None:
world = tmp_path / "world-state.jsonl"
telemetry = tmp_path / "telemetry.jsonl"
world.write_text(json.dumps(_world_row()) + "\n", encoding="utf-8")
telemetry.write_text(
json.dumps(
{
"schema_version": TELEMETRY_SCHEMA,
"frame_index": 3,
"end_to_end_latency_ms": 12.0,
"health": "healthy",
}
)
+ "\n",
encoding="utf-8",
)
indices = _validate_world_rows(
world,
tmp_path,
expected_count=1,
selection_start=3,
selection_count=1,
)
_validate_telemetry_rows(telemetry, tmp_path, expected_indices=indices)
assert indices == (3,)
def test_world_row_rejects_invented_object_count(tmp_path: Path) -> None:
world = tmp_path / "world-state.jsonl"
value = _world_row()
value["object_count"] = 2
world.write_text(json.dumps(value) + "\n", encoding="utf-8")
with pytest.raises(SessionIntegrityError, match="world-state row"):
_validate_world_rows(
world,
tmp_path,
expected_count=1,
selection_start=3,
selection_count=1,
)
@@ -0,0 +1,113 @@
from __future__ import annotations
import importlib.util
import plistlib
import sqlite3
from pathlib import Path
from types import ModuleType, SimpleNamespace
import pytest
REPOSITORY_ROOT = Path(__file__).parents[1]
MODULE_PATH = (
REPOSITORY_ROOT
/ "plugins"
/ "xgrids-k1"
/ "lab"
/ "iphone-capture"
/ "targeted_profile_backup.py"
)
def _load_module() -> ModuleType:
spec = importlib.util.spec_from_file_location("targeted_profile_backup", MODULE_PATH)
assert spec is not None
assert spec.loader is not None
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
return module
TARGETED = _load_module()
def _synthetic_backup(tmp_path: Path, payload: bytes) -> Path:
device = tmp_path / "device"
device.mkdir()
(device / "Manifest.plist").write_bytes(
plistlib.dumps({"IsEncrypted": False}, fmt=plistlib.FMT_BINARY)
)
file_id = TARGETED.PREFERENCES_FILE_ID
source = device / file_id[:2] / file_id
source.parent.mkdir()
source.write_bytes(payload)
with sqlite3.connect(device / "Manifest.db") as connection:
connection.execute(
"CREATE TABLE Files (fileID TEXT, domain TEXT, relativePath TEXT)"
)
connection.execute(
"INSERT INTO Files VALUES (?, ?, ?)",
(file_id, TARGETED.APP_DOMAIN, TARGETED.PREFERENCES_PATH),
)
return device
def test_profile_filter_is_exact_to_lixelgo_preferences() -> None:
assert TARGETED._is_preferences_backup_file(
SimpleNamespace(
file_name=None,
device_name=None,
domain=TARGETED.APP_DOMAIN,
relative_path=TARGETED.PREFERENCES_PATH,
)
)
assert not TARGETED._is_preferences_backup_file(
SimpleNamespace(
file_name=None,
device_name=None,
domain=TARGETED.APP_DOMAIN,
relative_path="Documents/large-project.las",
)
)
assert not TARGETED._is_preferences_backup_file(
SimpleNamespace(
file_name=None,
device_name=None,
domain="AppDomain-com.example.Other",
relative_path=TARGETED.PREFERENCES_PATH,
)
)
def test_profile_file_id_filter_matches_only_the_exact_backup_payload() -> None:
file_id = TARGETED.PREFERENCES_FILE_ID
assert TARGETED._is_preferences_backup_file(
SimpleNamespace(file_name=f"device/{file_id[:2]}/{file_id}")
)
assert TARGETED._is_preferences_backup_file(
SimpleNamespace(file_name=None, device_name=f"device/{file_id[:2]}/{file_id}")
)
assert not TARGETED._is_preferences_backup_file(
SimpleNamespace(file_name=f"device/{file_id[:2]}/{file_id}0")
)
assert not TARGETED._is_preferences_backup_file(
SimpleNamespace(file_name="device/aa/" + "a" * 40)
)
def test_read_preferences_accepts_one_small_unencrypted_plist(tmp_path: Path) -> None:
payload = plistlib.dumps({"opaque-key": "opaque-value"}, fmt=plistlib.FMT_BINARY)
device = _synthetic_backup(tmp_path, payload)
assert TARGETED._read_preferences(device) == payload
def test_read_preferences_rejects_encrypted_backup(tmp_path: Path) -> None:
payload = plistlib.dumps({"opaque-key": "opaque-value"}, fmt=plistlib.FMT_BINARY)
device = _synthetic_backup(tmp_path, payload)
(device / "Manifest.plist").write_bytes(
plistlib.dumps({"IsEncrypted": True}, fmt=plistlib.FMT_BINARY)
)
with pytest.raises(TARGETED.TargetedProfileBackupError, match="encrypted"):
TARGETED._read_preferences(device)
+21
View File
@@ -183,6 +183,27 @@ def test_capture_writes_verifiable_frames_metadata_and_summary(tmp_path: Path) -
assert stat.S_IMODE((capture_dir / artifact_name).stat().st_mode) == 0o600
def test_capture_without_duration_runs_until_explicit_stop(tmp_path: Path) -> None:
fake = FakeClient()
stop_checks = 0
def should_stop() -> bool:
nonlocal stop_checks
stop_checks += 1
return stop_checks >= 4
summary = capture_mqtt(
"192.168.1.50",
tmp_path / "unbounded-capture",
duration_seconds=None,
should_stop=should_stop,
_client_factory=lambda: cast(mqtt.Client, fake),
)
assert summary["requested_duration_seconds"] is None
assert summary["stop_reason"] == "external_stop"
def test_oversize_payload_is_not_written_to_raw_capture(tmp_path: Path) -> None:
fake = FakeClient(payload=b"oversize")
capture_dir = tmp_path / "capture"
@@ -0,0 +1,75 @@
from __future__ import annotations
import json
from pathlib import Path
import pytest
from k1link.compute.multirate_perception_qualification import (
MERGED_FRAME_SCHEMA,
_validate_merged_rows,
)
from k1link.sessions import SessionIntegrityError
def _merged(index: int, semantic: dict[str, object]) -> dict[str, object]:
return {
"schema_version": MERGED_FRAME_SCHEMA,
"frame_index": index,
"source_frame_index": 1000 + index,
"session_seconds": 20.0 + index * 0.1,
"detector_result_age_ms": 80.0,
"tracks": [],
"semantic": semantic,
}
def test_merged_rows_allow_explicit_unavailable_then_fresh(tmp_path: Path) -> None:
path = tmp_path / "merged-frames.jsonl"
unavailable = {
"status": "unavailable",
"source_frame_index": None,
"source_age_ms": None,
"completion_age_ms": None,
"mask_sha256": None,
}
fresh = {
"status": "fresh",
"source_frame_index": 1000,
"source_age_ms": 200.0,
"completion_age_ms": 210.0,
"mask_sha256": "a" * 64,
}
path.write_text(
json.dumps(_merged(0, unavailable)) + "\n" + json.dumps(_merged(2, fresh)) + "\n",
encoding="utf-8",
)
_validate_merged_rows(
path,
tmp_path,
expected_indices=(0, 2),
source_start=1000,
semantic_indices={0},
)
def test_merged_rows_reject_future_semantic_binding(tmp_path: Path) -> None:
path = tmp_path / "merged-frames.jsonl"
future = {
"status": "fresh",
"source_frame_index": 1005,
"source_age_ms": 0.0,
"completion_age_ms": 200.0,
"mask_sha256": "a" * 64,
}
path.write_text(json.dumps(_merged(2, future)) + "\n", encoding="utf-8")
with pytest.raises(SessionIntegrityError, match="binding"):
_validate_merged_rows(
path,
tmp_path,
expected_indices=(2,),
source_start=1000,
semantic_indices={5},
)
+380
View File
@@ -0,0 +1,380 @@
from __future__ import annotations
import hashlib
import json
from datetime import UTC, datetime
from pathlib import Path
from typing import Any
import numpy as np
import pytest
from PIL import Image
from k1link.compute import (
EvaluationFrameRequest,
RecordedEvaluationPackError,
RecordedQualificationSliceError,
prepare_camera_compute_job,
prepare_recorded_evaluation_pack,
prepare_recorded_qualification_slice,
validate_recorded_evaluation_pack,
validate_recorded_qualification_slice,
)
from k1link.device_plugins.xgrids_k1.analyze import (
K1ValidFovMaskError,
prepare_k1_valid_fov_mask,
validate_k1_valid_fov_mask,
)
from k1link.device_plugins.xgrids_k1.calibration_schema import (
parse_k1_factory_calibration,
)
from k1link.device_plugins.xgrids_k1.calibration_snapshot import (
CALIBRATION_SNAPSHOT_MANIFEST_VERSION,
)
from k1link.web.camera_archive import CameraArchiveWriter
CALIBRATION_FIXTURES = Path(__file__).parent / "fixtures" / "k1" / "calibration"
def _box(box_type: bytes, payload: bytes = b"") -> bytes:
return (8 + len(payload)).to_bytes(4, "big") + box_type + payload
def _full_box(box_type: bytes, payload: bytes = b"", *, flags: int = 0) -> bytes:
return _box(box_type, bytes([0]) + flags.to_bytes(3, "big") + payload)
def _recorded_h264_fixture(base_decode_time: int = 0) -> tuple[bytes, bytes]:
track_id = 1
sample_duration = 500
tkhd = _full_box(
b"tkhd",
b"\x00" * 8 + track_id.to_bytes(4, "big") + b"\x00" * 4,
)
mdhd = _full_box(
b"mdhd",
b"\x00" * 8 + (1_000).to_bytes(4, "big") + b"\x00" * 4,
)
hdlr = _full_box(b"hdlr", b"\x00" * 4 + b"vide")
trak = _box(b"trak", tkhd + _box(b"mdia", mdhd + hdlr))
trex = _full_box(
b"trex",
track_id.to_bytes(4, "big")
+ (1).to_bytes(4, "big")
+ sample_duration.to_bytes(4, "big")
+ b"\x00" * 8,
)
init = _box(b"ftyp", b"isom") + _box(
b"moov",
trak + _box(b"mvex", trex) + _box(b"avcC", b"\x01\x64\x00\x28"),
)
tfhd = _full_box(b"tfhd", track_id.to_bytes(4, "big"), flags=0x020000)
tfdt = _full_box(b"tfdt", base_decode_time.to_bytes(4, "big"))
trun = _full_box(b"trun", (1).to_bytes(4, "big"))
fragment = _box(b"moof", _box(b"traf", tfhd + tfdt + trun)) + _box(
b"mdat",
b"frame",
)
return init, fragment
def _camera_job(tmp_path: Path, frame_count: int = 9) -> Path:
session = tmp_path / "session-qualification"
session.mkdir()
init, _fragment = _recorded_h264_fixture()
writer = CameraArchiveWriter(session, "sensor.camera.right", 1)
writer.append(
"init",
init,
host_epoch_ns=1_000_000_000,
host_monotonic_ns=2_000_000_000,
)
for index in range(frame_count):
_init, fragment = _recorded_h264_fixture(index * 500)
writer.append(
"media",
fragment,
host_epoch_ns=1_500_000_000 + index * 500_000_000,
host_monotonic_ns=2_500_000_000 + index * 500_000_000,
)
writer.close()
return prepare_camera_compute_job(
session_root=session,
source_id="sensor.camera.right",
codec_epoch=1,
origin_epoch_ns=1_000_000_000,
origin_monotonic_ns=2_000_000_000,
output_root=tmp_path / "jobs",
).job_root
def _calibration_snapshot(tmp_path: Path) -> Path:
root = tmp_path / "calibration"
root.mkdir()
camera = (CALIBRATION_FIXTURES / "camera.yaml").read_bytes()
extrinsic = (CALIBRATION_FIXTURES / "extrinsic_camera_lidar.yaml").read_bytes()
(root / "camera.yaml").write_bytes(camera)
(root / "extrinsic_camera_lidar.yaml").write_bytes(extrinsic)
vendor_device_id = "fixture-device"
device_serial = "fixture-serial"
artifact_values = (
(
"/mnt/system/factory-data/config/camera.yaml",
"camera.yaml",
camera,
),
(
"/mnt/system/factory-data/config/extrinsic_camera_lidar.yaml",
"extrinsic_camera_lidar.yaml",
extrinsic,
),
)
artifacts = [
{
"source_path": source_path,
"artifact_name": name,
"sha256": hashlib.sha256(payload).hexdigest(),
"bytes": len(payload),
"encoding": "utf-8",
}
for source_path, name, payload in artifact_values
]
content_identity = hashlib.sha256()
content_identity.update(vendor_device_id.encode("ascii"))
content_identity.update(b"\x00")
content_identity.update(device_serial.encode("ascii"))
for artifact in sorted(artifacts, key=lambda item: str(item["source_path"])):
content_identity.update(b"\x00")
content_identity.update(str(artifact["source_path"]).encode("utf-8"))
content_identity.update(bytes.fromhex(str(artifact["sha256"])))
calibration = parse_k1_factory_calibration(camera, extrinsic)
manifest = {
"schema_version": CALIBRATION_SNAPSHOT_MANIFEST_VERSION,
"captured_at_utc": datetime.now(UTC).isoformat(),
"content_identity_sha256": content_identity.hexdigest(),
"device": {
"vendor_device_id": vendor_device_id,
"device_serial": device_serial,
},
"artifacts": artifacts,
"normalized_calibration": calibration.normalized_profile(),
}
(root / "manifest.json").write_text(json.dumps(manifest), encoding="utf-8")
return root
def test_valid_fov_mask_is_calibration_bound_binary_and_reusable(tmp_path: Path) -> None:
snapshot = _calibration_snapshot(tmp_path)
first = prepare_k1_valid_fov_mask(
calibration_snapshot_root=snapshot,
source_id="sensor.camera.right",
output_root=tmp_path / "masks",
)
repeated = prepare_k1_valid_fov_mask(
calibration_snapshot_root=snapshot,
source_id="sensor.camera.right",
output_root=tmp_path / "masks",
)
assert repeated == first
assert first.calibration_slot == "camera_1"
assert (first.width, first.height) == (800, 600)
calibration = parse_k1_factory_calibration(
(CALIBRATION_FIXTURES / "camera.yaml").read_bytes(),
(CALIBRATION_FIXTURES / "extrinsic_camera_lidar.yaml").read_bytes(),
)
camera = calibration.camera("camera_1")
expected_center = (camera.intrinsic[2] * 0.2, camera.intrinsic[3] * 0.2)
expected_radius = min(
expected_center[0],
799 - expected_center[0],
expected_center[1],
599 - expected_center[1],
) - 4.0
assert first.center_xy == pytest.approx(expected_center)
assert first.radius_pixels == pytest.approx(expected_radius)
assert 0.55 < first.valid_fraction < 0.57
mask = np.asarray(Image.open(first.mask_path), dtype=np.uint8)
assert set(np.unique(mask)) == {0, 255}
assert mask[0, 0] == 0
assert mask[round(first.center_xy[1]), round(first.center_xy[0])] == 255
assert validate_k1_valid_fov_mask(first.root) == first
def test_valid_fov_mask_rejects_changed_png(tmp_path: Path) -> None:
result = prepare_k1_valid_fov_mask(
calibration_snapshot_root=_calibration_snapshot(tmp_path),
source_id="sensor.camera.right",
output_root=tmp_path / "masks",
)
result.mask_path.write_bytes(b"changed")
with pytest.raises(K1ValidFovMaskError, match="artifact changed"):
validate_k1_valid_fov_mask(result.root)
def test_qualification_slice_is_uniform_job_bound_and_reusable(tmp_path: Path) -> None:
job_root = _camera_job(tmp_path)
first = prepare_recorded_qualification_slice(
job_root=job_root,
output_root=tmp_path / "slices",
sample_count=4,
)
repeated = prepare_recorded_qualification_slice(
job_root=job_root,
output_root=tmp_path / "slices",
sample_count=4,
)
assert repeated == first
assert first.source_frame_count == 9
assert tuple(frame.frame_index for frame in first.frames) == (0, 3, 5, 8)
assert tuple(frame.sequence for frame in first.frames) == (1, 4, 6, 9)
assert validate_recorded_qualification_slice(first.root, job_root=job_root) == first
def test_qualification_slice_rejects_changed_selection(tmp_path: Path) -> None:
job_root = _camera_job(tmp_path)
result = prepare_recorded_qualification_slice(
job_root=job_root,
output_root=tmp_path / "slices",
sample_count=4,
)
manifest = json.loads(result.manifest_path.read_text(encoding="utf-8"))
manifest["frames"][1]["frame_index"] = 2
result.manifest_path.write_text(json.dumps(manifest), encoding="utf-8")
with pytest.raises(RecordedQualificationSliceError, match="binding changed"):
validate_recorded_qualification_slice(result.root, job_root=job_root)
def _evaluation_fixture(tmp_path: Path) -> tuple[Path, Path, Path, Path, Path, tuple[Any, ...]]:
job_root = _camera_job(tmp_path, frame_count=64)
qualification = prepare_recorded_qualification_slice(
job_root=job_root,
output_root=tmp_path / "slices",
sample_count=16,
)
valid_fov = prepare_k1_valid_fov_mask(
calibration_snapshot_root=_calibration_snapshot(tmp_path),
source_id="sensor.camera.right",
output_root=tmp_path / "masks",
)
anchors = {frame.frame_index for frame in qualification.frames}
temporal = {
1: "clip-a",
2: "clip-a",
3: "clip-a",
60: "clip-b",
61: "clip-b",
62: "clip-b",
}
requests = tuple(
EvaluationFrameRequest(
frame_index=index,
role="anchor" if index in anchors else "temporal",
group_id=f"anchor-{index:06d}" if index in anchors else temporal[index],
)
for index in sorted(anchors | set(temporal))
)
frames_root = tmp_path / "decoded"
frames_root.mkdir()
for request in requests:
image = Image.new(
"RGB",
(800, 600),
(request.frame_index, request.frame_index // 2, 255 - request.frame_index),
)
image.save(frames_root / f"frame-{request.frame_index:06d}.png")
timeline_path = tmp_path / "timeline.jsonl"
timeline_path.write_text(
"".join(
json.dumps({"frame_index": index, "session_seconds": 0.5 + index * 0.5}) + "\n"
for index in range(64)
),
encoding="utf-8",
)
return (
job_root,
qualification.root,
valid_fov.root,
frames_root,
timeline_path,
requests,
)
def test_evaluation_pack_is_bound_reusable_and_separates_annotation_state(
tmp_path: Path,
) -> None:
job_root, qualification_root, valid_fov_root, frames_root, timeline_path, requests = (
_evaluation_fixture(tmp_path)
)
first = prepare_recorded_evaluation_pack(
job_root=job_root,
qualification_root=qualification_root,
valid_fov_root=valid_fov_root,
decoded_frames_root=frames_root,
timeline_path=timeline_path,
output_root=tmp_path / "evaluation-packs",
selection=requests,
decoder_version="fixture-decoder/v1",
selection_document_sha256="1" * 64,
producer_files=(("fixture.py", "2" * 64),),
)
repeated = prepare_recorded_evaluation_pack(
job_root=job_root,
qualification_root=qualification_root,
valid_fov_root=valid_fov_root,
decoded_frames_root=frames_root,
timeline_path=timeline_path,
output_root=tmp_path / "evaluation-packs",
selection=requests,
decoder_version="fixture-decoder/v1",
selection_document_sha256="1" * 64,
producer_files=(("fixture.py", "2" * 64),),
)
assert repeated == first
assert len(first.frames) == 22
assert sum(frame.role == "anchor" for frame in first.frames) == 16
assert sum(frame.role == "temporal" for frame in first.frames) == 6
template = json.loads(first.annotation_template_path.read_text(encoding="utf-8"))
assert template["state"] == "unannotated"
assert {row["annotation_status"] for row in template["reviews"]} == {"unannotated"}
assert (
validate_recorded_evaluation_pack(
first.root,
job_root=job_root,
qualification_root=qualification_root,
valid_fov_root=valid_fov_root,
)
== first
)
def test_evaluation_pack_rejects_changed_image(tmp_path: Path) -> None:
job_root, qualification_root, valid_fov_root, frames_root, timeline_path, requests = (
_evaluation_fixture(tmp_path)
)
result = prepare_recorded_evaluation_pack(
job_root=job_root,
qualification_root=qualification_root,
valid_fov_root=valid_fov_root,
decoded_frames_root=frames_root,
timeline_path=timeline_path,
output_root=tmp_path / "evaluation-packs",
selection=requests,
decoder_version="fixture-decoder/v1",
selection_document_sha256="1" * 64,
producer_files=(("fixture.py", "2" * 64),),
)
result.frames[0].valid_fov_fill_path.write_bytes(b"changed")
with pytest.raises(RecordedEvaluationPackError, match="artifact changed"):
validate_recorded_evaluation_pack(
result.root,
job_root=job_root,
qualification_root=qualification_root,
valid_fov_root=valid_fov_root,
)
+24 -1
View File
@@ -20,6 +20,7 @@ from pydantic import ValidationError
import k1link.web.device_plugin_composition as plugin_composition
from k1link.device_plugins.xgrids_k1.facade import (
ACTION_DEVICE_CALIBRATION_SNAPSHOT_READ,
ACTION_DISCOVERY_SCAN,
ACTION_NETWORK_PROVISION,
ACTION_STREAM_START_LIVE,
@@ -59,6 +60,10 @@ class FakeXgridsService:
self.calls.append(("state", None))
return {"phase": "idle"}
def read_device_calibration_snapshot(self) -> dict[str, Any]:
self.calls.append(("calibration", None))
return {"status": "available", "snapshot_id": "fixture-snapshot"}
async def scan_ble(self, duration_seconds: float) -> dict[str, Any]:
self.calls.append(("scan", duration_seconds))
return {"phase": "idle", "devices": []}
@@ -71,7 +76,7 @@ class FakeXgridsService:
self,
project_name: str,
host: str | None,
duration_seconds: float,
duration_seconds: float | None,
compatibility_attestation: CompatibilityAttestationRequest,
) -> dict[str, Any]:
self.calls.append(
@@ -135,6 +140,24 @@ def test_manifest_and_runtime_facade_declare_identical_actions() -> None:
assert {action.id for action in manifest.spec.actions} == XgridsK1PluginFacade.action_ids
def test_calibration_snapshot_action_calls_the_read_only_service_method() -> None:
service = FakeXgridsService()
dispatcher = DevicePluginDispatcher(
[_in_process_runtime(XgridsK1PluginFacade(service))]
)
result = asyncio.run(
dispatcher.invoke(
XGRIDS_K1_PLUGIN_ID,
ACTION_DEVICE_CALIBRATION_SNAPSHOT_READ,
{},
)
)
assert result == {"status": "available", "snapshot_id": "fixture-snapshot"}
assert service.calls == [("calibration", None)]
def test_repository_runtime_composition_exactly_matches_catalog() -> None:
repository_root = Path(__file__).resolve().parents[1]
environment = load_installed_device_plugins(repository_root)
@@ -0,0 +1,87 @@
from __future__ import annotations
import json
from pathlib import Path
import pytest
from k1link.compute.realtime_tracking_qualification import (
FRAME_SCHEMA,
TELEMETRY_SCHEMA,
_validate_realtime_frames,
_validate_realtime_telemetry,
)
from k1link.sessions import SessionIntegrityError
def _frame(index: int) -> dict[str, object]:
return {
"schema_version": FRAME_SCHEMA,
"frame_index": index,
"sequence": index + 1,
"source_frame_index": 1000 + index,
"source_sequence": 1001 + index,
"session_seconds": 135.0 + index * 0.1,
"detections": [],
"tracks": [],
"delivery": {"health": "healthy", "result_age_ms": 50.0},
}
def _telemetry(index: int) -> dict[str, object]:
return {
"schema_version": TELEMETRY_SCHEMA,
"frame_index": index,
"session_seconds": 135.0 + index * 0.1,
"health": "healthy",
"result_age_ms": 50.0,
"processing_ms": 20.0,
"queue_depth_after_take": 0,
"queue_dropped_overflow": 0,
}
def test_realtime_rows_allow_explicit_latest_wins_gaps(tmp_path: Path) -> None:
indices = (0, 2, 3)
frames = tmp_path / "frames.jsonl"
telemetry = tmp_path / "telemetry.jsonl"
frames.write_text(
"".join(json.dumps(_frame(index)) + "\n" for index in indices),
encoding="utf-8",
)
telemetry.write_text(
"".join(json.dumps(_telemetry(index)) + "\n" for index in indices),
encoding="utf-8",
)
observed = _validate_realtime_frames(
frames,
tmp_path,
expected_count=3,
selection_count=4,
source_start=1000,
timeline_start=135.0,
timeline_end=135.3,
)
_validate_realtime_telemetry(telemetry, tmp_path, expected_indices=observed)
assert observed == indices
def test_realtime_rows_reject_out_of_order_results(tmp_path: Path) -> None:
frames = tmp_path / "frames.jsonl"
frames.write_text(
json.dumps(_frame(1)) + "\n" + json.dumps(_frame(0)) + "\n",
encoding="utf-8",
)
with pytest.raises(SessionIntegrityError, match="frame metadata"):
_validate_realtime_frames(
frames,
tmp_path,
expected_count=2,
selection_count=4,
source_start=1000,
timeline_start=135.0,
timeline_end=135.3,
)
+81
View File
@@ -0,0 +1,81 @@
from __future__ import annotations
import hashlib
import importlib.util
import json
from pathlib import Path
from types import ModuleType
import pytest
def _worker_module() -> ModuleType:
path = (
Path(__file__).parents[1]
/ "experiments"
/ "perception"
/ "worker"
/ "run_recorded_perception_epoch.py"
)
spec = importlib.util.spec_from_file_location("recorded_perception_worker", path)
assert spec is not None and spec.loader is not None
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
return module
def _job(root: Path) -> dict[str, object]:
payload = root / "input" / "payload.bin"
payload.parent.mkdir(parents=True)
payload.write_bytes(b"immutable-camera-input")
input_document = {
"byte_length": payload.stat().st_size,
"files": [
{
"path": "input/payload.bin",
"byte_length": payload.stat().st_size,
"sha256": hashlib.sha256(payload.read_bytes()).hexdigest(),
}
],
}
encoded = json.dumps(
input_document,
ensure_ascii=False,
sort_keys=True,
separators=(",", ":"),
allow_nan=False,
).encode()
input_sha256 = hashlib.sha256(encoded).hexdigest()
document: dict[str, object] = {
"schema_version": "missioncore.compute-job/v1",
"job_id": f"recorded-camera-{input_sha256[:24]}",
"input_sha256": input_sha256,
"input": input_document,
}
(root / "job.json").write_text(json.dumps(document), encoding="utf-8")
return document
def test_worker_validates_job_identity_independently_of_container_mount_name(
tmp_path: Path,
) -> None:
worker = _worker_module()
mounted_root = tmp_path / "job"
mounted_root.mkdir()
expected = _job(mounted_root)
validated = worker._validate_job(mounted_root)
assert validated["job_id"] == expected["job_id"]
assert mounted_root.name != expected["job_id"]
def test_worker_rejects_a_transferred_payload_that_changed(tmp_path: Path) -> None:
worker = _worker_module()
mounted_root = tmp_path / "job"
mounted_root.mkdir()
_job(mounted_root)
(mounted_root / "input" / "payload.bin").write_bytes(b"changed")
with pytest.raises(RuntimeError, match="compute job artifact changed"):
worker._validate_job(mounted_root)
+38
View File
@@ -9,6 +9,7 @@ from pathlib import Path
import numpy as np
import pytest
from k1link.compute.live_perception import LivePerceptionResultFrame
from k1link.data_plane import DecodedDataPlaneView, NormalizationError
from k1link.device_plugins.xgrids_k1.mqtt.capture import FRAME_HEADER, RAW_MAGIC
from k1link.device_plugins.xgrids_k1.protocol.normalizer import normalize_k1_message
@@ -138,6 +139,43 @@ def test_live_blueprint_follows_stream_time_without_frontend_cursor_writes() ->
assert panel.state == "hidden"
def test_live_perception_logs_original_mask_2d_distance_and_3d_cuboid() -> None:
recording = FakeRecording()
bridge = RerunBridge(recording_factory=lambda _: recording) # type: ignore[arg-type]
mask = np.zeros((600, 800), dtype=np.uint8)
mask[20:30, 40:50] = 4
bridge.process_perception(
LivePerceptionResultFrame(
frame_index=3,
source_frame_index=30,
session_seconds=1.0,
captured_at_epoch_ns=1_784_124_315_186_225_000,
image_jpeg=b"\xff\xd8test\xff\xd9",
segmentation_mask=mask,
objects=(
{
"track_id": 9,
"label": "car",
"score": 0.9,
"bbox_xyxy": [10.0, 20.0, 110.0, 80.0],
"distance_m": 6.2,
"cuboid_center_map": [1.0, 2.0, 0.5],
"cuboid_half_size": [2.25, 0.925, 0.775],
"cuboid_quaternion_xyzw": [0.0, 0.0, 0.0, 1.0],
},
),
delivery={"health": "healthy"},
)
)
paths = [path for path, _, _ in recording.logs]
assert "/perception/camera/image" in paths
assert "/perception/camera/segmentation" in paths
assert "/perception/camera/detections" in paths
assert "/world/perception/boxes3d" in paths
def test_constructor_disconnects_recording_after_partial_setup_failure() -> None:
recording = BlueprintFailureRecording()
+174 -2
View File
@@ -19,16 +19,23 @@ from k1link.device_plugins.xgrids_k1.mqtt.capture import (
from k1link.device_plugins.xgrids_k1.rrd_export import (
RECORDED_CAMERA_VIEW_ID,
RECORDED_METRICS_VIEW_ID,
RECORDED_PERCEPTION_3D_VIEW_ID,
RECORDED_POINTS_VISUALIZER_ID,
RECORDED_ROOT_CONTAINER_ID,
RECORDED_SPATIAL_VIEW_ID,
RECORDED_VIEW_POINT_DECIMATION_THRESHOLD,
RECORDED_VIEW_POINT_FRAME_STRIDE,
RECORDED_VIEW_POINT_STRIDE,
SESSION_TIMELINE,
RrdExportCancelled,
RrdExportError,
_recorded_blueprint,
_recorded_view_points,
_should_publish_recorded_point_frame,
export_k1mqtt_to_rrd,
recorded_blueprint_rrd,
)
from k1link.viewer.recorded import recorded_blueprint as viewer_recorded_blueprint
from k1link.viewer.rerun_bridge import RerunSceneSettings
@@ -45,6 +52,57 @@ def _point_payload(x: float) -> bytes:
)
def test_recorded_operator_projection_thins_only_dense_point_batches() -> None:
assert RECORDED_VIEW_POINT_FRAME_STRIDE == 5
count = RECORDED_VIEW_POINT_DECIMATION_THRESHOLD + 3
positions = export_module.np.arange(
count * 3,
dtype=export_module.np.float32,
).reshape((-1, 3))
intensities = export_module.np.arange(count, dtype=export_module.np.uint8)
rgb = export_module.np.arange(count * 3, dtype=export_module.np.uint8).reshape((-1, 3))
projected_positions, projected_intensities, projected_rgb = _recorded_view_points(
positions,
intensities,
rgb,
)
assert projected_rgb is not None
assert export_module.np.array_equal(
projected_positions,
positions[::RECORDED_VIEW_POINT_STRIDE],
)
assert export_module.np.array_equal(
projected_intensities,
intensities[::RECORDED_VIEW_POINT_STRIDE],
)
assert export_module.np.array_equal(projected_rgb, rgb[::RECORDED_VIEW_POINT_STRIDE])
small_positions = positions[:RECORDED_VIEW_POINT_DECIMATION_THRESHOLD]
small_intensities = intensities[:RECORDED_VIEW_POINT_DECIMATION_THRESHOLD]
same_positions, same_intensities, no_rgb = _recorded_view_points(
small_positions,
small_intensities,
None,
)
assert same_positions is small_positions
assert same_intensities is small_intensities
assert no_rgb is None
def test_recorded_operator_projection_uses_stable_two_hz_point_cadence() -> None:
published = [
frame_number
for frame_number in range(1, 13)
if _should_publish_recorded_point_frame(frame_number)
]
assert published == [1, 6, 11]
with pytest.raises(ValueError, match="positive"):
_should_publish_recorded_point_frame(0)
def _pose_payload(x: float) -> bytes:
return struct.pack("<ffffffff", x, 2.0, 3.0, 99.0, 1.0, 0.0, 0.0, 0.0)
@@ -191,8 +249,19 @@ def test_recorded_blueprint_accumulates_point_frames_on_session_timeline() -> No
assert line_grid.visible.as_arrow_array().to_pylist() == [False]
point_behavior, point_visualizer = spatial_view.visualizer_overrides["/world/points"]
trajectory_behavior = spatial_view.visualizer_overrides["/world/trajectory"]
perception_behavior = spatial_view.visualizer_overrides["/world/perception"]
assert point_behavior.visible.as_arrow_array().to_pylist() == [False]
assert trajectory_behavior.visible.as_arrow_array().to_pylist() == [True]
assert perception_behavior.visible.as_arrow_array().to_pylist() == [False]
perception_3d_view = blueprint.root_container.contents[2]
assert perception_3d_view.origin == "/world"
assert "VisibleTimeRanges" not in perception_3d_view.properties
assert perception_3d_view.visualizer_overrides[
"/world/perception"
].visible.as_arrow_array().to_pylist() == [True]
assert perception_3d_view.visualizer_overrides[
"/world/perception/lidar"
].visible.as_arrow_array().to_pylist() == [False]
point_overrides = {
str(batch.component_descriptor()): batch.as_arrow_array().to_pylist()
for batch in point_visualizer.overrides
@@ -235,8 +304,10 @@ def test_dynamic_blueprint_reuses_scene_ids_without_playback_mutation() -> None:
assert first_view.id == second_view.id == RECORDED_SPATIAL_VIEW_ID
assert first.root_container.contents[1].id == RECORDED_CAMERA_VIEW_ID
assert second.root_container.contents[1].id == RECORDED_CAMERA_VIEW_ID
assert first.root_container.contents[2].id == RECORDED_METRICS_VIEW_ID
assert second.root_container.contents[2].id == RECORDED_METRICS_VIEW_ID
assert first.root_container.contents[2].id == RECORDED_PERCEPTION_3D_VIEW_ID
assert second.root_container.contents[2].id == RECORDED_PERCEPTION_3D_VIEW_ID
assert first.root_container.contents[3].id == RECORDED_METRICS_VIEW_ID
assert second.root_container.contents[3].id == RECORDED_METRICS_VIEW_ID
first_point_behavior, first_point_visualizer = first_view.visualizer_overrides["/world/points"]
second_point_behavior, second_point_visualizer = second_view.visualizer_overrides[
@@ -262,6 +333,107 @@ def test_dynamic_blueprint_reuses_scene_ids_without_playback_mutation() -> None:
assert str(RECORDED_POINTS_VISUALIZER_ID).encode() in payload
def test_viewer_blueprint_reset_is_bounded_and_recreates_render_views() -> None:
initial = viewer_recorded_blueprint(
RerunSceneSettings(accumulation_seconds=12.0),
include_initial_playback_state=False,
active_view="perception",
view_reset_generation=0,
)
reset = viewer_recorded_blueprint(
RerunSceneSettings(accumulation_seconds=12.0),
include_initial_playback_state=False,
active_view="perception",
view_reset_generation=1,
)
restored = viewer_recorded_blueprint(
RerunSceneSettings(accumulation_seconds=12.0),
include_initial_playback_state=False,
active_view="perception",
view_reset_generation=0,
)
assert initial.root_container.id == restored.root_container.id
assert reset.root_container.id != initial.root_container.id
assert initial.root_container.contents[0].id != reset.root_container.contents[0].id
assert restored.root_container.contents[0].id == initial.root_container.contents[0].id
assert initial.root_container.active_tab == 1
assert reset.root_container.active_tab == 1
assert initial.root_container.contents[1].id != reset.root_container.contents[1].id
assert initial.root_container.contents[2].id != reset.root_container.contents[2].id
assert restored.root_container.contents[1].id == initial.root_container.contents[1].id
assert restored.root_container.contents[2].id == initial.root_container.contents[2].id
cuboids = viewer_recorded_blueprint(
RerunSceneSettings(accumulation_seconds=12.0),
include_initial_playback_state=False,
active_view="perception3d",
)
assert cuboids.root_container.active_tab == 2
assert cuboids.root_container.id != initial.root_container.id
cuboid_view = cuboids.root_container.contents[2]
assert cuboid_view.origin == "/world"
assert "VisibleTimeRanges" not in cuboid_view.properties
cuboid_points, cuboid_point_visualizer = cuboid_view.visualizer_overrides[
"/world/points"
]
cuboid_perception = cuboid_view.visualizer_overrides["/world/perception"]
cuboid_diagnostic_lidar = cuboid_view.visualizer_overrides[
"/world/perception/lidar"
]
assert cuboid_points.visible.as_arrow_array().to_pylist() == [True]
assert cuboid_point_visualizer.id != initial.root_container.contents[0].visualizer_overrides[
"/world/points"
][1].id
assert cuboid_perception.visible.as_arrow_array().to_pylist() == [True]
assert cuboid_diagnostic_lidar.visible.as_arrow_array().to_pylist() == [False]
perception_behavior = initial.root_container.contents[0].visualizer_overrides[
"/world/perception"
]
assert perception_behavior.visible.as_arrow_array().to_pylist() == [False]
def test_viewer_blueprint_unifies_original_video_and_independent_ai_layers() -> None:
blueprint = viewer_recorded_blueprint(
RerunSceneSettings(accumulation_seconds=12.0),
include_initial_playback_state=False,
unified_perception=True,
show_detections_2d=True,
show_segmentation=True,
show_cuboids_3d=False,
)
assert type(blueprint.root_container).__name__ == "Horizontal"
camera_view, spatial_view = blueprint.root_container.contents
assert camera_view.origin == "/perception/camera"
assert spatial_view.origin == "/world"
assert camera_view.visualizer_overrides[
"/perception/camera/image"
].visible.as_arrow_array().to_pylist() == [True]
assert camera_view.visualizer_overrides[
"/perception/camera/detections"
].visible.as_arrow_array().to_pylist() == [True]
assert camera_view.visualizer_overrides[
"/perception/camera/segmentation"
].visible.as_arrow_array().to_pylist() == [True]
semantic_behavior, semantic_time_ranges = spatial_view.visualizer_overrides[
"/world/perception/semantic_points"
]
cuboid_behavior, cuboid_time_ranges = spatial_view.visualizer_overrides[
"/world/perception/boxes3d"
]
assert semantic_behavior.visible.as_arrow_array().to_pylist() == [True]
assert cuboid_behavior.visible.as_arrow_array().to_pylist() == [False]
assert semantic_time_ranges.ranges.as_arrow_array().to_pylist() == []
assert cuboid_time_ranges.ranges.as_arrow_array().to_pylist() == []
visible_ranges = spatial_view.properties["VisibleTimeRanges"]
assert visible_ranges.ranges.as_arrow_array().to_pylist() == [
{
"timeline": SESSION_TIMELINE,
"range": {"start": -12_000_000_000, "end": 0},
}
]
def test_export_preserves_every_decodable_frame_and_source_timeline(tmp_path: Path) -> None:
capture = _write_capture(
tmp_path,
+233 -17
View File
@@ -12,10 +12,11 @@ from pathlib import Path
from typing import Any
import pytest
from fastapi import APIRouter, HTTPException, Response
from fastapi import APIRouter, HTTPException, Request, Response
from fastapi.routing import APIRoute
import k1link.sessions.media as recorded_media_module
from k1link.compute import RecordedPerceptionVideo
from k1link.device_plugins.xgrids_k1 import xgrids_k1_archive_source
from k1link.device_plugins.xgrids_k1.mqtt.capture import FRAME_HEADER, RAW_MAGIC
from k1link.sessions import (
@@ -166,9 +167,24 @@ async def render_file_response(
*,
range_header: bytes | None,
) -> tuple[dict[str, Any], bytes]:
body_iterator = getattr(response, "body_iterator", None)
if body_iterator is not None:
chunks = [chunk async for chunk in body_iterator]
return {
"status": response.status_code,
"headers": response.raw_headers,
}, b"".join(
chunk.encode("utf-8") if isinstance(chunk, str) else chunk
for chunk in chunks
)
sent: list[dict[str, Any]] = []
request_delivered = False
async def receive() -> dict[str, Any]:
nonlocal request_delivered
if request_delivered:
return {"type": "http.disconnect"}
request_delivered = True
return {"type": "http.request", "body": b"", "more_body": False}
async def send(message: dict[str, Any]) -> None:
@@ -1069,6 +1085,11 @@ def test_recorded_blueprint_endpoint_is_small_strict_and_session_scoped(
palette="custom",
custom_color="#112233",
active_view="perception",
view_reset_generation=1,
unified_perception=True,
show_detections_2d=True,
show_segmentation=True,
show_cuboids_3d=True,
),
)
)
@@ -1083,6 +1104,11 @@ def test_recorded_blueprint_endpoint_is_small_strict_and_session_scoped(
assert observed_settings[0].show_points is False
assert observed_settings[0].show_trajectory is True
assert observed_kwargs[0]["active_view"] == "perception"
assert observed_kwargs[0]["view_reset_generation"] == 1
assert observed_kwargs[0]["unified_perception"] is True
assert observed_kwargs[0]["show_detections_2d"] is True
assert observed_kwargs[0]["show_segmentation"] is True
assert observed_kwargs[0]["show_cuboids_3d"] is True
with pytest.raises(ValueError):
RecordedBlueprintRequest.model_validate(
@@ -1234,6 +1260,12 @@ def test_session_router_exposes_opaque_recorded_media_manifest_and_ranges(
"epochs/{epoch_ordinal}/segments/{segment_sequence}.m4s",
"GET",
)
stream_route = endpoint(
router,
"/api/v1/observation-sessions/{session_id}/media/{artifact_id}/"
"epochs/{epoch_ordinal}/recording.mp4",
"GET",
)
replay = asyncio.run(replay_route(session_id=session.name, request=None))
source = replay["launch"]["media_sources"][0]
@@ -1271,39 +1303,66 @@ def test_session_router_exposes_opaque_recorded_media_manifest_and_ranges(
if_match=f'"sha256:{source["manifest_generation_sha256"]}"',
)
manifest = json.loads(manifest_response.body)
assert manifest["schema_version"] == "missioncore.observation-recorded-media/v2"
assert manifest["schema_version"] == "missioncore.observation-recorded-media/v3"
assert manifest["source_id"] == source["id"]
assert manifest["generation_sha256"] == source["manifest_generation_sha256"]
assert manifest["byte_length"] == source["byte_length"]
assert manifest["timeline_start_seconds"] == source["timeline_start_seconds"]
assert manifest["timeline_end_seconds"] == source["timeline_end_seconds"]
assert manifest_response.headers["etag"] == (f'"sha256:{manifest["generation_sha256"]}"')
init_sha256 = hashlib.sha256(init).hexdigest()
segment_sha256 = hashlib.sha256(segment).hexdigest()
generation = manifest["generation_sha256"]
assert manifest["epochs"] == [
{
"ordinal": 1,
"timeline_start_seconds": 0.0,
"timeline_end_seconds": 0.5,
"media_type": 'video/mp4; codecs="avc1.640028"',
"init_url": manifest["epochs"][0]["init_url"],
"init_byte_length": len(init),
"init_sha256": init_sha256,
"segment_count": 1,
"segment_url_prefix": manifest["epochs"][0]["segment_url_prefix"],
"segments": [
{
"sequence": 1,
"url": manifest["epochs"][0]["segments"][0]["url"],
"byte_length": len(segment),
"sha256": segment_sha256,
}
],
"byte_length": len(init) + len(segment),
"stream_url": (
f"{source['manifest_url'].removesuffix('/manifest')}/epochs/1/recording.mp4"
f"?generation={generation}"
),
}
]
assert "sensor.camera.private-left" not in json.dumps(manifest)
assert_no_local_paths(manifest, repository)
request = Request({"type": "http", "method": "GET", "headers": []})
with pytest.raises(HTTPException) as stale_stream_generation:
stream_route(
request=request,
session_id=session.name,
artifact_id=artifact_id,
epoch_ordinal=1,
generation="0" * 64,
range_header="bytes=0-5",
)
assert stale_stream_generation.value.status_code == 412
stream_response = stream_route(
request=request,
session_id=session.name,
artifact_id=artifact_id,
epoch_ordinal=1,
generation=generation,
range_header=f"bytes={len(init) - 2}-{len(init) + 3}",
)
stream_start, stream_body = asyncio.run(
render_file_response(stream_response, range_header=None)
)
stream_headers = {
key.decode("latin-1"): value.decode("latin-1")
for key, value in stream_start["headers"]
}
assert stream_start["status"] == 206
assert stream_body == init[-2:] + segment[:4]
assert stream_headers["content-range"] == (
f"bytes {len(init) - 2}-{len(init) + 3}/{len(init) + len(segment)}"
)
assert stream_headers["content-length"] == "6"
assert stream_headers["accept-ranges"] == "bytes"
assert stream_headers["etag"] == f'"generation:{generation}:epoch:1"'
with pytest.raises(HTTPException) as missing_init_generation:
init_route(
session_id=session.name,
@@ -1313,6 +1372,9 @@ def test_session_router_exposes_opaque_recorded_media_manifest_and_ranges(
)
assert missing_init_generation.value.status_code == 428
init_sha256 = hashlib.sha256(init).hexdigest()
segment_sha256 = hashlib.sha256(segment).hexdigest()
init_response = init_route(
session_id=session.name,
artifact_id=artifact_id,
@@ -1375,6 +1437,160 @@ def test_session_router_exposes_opaque_recorded_media_manifest_and_ranges(
assert confined.value.status_code == 409
def test_replay_exposes_generation_bound_perception_video_with_native_ranges(
tmp_path: Path,
) -> None:
repository = tmp_path / "repo"
sessions = repository / "sessions"
session = make_legacy_session(sessions, "20260720T065719Z_viewer_live")
store = SessionStore(repository, data_dir=tmp_path / "data")
store.reconcile_archive(xgrids_k1_archive_source(sessions))
recording_payload = b"recording"
def export_recording(source: Path, destination: Path) -> dict[str, object]:
destination.write_bytes(recording_payload)
return {
"source_sha256": hashlib.sha256(source.read_bytes()).hexdigest(),
"rrd_sha256": hashlib.sha256(recording_payload).hexdigest(),
"rrd_bytes": len(recording_payload),
"timeline": "session_time",
"timeline_start_ns": 0,
"timeline_end_ns": 5_000_000_000,
}
video_payload = b"sealed-panoptic-video"
video_path = tmp_path / "perception.mp4"
video_path.write_bytes(video_payload)
video_sha256 = hashlib.sha256(video_payload).hexdigest()
result_id = f"result-{'d' * 64}"
video = RecordedPerceptionVideo(
result_id=result_id,
session_id=session.name,
source_id="sensor.camera.right",
public_source_id="recorded.perception.right",
label="Сегментация · камера right",
path=video_path,
media_type='video/mp4; codecs="avc1.640028"',
byte_length=len(video_payload),
sha256=video_sha256,
timeline_start_seconds=0.5,
timeline_end_seconds=4.5,
)
class Provider:
def __init__(self) -> None:
self.calls: list[tuple[str, str | None]] = []
def video(
self,
session_id: str,
requested_result_id: str | None = None,
) -> RecordedPerceptionVideo | None:
self.calls.append((session_id, requested_result_id))
if session_id != video.session_id:
return None
if requested_result_id is not None and requested_result_id != video.result_id:
return None
return video
provider = Provider()
router = build_session_router(
store,
recording_materializer=SessionRecordingMaterializer(
store.data_dir,
exporter=export_recording,
),
perception_media_provider=provider,
allow_synchronous_recording_fallback=True,
)
replay_route = endpoint(
router,
"/api/v1/observation-sessions/{session_id}/replay",
"POST",
)
manifest_route = endpoint(
router,
"/api/v1/observation-sessions/{session_id}/perception-media/"
"{result_id}/manifest",
"GET",
)
stream_route = endpoint(
router,
"/api/v1/observation-sessions/{session_id}/perception-media/"
"{result_id}/recording.mp4",
"GET",
)
replay = asyncio.run(replay_route(session_id=session.name, request=None))
# Perception is loaded through the on-demand RRD overlay and no longer
# blocks replay launch by hashing a duplicate pre-rendered video.
assert replay["launch"]["media_sources"] == []
assert provider.calls == []
with pytest.raises(HTTPException) as missing_generation:
manifest_route(session_id=session.name, result_id=result_id)
assert missing_generation.value.status_code == 428
manifest_response = manifest_route(
session_id=session.name,
result_id=result_id,
if_match=f'"sha256:{video_sha256}"',
)
assert provider.calls == [
(session.name, result_id),
(session.name, result_id),
]
manifest = json.loads(manifest_response.body)
assert manifest == {
"schema_version": "missioncore.observation-recorded-media/v3",
"source_id": "recorded.perception.right",
"generation_sha256": video_sha256,
"byte_length": len(video_payload),
"timeline_start_seconds": 0.5,
"timeline_end_seconds": 4.5,
"synchronization": "host-arrival-best-effort",
"epochs": [
{
"ordinal": 1,
"timeline_start_seconds": 0.5,
"timeline_end_seconds": 4.5,
"media_type": 'video/mp4; codecs="avc1.640028"',
"byte_length": len(video_payload),
"stream_url": (
f"/api/v1/observation-sessions/{session.name}/perception-media/"
f"{result_id}/recording.mp4?generation={video_sha256}"
),
}
],
}
request = Request({"type": "http", "method": "GET", "headers": []})
with pytest.raises(HTTPException) as stale_generation:
stream_route(
request=request,
session_id=session.name,
result_id=result_id,
generation="0" * 64,
range_header=None,
)
assert stale_generation.value.status_code == 412
response = stream_route(
request=request,
session_id=session.name,
result_id=result_id,
generation=video_sha256,
range_header="bytes=7-14",
)
start, body = asyncio.run(render_file_response(response, range_header=b"bytes=7-14"))
headers = {
key.decode("latin-1"): value.decode("latin-1") for key, value in start["headers"]
}
assert start["status"] == 206
assert body == video_payload[7:15]
assert headers["content-range"] == f"bytes 7-14/{len(video_payload)}"
assert headers["accept-ranges"] == "bytes"
assert headers["etag"] == f'"sha256:{video_sha256}"'
def test_ready_launch_uses_background_prepared_camera_manifest_without_rescan(
tmp_path: Path,
monkeypatch: pytest.MonkeyPatch,
+21 -5
View File
@@ -16,6 +16,8 @@ import k1link.sessions.recording as recording_module
from k1link.sessions.models import ReplayArtifact, ReplayCommand
from k1link.sessions.recording import (
CACHE_SCHEMA,
RECORDING_CACHE_FILENAME,
RECORDING_CACHE_SIDECAR_FILENAME,
RERUN_RECORDING_MEDIA_TYPE,
RecordingMaterializationError,
SessionRecordingMaterializer,
@@ -113,7 +115,7 @@ def test_materializer_reuses_only_a_digest_validated_private_cache(tmp_path: Pat
assert first.timeline_end_ns == 2_500_000_000
assert first.path.is_relative_to(materializer.recordings_root)
assert first.path.stat().st_mode & 0o777 == 0o600
sidecar = first.path.with_name("scene.rrd.cache.json")
sidecar = first.path.with_name(RECORDING_CACHE_SIDECAR_FILENAME)
assert sidecar.stat().st_mode & 0o777 == 0o600
document = json.loads(sidecar.read_text(encoding="utf-8"))
assert document["schema_version"] == CACHE_SCHEMA
@@ -129,6 +131,20 @@ def test_materializer_reuses_only_a_digest_validated_private_cache(tmp_path: Pat
assert exporter.calls == 1
def test_default_recording_cache_has_no_application_byte_quota(
tmp_path: Path,
monkeypatch: pytest.MonkeyPatch,
) -> None:
monkeypatch.delenv("MISSIONCORE_RRD_CACHE_MAX_BYTES", raising=False)
materializer = SessionRecordingMaterializer(
tmp_path / "private",
exporter=FakeExporter(),
)
assert materializer.cache_max_bytes is None
def test_delete_cached_refuses_a_live_lease_then_removes_the_exact_cache(
tmp_path: Path,
) -> None:
@@ -199,7 +215,7 @@ def test_materializer_rebuilds_incompatible_recording_cache_schema(
exporter = FakeExporter()
private_root = tmp_path / "private"
first = SessionRecordingMaterializer(private_root, exporter=exporter).materialize(command)
sidecar = first.path.with_name("scene.rrd.cache.json")
sidecar = first.path.with_name(RECORDING_CACHE_SIDECAR_FILENAME)
document = json.loads(sidecar.read_text(encoding="utf-8"))
document["schema_version"] = obsolete_schema
sidecar.write_text(json.dumps(document), encoding="utf-8")
@@ -217,7 +233,7 @@ def test_failed_rebuild_preserves_previously_published_cache(tmp_path: Path) ->
materializer = SessionRecordingMaterializer(tmp_path / "private", exporter=exporter)
first = materializer.materialize(command)
published_bytes = first.path.read_bytes()
sidecar = first.path.with_name("scene.rrd.cache.json")
sidecar = first.path.with_name(RECORDING_CACHE_SIDECAR_FILENAME)
published_sidecar = sidecar.read_bytes()
command.primary_artifact.path.write_bytes(b"new-source-that-requires-rebuild")
changed = _replace_primary(
@@ -300,9 +316,9 @@ def test_materializer_never_follows_cache_symlinks_outside_private_root(
assert list(outside.iterdir()) == []
session_cache.unlink()
session_cache.mkdir()
outside_recording = outside / "scene.rrd"
outside_recording = outside / RECORDING_CACHE_FILENAME
outside_recording.write_bytes(b"do-not-touch")
(session_cache / "scene.rrd").symlink_to(outside_recording)
(session_cache / RECORDING_CACHE_FILENAME).symlink_to(outside_recording)
recording = materializer.materialize(command)
+54
View File
@@ -566,6 +566,60 @@ def test_interrupted_capture_is_recovered_from_aligned_raw_and_metadata_prefix(
assert store.prepare_replay(session.name).primary_artifact.path.name == "mqtt.raw.k1mqtt"
def test_interrupted_capture_streams_metadata_beyond_legacy_total_limit(
tmp_path: Path,
) -> None:
repository = tmp_path / "repo"
sessions = repository / "sessions"
session = make_legacy_session(sessions, "20260716T205632Z_viewer_live")
capture = session / "captures" / "mqtt_live"
raw = bytearray(RAW_MAGIC)
records: list[bytes] = []
topic = "lixel/application/report/lio_pose"
topic_bytes = topic.encode()
padding = "x" * (60 * 1024)
for sequence in range(1, 1_101):
payload = b"p"
frame_offset = len(raw)
raw.extend(FRAME_HEADER.pack(len(topic_bytes), len(payload)))
raw.extend(topic_bytes)
raw.extend(payload)
record = {
"schema_version": 1,
"record_type": "message",
"sequence": sequence,
"received_at_utc": "2026-07-16T20:56:32.699Z",
"received_at_epoch_ns": 1_784_235_391_699_000_000 + sequence,
"received_monotonic_ns": 9_000_000_000 + sequence,
"topic": topic,
"payload_bytes": len(payload),
"raw_frame_offset": frame_offset,
"raw_payload_offset": frame_offset + FRAME_HEADER.size + len(topic_bytes),
"raw_frame_bytes": FRAME_HEADER.size + len(topic_bytes) + len(payload),
"padding": padding,
}
records.append((json.dumps(record, separators=(",", ":")) + "\n").encode())
(capture / "mqtt.raw.k1mqtt").write_bytes(raw)
metadata_path = capture / "mqtt.metadata.jsonl"
metadata_path.write_bytes(b"".join(records))
assert metadata_path.stat().st_size > 64 * 1024 * 1024
(capture / "mqtt.summary.json").write_text("{corrupt", encoding="utf-8")
store = SessionStore(repository, data_dir=tmp_path / "data")
store.reconcile_archive(xgrids_k1_archive_source(sessions))
detail = store.get_session(session.name)
assert detail.summary.status == "interrupted"
assert detail.summary.replayable is True
command = store.prepare_replay(session.name)
assert command.primary_artifact.replay_byte_length == len(raw)
assert next(
artifact.replay_byte_length
for artifact in command.artifacts
if artifact.artifact_id == "raw-transport-index"
) == metadata_path.stat().st_size
def test_catalog_upsert_promotes_recovered_session_after_summary_is_completed(
tmp_path: Path,
) -> None:
+3
View File
@@ -72,4 +72,7 @@ def test_viewer_settings_are_validated_and_exposed(tmp_path: Path) -> None:
"show_points": True,
"show_trajectory": False,
"show_grid": False,
"show_detections_2d": False,
"show_segmentation": False,
"show_cuboids_3d": False,
}
+58
View File
@@ -1,9 +1,15 @@
import asyncio
from types import SimpleNamespace
from typing import Any
import pytest
import k1link.device_plugins.xgrids_k1.ble.wifi_provisioning as wifi_module
from k1link.device_plugins.xgrids_k1.ble.wifi_provisioning import (
FRAME_LENGTH,
build_wifi_provisioning_frame,
parse_wifi_status,
read_wifi_status_once,
)
@@ -70,3 +76,55 @@ def test_parse_wifi_status_ap_baseline() -> None:
def test_parse_wifi_status_rejects_short_frame() -> None:
with pytest.raises(ValueError, match="at least 51 bytes"):
parse_wifi_status(bytes(50))
def test_read_wifi_status_once_reads_only_and_returns_current_dhcp_address(
monkeypatch: pytest.MonkeyPatch,
) -> None:
value = bytearray(54)
value[0] = 11
value[1:12] = b"WIFI_CLIENT"
value[33] = 4
value[34:38] = bytes((10, 255, 254, 77))
value[50] = 1
characteristic = SimpleNamespace(
uuid=wifi_module.STATUS_CHARACTERISTIC_UUID,
service_uuid=wifi_module.SERVICE_UUID,
properties=["read"],
)
service = SimpleNamespace(uuid=wifi_module.SERVICE_UUID)
class FakeServices:
def get_service(self, uuid: str) -> object | None:
return service if uuid == wifi_module.SERVICE_UUID else None
def get_characteristic(self, uuid: str) -> object | None:
return characteristic if uuid == wifi_module.STATUS_CHARACTERISTIC_UUID else None
class FakeClient:
def __init__(self, _device: object, **_kwargs: object) -> None:
self.services = FakeServices()
self.name = "XGR-K1"
self.write_calls = 0
async def __aenter__(self) -> Any:
return self
async def __aexit__(self, *_args: object) -> None:
return None
async def read_gatt_char(self, _characteristic: object) -> bytes:
return bytes(value)
async def write_gatt_char(self, *_args: object, **_kwargs: object) -> None:
self.write_calls += 1
raise AssertionError("status refresh must not write a BLE characteristic")
monkeypatch.setattr(wifi_module, "discovered_device", lambda _uuid: object())
monkeypatch.setattr(wifi_module, "BleakClient", FakeClient)
result = asyncio.run(read_wifi_status_once("synthetic-corebluetooth-uuid"))
assert result["operation"] == "single_reviewed_wifi_status_read"
assert result["write_performed"] is False
assert result["status"]["ipv4"] == "10.255.254.77"
+394 -29
View File
@@ -1,7 +1,10 @@
from __future__ import annotations
import asyncio
import json
import threading
from collections.abc import AsyncIterator
from contextlib import asynccontextmanager
from pathlib import Path
from typing import Any
@@ -64,7 +67,7 @@ class FakeVisualizationRuntime:
self.source_mode = "idle"
self.source_ready = False
self.pcl_frames = 0
self.start_calls: list[tuple[str, Path, float, str]] = []
self.start_calls: list[tuple[str, Path, float | None, str]] = []
self.stop_calls = 0
self.stop_error: Exception | None = None
@@ -102,7 +105,7 @@ class FakeVisualizationRuntime:
host: str,
out_dir: Path,
*,
duration_seconds: float,
duration_seconds: float | None,
project_name: str,
) -> None:
self.start_calls.append((host, out_dir, duration_seconds, project_name))
@@ -195,6 +198,132 @@ def service_with_fake_runtime(
return service, runtime
def _wifi_status_read(ipv4: str) -> dict[str, Any]:
return {
"schema_version": 1,
"profile_id": "xgrids-k1-fw3-wifi-v1",
"observed_at_utc": "2026-07-20T12:00:00Z",
"adapter": "CoreBluetooth",
"bleak_version": "test",
"device_macos_uuid": "test-ble-transport",
"device_name": "XGR-K1",
"service_uuid": "00007f00-0000-1000-8000-00805f9b34fb",
"status_characteristic_uuid": "00007f02-0000-1000-8000-00805f9b34fb",
"operation": "single_reviewed_wifi_status_read",
"write_performed": False,
"status": {
"value_length": 54,
"mode": "WIFI_CLIENT",
"ipv4": ipv4,
"status_code": 1,
"reserved": 0,
"trailer_hex": "",
},
}
def test_verify_connection_refreshes_dynamic_dhcp_address_and_rotates_session(
monkeypatch: pytest.MonkeyPatch,
tmp_path: Path,
) -> None:
service, _ = service_with_fake_runtime(tmp_path)
service._selected_device_id = "test-ble-transport" # noqa: SLF001
service._connection_mode = "bridge" # noqa: SLF001
service._k1_ip = "10.255.254.54" # noqa: SLF001
service._device_id = "known-k1" # noqa: SLF001
service._device_session_id = "old-device-session" # noqa: SLF001
service._device_session_opened_at = "2026-07-20T10:00:00Z" # noqa: SLF001
service._device_calibration = {"status": "available"} # noqa: SLF001
async def fake_status_read(*_: object, **__: object) -> dict[str, Any]:
return _wifi_status_read("10.255.254.77")
monkeypatch.setattr(facade_module, "read_wifi_status_once", fake_status_read)
monkeypatch.setattr(facade_module, "_target_is_local_ipv4", lambda _target: False)
state = service.verify_connection()
assert state["k1_ip"] == "10.255.254.77"
assert state["device_session"]["device_session_id"] != "old-device-session"
assert state["connection_verification"] == {
"status": "live-address-observed",
"endpoint_validation": "ble-wifi-status-read",
"network_reachability": "not-probed",
"address_changed": True,
"previous_address_present": True,
"write_performed": False,
"observed_at": "2026-07-20T12:00:00Z",
}
assert state["device_calibration"]["status"] == "unavailable"
def test_implicit_acquisition_target_uses_current_ble_dhcp_address(
monkeypatch: pytest.MonkeyPatch,
tmp_path: Path,
) -> None:
service, _ = service_with_fake_runtime(tmp_path)
service._selected_device_id = "test-ble-transport" # noqa: SLF001
service._connection_mode = "bridge" # noqa: SLF001
service._k1_ip = "10.255.254.54" # noqa: SLF001
async def fake_status_read(*_: object, **__: object) -> dict[str, Any]:
return _wifi_status_read("10.255.254.77")
monkeypatch.setattr(facade_module, "read_wifi_status_once", fake_status_read)
monkeypatch.setattr(facade_module, "_target_is_local_ipv4", lambda _target: False)
state = service.prepare_acquisition(
PrepareAcquisitionRequest(
project_name=PROJECT_NAME,
compatibility_attestation=ATTESTATION,
)
)
assert state["k1_ip"] == "10.255.254.77"
assert state["acquisition"]["target_host"] == "10.255.254.77"
def test_control_session_opens_against_current_ble_dhcp_address(
monkeypatch: pytest.MonkeyPatch,
tmp_path: Path,
) -> None:
service, _ = service_with_fake_runtime(tmp_path)
service._selected_device_id = "test-ble-transport" # noqa: SLF001
service._connection_mode = "bridge" # noqa: SLF001
service._k1_ip = "10.255.254.54" # noqa: SLF001
service._compatibility_attestation = {"profile": "exact"} # noqa: SLF001
opened_hosts: list[str] = []
class FakeOpenControlSession:
def snapshot(self) -> dict[str, object]:
return {"state": "idle", "can_confirm_standby": False}
def open(self, *, host: str, **_: object) -> dict[str, object]:
opened_hosts.append(host)
return self.snapshot()
async def fake_status_read(*_: object, **__: object) -> dict[str, Any]:
return _wifi_status_read("10.255.254.77")
service._application_control_session = FakeOpenControlSession() # type: ignore[assignment] # noqa: SLF001
monkeypatch.setattr(facade_module, "read_wifi_status_once", fake_status_read)
monkeypatch.setattr(facade_module, "_target_is_local_ipv4", lambda _target: False)
state = service.open_application_control_session(
OpenApplicationControlSessionRequest(
operator_present=True,
owner_controlled_device=True,
lixelgo_closed=True,
battery_storage_confirmed=True,
expected_physical_state_confirmed=True,
timezone_name="Europe/Moscow",
)
)
assert opened_hosts == ["10.255.254.77"]
assert state["k1_ip"] == "10.255.254.77"
def test_prepare_creates_provisional_device_session_and_profiled_acquisition(
tmp_path: Path,
) -> None:
@@ -237,11 +366,26 @@ def test_project_name_is_normalized_and_control_characters_are_rejected() -> Non
)
def test_acquisition_is_unbounded_by_default_and_accepts_ten_hour_hint() -> None:
unbounded = PrepareAcquisitionRequest(
project_name=PROJECT_NAME,
host="192.168.1.20",
compatibility_attestation=ATTESTATION,
)
ten_hours = PrepareAcquisitionRequest(
project_name=PROJECT_NAME,
host="192.168.1.20",
duration_seconds=10 * 60 * 60,
compatibility_attestation=ATTESTATION,
)
assert unbounded.duration_seconds is None
assert ten_hours.duration_seconds == 36_000
def test_connection_modes_require_their_exact_topology_attestation() -> None:
assert ConnectRequest(
device_id="synthetic-device",
ssid="synthetic-network",
password=SecretStr(PRIMARY_TEST_CREDENTIAL),
connection_mode="quick-connect",
compatibility_attestation=QUICK_CONNECT_ATTESTATION,
).connection_mode == "quick-connect"
@@ -253,12 +397,18 @@ def test_connection_modes_require_their_exact_topology_attestation() -> None:
compatibility_attestation=DIRECT_CONNECT_ATTESTATION,
).connection_mode == "direct-connect"
with pytest.raises(ValidationError):
ConnectRequest(
device_id="synthetic-device",
connection_mode="quick-connect",
compatibility_attestation=ATTESTATION,
)
with pytest.raises(ValidationError, match="host Wi-Fi profile"):
ConnectRequest(
device_id="synthetic-device",
ssid="synthetic-network",
password=SecretStr(PRIMARY_TEST_CREDENTIAL),
connection_mode="quick-connect",
compatibility_attestation=ATTESTATION,
compatibility_attestation=QUICK_CONNECT_ATTESTATION,
)
with pytest.raises(ValidationError, match="32 UTF-8 bytes"):
ConnectRequest(
@@ -790,10 +940,10 @@ def test_camera_arm_failure_seals_stopped_session_before_releasing_lease(
_host: str,
out_dir: Path,
*,
duration_seconds: float,
duration_seconds: float | None,
project_name: str,
) -> None:
assert duration_seconds > 0
assert duration_seconds is None
assert project_name == PROJECT_NAME
events.append("start")
out_dir.mkdir(parents=True)
@@ -1855,50 +2005,97 @@ def test_network_provisioning_is_single_flight_and_secret_is_unwrapped_only_at_b
assert {item["status"] for item in provision_operations} == {"succeeded", "failed"}
def test_quick_connect_associates_the_host_without_a_ble_write(
def test_quick_connect_activates_the_device_ap_then_associates_the_host(
monkeypatch: pytest.MonkeyPatch,
tmp_path: Path,
) -> None:
service, _ = service_with_fake_runtime(tmp_path)
service._devices = [{"device_id": "k1-a"}] # noqa: SLF001
service._devices = [{"device_id": "k1-a", "name": "XGR-TEST-A"}] # noqa: SLF001
activation_calls: list[str] = []
association_calls: list[tuple[Path, str, str]] = []
ble_session_open = False
monkeypatch.setattr(
facade_module,
"ensure_wifi_profile_from_credential_source",
lambda *_args, **_kwargs: {
"schema_version": 1,
"adapter": "macOS Keychain",
"available": True,
"profile_enrolled": True,
"credential_source": "exact-firmware-profile",
},
)
@asynccontextmanager
async def fake_activation_session(
device_id: str, **_: object
) -> AsyncIterator[dict[str, Any]]:
nonlocal ble_session_open
activation_calls.append(device_id)
ble_session_open = True
try:
yield {
"profile_id": "xgrids-k1-fw3-quick-connect-ap-v1",
"started_at_utc": "2026-07-19T15:00:00Z",
"completed_at_utc": "2026-07-19T15:00:01Z",
"outcome": "ap_ready_observed",
"ready_observed": True,
"write_performed": True,
"write_mode": "with_response",
}
finally:
ble_session_open = False
def fake_associate(
helper_path: Path,
ssid: str,
password: str,
profile_id: str,
expected_ssid: str,
**_: object,
) -> dict[str, Any]:
association_calls.append((helper_path, ssid, password))
assert ble_session_open
association_calls.append((helper_path, profile_id, expected_ssid))
return {
"schema_version": 1,
"adapter": "CoreWLAN",
"outcome": "associated",
"already_associated": False,
"profile_enrolled": True,
"scan_attempt_count": 2,
"scan_elapsed_ms": 900,
"credential_source": "system-wifi-keychain",
}
async def forbidden_ble_write(*_: object, **__: object) -> dict[str, Any]:
raise AssertionError("Quick Connect must not provision the K1 over BLE")
async def forbidden_provisioning_write(*_: object, **__: object) -> dict[str, Any]:
raise AssertionError("Quick Connect must not send router credentials to the K1")
monkeypatch.setattr(facade_module, "associate_with_wifi_once", fake_associate)
monkeypatch.setattr(facade_module, "provision_wifi_once", forbidden_ble_write)
monkeypatch.setattr(
facade_module,
"device_ap_activation_session",
fake_activation_session,
)
monkeypatch.setattr(facade_module, "associate_with_wifi_profile_once", fake_associate)
monkeypatch.setattr(facade_module, "provision_wifi_once", forbidden_provisioning_write)
monkeypatch.setattr(facade_module, "_target_is_local_ipv4", lambda _target: False)
state = asyncio.run(
service.connect(
ConnectRequest(
device_id="k1-a",
ssid="XGR-TEST",
password=SecretStr(PRIMARY_TEST_CREDENTIAL),
connection_mode="quick-connect",
compatibility_attestation=QUICK_CONNECT_ATTESTATION,
)
)
)
assert activation_calls == ["k1-a"]
assert not ble_session_open
assert len(association_calls) == 1
assert association_calls[0][0].name == "associate_wifi.swift"
assert association_calls[0][1:] == ("XGR-TEST", PRIMARY_TEST_CREDENTIAL)
assert association_calls[0][1] == facade_module.quick_connect_host_profile_id(
"XGR-TEST-A"
)
assert association_calls[0][2] == "XGR-TEST-A"
assert state["connection_mode"] == "quick-connect"
assert state["k1_ip"] == "192.168.56.1"
assert state["compatibility"]["attestation"]["topology"] == "device-ap"
@@ -1909,7 +2106,12 @@ def test_quick_connect_associates_the_host_without_a_ble_write(
encoding="utf-8"
)
assert PRIMARY_TEST_CREDENTIAL not in redacted_manifest
assert "XGR-TEST" not in redacted_manifest
assert "host_wifi_profile_id" in redacted_manifest
assert '"host_wifi_profile_ready_before_device_write": true' in redacted_manifest
assert '"credentials_resolved_by_plugin": true' in redacted_manifest
assert "credential_provider_id" in redacted_manifest
assert "device_ap_activation_profile_id" in redacted_manifest
assert (quick_sessions[0] / "ap-activation.redacted.json").exists()
assert service._camera_target_for_session( # noqa: SLF001
state["device_session"]["device_session_id"]
) == "192.168.56.1"
@@ -1928,7 +2130,7 @@ def test_direct_connect_reuses_the_reviewed_ble_provisioning_frame(
tmp_path: Path,
) -> None:
service, _ = service_with_fake_runtime(tmp_path)
service._devices = [{"device_id": "k1-a"}] # noqa: SLF001
service._devices = [{"device_id": "k1-a", "name": "XGR-TEST-A"}] # noqa: SLF001
provisioning_calls: list[tuple[str, str, str]] = []
async def fake_provision(
@@ -1952,7 +2154,7 @@ def test_direct_connect_reuses_the_reviewed_ble_provisioning_frame(
monkeypatch.setattr(facade_module, "provision_wifi_once", fake_provision)
monkeypatch.setattr(
facade_module,
"associate_with_wifi_once",
"associate_with_wifi_profile_once",
forbidden_host_association,
)
monkeypatch.setattr(facade_module, "_target_is_local_ipv4", lambda _target: False)
@@ -1979,28 +2181,182 @@ def test_direct_connect_reuses_the_reviewed_ble_provisioning_frame(
)
def test_quick_connect_missing_credential_provider_stops_before_ap_write(
monkeypatch: pytest.MonkeyPatch,
tmp_path: Path,
) -> None:
service, _ = service_with_fake_runtime(tmp_path)
service._devices = [{"device_id": "k1-a", "name": "XGR-TEST-A"}] # noqa: SLF001
service._selected_device_id = "previous-k1" # noqa: SLF001
service._k1_ip = "192.168.1.20" # noqa: SLF001
service._connection_mode = "bridge" # noqa: SLF001
monkeypatch.setattr(
facade_module,
"ensure_wifi_profile_from_credential_source",
lambda *_args, **_kwargs: {
"schema_version": 1,
"adapter": "macOS Keychain",
"available": False,
"profile_enrolled": False,
"credential_source": None,
},
)
@asynccontextmanager
async def forbidden_activation(
*_args: object, **_kwargs: object
) -> AsyncIterator[dict[str, Any]]:
raise AssertionError("missing host credential must stop before the K1 AP write")
yield {}
monkeypatch.setattr(
facade_module,
"device_ap_activation_session",
forbidden_activation,
)
with pytest.raises(RuntimeError, match="credential-source-unavailable"):
asyncio.run(
service.connect(
ConnectRequest(
device_id="k1-a",
connection_mode="quick-connect",
compatibility_attestation=QUICK_CONNECT_ATTESTATION,
)
)
)
state = service.state()
assert state["selected_device_id"] == "previous-k1"
assert state["k1_ip"] == "192.168.1.20"
assert state["connection_mode"] == "bridge"
assert not list(service.evidence_root.glob("*viewer_k1_ap_association*"))
operation = next(
item for item in state["operations"] if item["action"] == "network.provision"
)
assert operation["status"] == "failed"
assert operation["error"]["side_effect_status"] == "none"
assert operation["error"]["safe_to_retry"] is True
def test_quick_connect_does_not_start_host_wifi_without_ap_ready_flag(
monkeypatch: pytest.MonkeyPatch,
tmp_path: Path,
) -> None:
service, _ = service_with_fake_runtime(tmp_path)
service._devices = [{"device_id": "k1-a", "name": "XGR-TEST-A"}] # noqa: SLF001
monkeypatch.setattr(
facade_module,
"ensure_wifi_profile_from_credential_source",
lambda *_args, **_kwargs: {
"schema_version": 1,
"adapter": "macOS Keychain",
"available": True,
"profile_enrolled": False,
"credential_source": "exact-firmware-profile",
},
)
@asynccontextmanager
async def not_ready_session(
*_: object, **__: object
) -> AsyncIterator[dict[str, Any]]:
yield {
"profile_id": "xgrids-k1-fw3-quick-connect-ap-v1",
"started_at_utc": "2026-07-19T15:00:00Z",
"completed_at_utc": "2026-07-19T15:00:15Z",
"outcome": "no_status_change_before_timeout",
"ready_observed": False,
"write_performed": True,
"write_mode": "with_response",
}
def forbidden_association(*_: object, **__: object) -> dict[str, Any]:
raise AssertionError("host Wi-Fi must wait for the canonical AP-ready flag")
monkeypatch.setattr(
facade_module,
"device_ap_activation_session",
not_ready_session,
)
monkeypatch.setattr(
facade_module,
"associate_with_wifi_profile_once",
forbidden_association,
)
with pytest.raises(RuntimeError, match="не подтвердил готовность"):
asyncio.run(
service.connect(
ConnectRequest(
device_id="k1-a",
connection_mode="quick-connect",
compatibility_attestation=QUICK_CONNECT_ATTESTATION,
)
)
)
quick_sessions = sorted(service.evidence_root.glob("*viewer_k1_ap_association*"))
assert len(quick_sessions) == 1
assert (quick_sessions[0] / "ap-activation.redacted.json").exists()
assert not (quick_sessions[0] / "manifest.redacted.json").exists()
def test_failed_connection_change_revokes_the_previous_route(
monkeypatch: pytest.MonkeyPatch,
tmp_path: Path,
) -> None:
service, _ = service_with_fake_runtime(tmp_path)
service._devices = [{"device_id": "k1-a"}] # noqa: SLF001
service._devices = [{"device_id": "k1-a", "name": "XGR-TEST-A"}] # noqa: SLF001
service._selected_device_id = "previous-k1" # noqa: SLF001
service._k1_ip = "192.168.1.20" # noqa: SLF001
service._connection_mode = "bridge" # noqa: SLF001
monkeypatch.setattr(
facade_module,
"ensure_wifi_profile_from_credential_source",
lambda *_args, **_kwargs: {
"schema_version": 1,
"adapter": "macOS Keychain",
"available": True,
"profile_enrolled": False,
"credential_source": "exact-firmware-profile",
},
)
@asynccontextmanager
async def fake_activation_session(
*_: object, **__: object
) -> AsyncIterator[dict[str, Any]]:
yield {
"profile_id": "xgrids-k1-fw3-quick-connect-ap-v1",
"started_at_utc": "2026-07-19T15:00:00Z",
"completed_at_utc": "2026-07-19T15:00:01Z",
"outcome": "ap_ready_observed",
"ready_observed": True,
"write_performed": True,
"write_mode": "with_response",
}
def failed_association(*_: object, **__: object) -> dict[str, Any]:
raise RuntimeError("offline association fixture failed")
raise facade_module.HostWifiProfileError(
"network-not-found",
scan_attempt_count=4,
scan_elapsed_ms=15014,
)
monkeypatch.setattr(facade_module, "associate_with_wifi_once", failed_association)
monkeypatch.setattr(
facade_module,
"device_ap_activation_session",
fake_activation_session,
)
monkeypatch.setattr(facade_module, "associate_with_wifi_profile_once", failed_association)
with pytest.raises(RuntimeError, match="offline association fixture failed"):
with pytest.raises(RuntimeError, match="network-not-found"):
asyncio.run(
service.connect(
ConnectRequest(
device_id="k1-a",
ssid="XGR-OFFLINE",
password=SecretStr(PRIMARY_TEST_CREDENTIAL),
connection_mode="quick-connect",
compatibility_attestation=QUICK_CONNECT_ATTESTATION,
)
@@ -2012,6 +2368,15 @@ def test_failed_connection_change_revokes_the_previous_route(
assert state["k1_ip"] is None
assert state["connection_mode"] is None
assert state["compatibility"]["attestation"] is None
quick_sessions = sorted(service.evidence_root.glob("*viewer_k1_ap_association*"))
failure_evidence = json.loads(
(quick_sessions[0] / "host-wifi-association.redacted.json").read_text(
encoding="utf-8"
)
)
assert failure_evidence["reason_code"] == "network-not-found"
assert failure_evidence["scan_attempt_count"] == 4
assert failure_evidence["scan_elapsed_ms"] == 15014
def test_network_provisioning_rejects_an_ipv4_owned_by_the_local_host(
@@ -2027,7 +2392,7 @@ def test_network_provisioning_rejects_an_ipv4_owned_by_the_local_host(
"completed_at_utc": "2026-07-18T15:19:26Z",
"profile_id": "xgrids-k1-fw3-wifi-v1",
"outcome": "lan_address_observed",
"observations": [{"status": {"ipv4": "192.168.68.51"}}],
"observations": [{"status": {"ipv4": "10.255.254.51"}}],
}
monkeypatch.setattr(facade_module, "provision_wifi_once", fake_provision)
+35
View File
@@ -0,0 +1,35 @@
from k1link.device_plugins.xgrids_k1.ble.ap_activation import (
COMMAND_OFFSET,
ENABLE_AP_COMMAND,
FRAME_LENGTH,
build_ap_activation_frame,
is_ap_ready_status,
)
from k1link.device_plugins.xgrids_k1.ble.wifi_provisioning import WifiStatus
def test_build_ap_activation_frame_matches_reviewed_lixelgo_layout() -> None:
frame = build_ap_activation_frame()
assert len(frame) == FRAME_LENGTH == 100
assert frame[COMMAND_OFFSET] == ENABLE_AP_COMMAND == 1
assert frame[:COMMAND_OFFSET] == bytes(COMMAND_OFFSET)
def _status(*, reserved: int) -> WifiStatus:
return {
"value_length": 52,
"mode": "WIFI_AP",
"ipv4": "192.168.56.1",
"status_code": 1,
"reserved": reserved,
"trailer_hex": "",
}
def test_ap_control_mode_without_ready_flag_is_not_ready() -> None:
assert not is_ap_ready_status(_status(reserved=0))
def test_ap_ready_requires_the_reviewed_byte_51_flag() -> None:
assert is_ap_ready_status(_status(reserved=1))
+109
View File
@@ -0,0 +1,109 @@
from __future__ import annotations
import math
from pathlib import Path
import numpy as np
import pytest
from k1link.device_plugins.xgrids_k1.analyze.calibrated_projection import (
CalibratedProjectionError,
Kb4ProjectionProfile,
depth_colors,
map_points_to_lidar,
project_map_points_kb4,
quaternion_xyzw_to_rotation_matrix,
)
from k1link.device_plugins.xgrids_k1.calibration_schema import (
parse_k1_factory_calibration,
)
FIXTURES = Path(__file__).parent / "fixtures" / "k1" / "calibration"
def _identity_profile() -> Kb4ProjectionProfile:
transform = np.eye(4, dtype=np.float64)
transform.setflags(write=False)
return Kb4ProjectionProfile(
source_id="sensor.camera.right",
calibration_slot="camera_1",
width=800,
height=600,
intrinsic_fx_fy_cx_cy=(100.0, 100.0, 400.0, 300.0),
distortion_kb4=(0.0, 0.0, 0.0, 0.0),
t_camera_from_lidar=transform,
)
def test_pose_inverse_maps_world_points_back_into_lidar_frame() -> None:
half = math.sqrt(0.5)
points_lidar = map_points_to_lidar(
[[10.0, 21.0, 30.0]],
position_map_xyz=(10.0, 20.0, 30.0),
orientation_map_from_lidar_xyzw=(0.0, 0.0, half, half),
)
np.testing.assert_allclose(points_lidar, [[1.0, 0.0, 0.0]], atol=1e-12)
def test_quaternion_rotation_is_orthonormal_after_normalization() -> None:
rotation = quaternion_xyzw_to_rotation_matrix((0.0, 0.0, 2.0, 2.0))
assert rotation @ rotation.T == pytest.approx(np.eye(3), abs=1e-12)
assert np.linalg.det(rotation) == pytest.approx(1.0, abs=1e-12)
def test_kb4_projection_uses_theta_polynomial_and_rejects_behind_camera() -> None:
projected = project_map_points_kb4(
[[0.0, 0.0, 1.0], [1.0, 0.0, 1.0], [0.0, 0.0, -1.0]],
position_map_xyz=(0.0, 0.0, 0.0),
orientation_map_from_lidar_xyzw=(0.0, 0.0, 0.0, 1.0),
profile=_identity_profile(),
)
assert projected.source_point_count == 3
assert projected.camera_front_point_count == 2
assert projected.projected_point_count == 2
assert projected.pixels_xy[0] == pytest.approx([400.0, 300.0])
assert projected.pixels_xy[1] == pytest.approx(
[400.0 + 100.0 * math.pi / 4.0, 300.0]
)
assert projected.source_indices.tolist() == [0, 1]
def test_factory_profile_binds_right_main_camera_and_scales_intrinsics() -> None:
calibration = parse_k1_factory_calibration(
(FIXTURES / "camera.yaml").read_bytes(),
(FIXTURES / "extrinsic_camera_lidar.yaml").read_bytes(),
)
profile = Kb4ProjectionProfile.from_factory_calibration(
calibration,
"sensor.camera.right",
)
camera = calibration.camera("camera_1")
assert profile.calibration_slot == "camera_1"
assert (profile.width, profile.height) == (800, 600)
assert profile.intrinsic_fx_fy_cx_cy == pytest.approx(
tuple(value * 0.2 for value in camera.intrinsic)
)
assert profile.t_camera_from_lidar == pytest.approx(
np.asarray(calibration.t_camera_from_lidar("camera_1"))
)
def test_projection_rejects_unknown_camera_and_invalid_quaternion() -> None:
calibration = parse_k1_factory_calibration(
(FIXTURES / "camera.yaml").read_bytes(),
(FIXTURES / "extrinsic_camera_lidar.yaml").read_bytes(),
)
with pytest.raises(CalibratedProjectionError, match="admitted K1 main camera"):
Kb4ProjectionProfile.from_factory_calibration(calibration, "sensor.camera.unknown")
with pytest.raises(CalibratedProjectionError, match="no usable norm"):
quaternion_xyzw_to_rotation_matrix((0.0, 0.0, 0.0, 0.0))
def test_depth_colors_are_bounded_and_repeatable() -> None:
first = depth_colors([1.0, 2.0, 3.0])
second = depth_colors([1.0, 2.0, 3.0])
assert first.dtype == np.uint8
assert first.shape == (3, 3)
assert np.array_equal(first, second)
assert first[0, 0] > first[0, 2]
assert first[-1, 2] > first[-1, 0]
+422
View File
@@ -0,0 +1,422 @@
from __future__ import annotations
import json
from collections import deque
from datetime import UTC, datetime
from pathlib import Path
from types import SimpleNamespace
from typing import Any
import paho.mqtt.client as mqtt
import pytest
from k1link.device_plugins.xgrids_k1.calibration_snapshot import (
seal_factory_calibration_snapshot,
)
from k1link.device_plugins.xgrids_k1.protocol.application_bootstrap import (
ApplicationControlAuthority,
LiveDeviceControlBinding,
)
from k1link.device_plugins.xgrids_k1.protocol.calibration_file import (
CALIBRATION_FILE_READ_COMMAND,
CALIBRATION_FILE_REQUEST_TOPIC,
CALIBRATION_FILE_RESPONSE_TOPIC,
FACTORY_CALIBRATION_PATHS,
FACTORY_CAMERA_CALIBRATION_PATH,
FACTORY_CAMERA_LIDAR_EXTRINSIC_PATH,
CalibrationFileProtocolError,
CalibrationFileRejected,
build_factory_calibration_file_read,
decode_factory_calibration_file_response,
)
from k1link.device_plugins.xgrids_k1.protocol.calibration_mqtt import (
CALIBRATION_READ_SUBSCRIPTIONS,
FactoryCalibrationReadResult,
ReviewedCalibrationMqttReader,
)
from k1link.device_plugins.xgrids_k1.protocol.modeling_control import OPENAPI_SUCCESS
from k1link.device_plugins.xgrids_k1.protocol.protobuf_wire import iter_fields
APPLICATION_KEY = "11111111-2222-3333-4444-555555555555"
VENDOR_DEVICE_ID = "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
DEVICE_SERIAL = "K1SERIAL01"
PROFILE_ID = "xgrids.lixelkity-k1.fw-3.0.2.local-network.v2"
CALIBRATION_FIXTURE_ROOT = Path(__file__).parent / "fixtures" / "k1" / "calibration"
def _authority() -> ApplicationControlAuthority:
return ApplicationControlAuthority(openapi_key=APPLICATION_KEY)
def _binding(**changes: object) -> LiveDeviceControlBinding:
values = {
"vendor_device_id": VENDOR_DEVICE_ID,
"device_serial": DEVICE_SERIAL,
"software_version": "V3.0.2",
"system_version": "V3.0.2",
"device_model": "LixelKity K1",
"device_type": "A4",
"is_activated": True,
}
values.update(changes)
return LiveDeviceControlBinding(**values) # type: ignore[arg-type]
def _varint(value: int) -> bytes:
encoded = bytearray()
while value > 0x7F:
encoded.append((value & 0x7F) | 0x80)
value >>= 7
encoded.append(value)
return bytes(encoded)
def _uint(number: int, value: int) -> bytes:
return _varint(number << 3) + _varint(value)
def _bytes(number: int, value: bytes) -> bytes:
return _varint((number << 3) | 2) + _varint(len(value)) + value
def _text(number: int, value: str) -> bytes:
return _bytes(number, value.encode("utf-8"))
def _header(session_id: str) -> bytes:
return b"".join(
(
_text(4, VENDOR_DEVICE_ID),
_text(5, session_id),
_text(6, APPLICATION_KEY),
)
)
def _device_info_response() -> bytes:
base_info = b"".join(
(
_text(2, "V3.0.2"),
_text(3, "V3.0.2"),
_text(6, "LixelKity K1"),
_text(7, DEVICE_SERIAL),
_text(8, "A4"),
)
)
working_status = _uint(1, 1)
device_info = _bytes(2, base_info) + _bytes(7, working_status)
return b"".join(
(
_bytes(1, _header(":DeviceInfoRequest")),
_bytes(2, device_info),
_bytes(15, _uint(1, OPENAPI_SUCCESS)),
)
)
def _calibration_response(
path: str,
content: bytes,
*,
command: int = CALIBRATION_FILE_READ_COMMAND,
result_code: int = OPENAPI_SUCCESS,
session_id: str | None = None,
) -> bytes:
return b"".join(
(
_bytes(
1,
_header(
session_id or f"{VENDOR_DEVICE_ID}:CalibFileRequest"
),
),
_uint(2, command),
_text(3, path),
_bytes(4, content),
_bytes(15, _uint(1, result_code)),
)
)
def _content_for(path: str) -> bytes:
if path == FACTORY_CAMERA_CALIBRATION_PATH:
return (CALIBRATION_FIXTURE_ROOT / "camera.yaml").read_bytes()
return (CALIBRATION_FIXTURE_ROOT / "extrinsic_camera_lidar.yaml").read_bytes()
def test_factory_file_request_is_command_five_and_has_no_content_field() -> None:
request = build_factory_calibration_file_read(
_authority(),
_binding(),
FACTORY_CAMERA_CALIBRATION_PATH,
)
fields = {field.number: field.value for field in iter_fields(request.payload)}
header = fields[1]
assert isinstance(header, bytes)
header_fields = {field.number: field.value for field in iter_fields(header)}
assert request.topic == CALIBRATION_FILE_REQUEST_TOPIC
assert request.response_topic == CALIBRATION_FILE_RESPONSE_TOPIC
assert request.mutates_device is False
assert request.automatic_retry is False
assert fields[2] == 5
assert fields[3] == FACTORY_CAMERA_CALIBRATION_PATH.encode()
assert 4 not in fields
assert header_fields[4] == VENDOR_DEVICE_ID.encode()
assert header_fields[5] == f"{VENDOR_DEVICE_ID}:CalibFileRequest".encode()
assert header_fields[6] == APPLICATION_KEY.encode()
@pytest.mark.parametrize(
"path",
(
"/mnt/system/factory-data/config/../Lixel.yaml",
"/mnt/system/factory-data/config/extrinsic_camera_motor.yaml",
"/tmp/camera.yaml",
"",
),
)
def test_factory_file_request_rejects_every_path_outside_two_file_allowlist(
path: str,
) -> None:
with pytest.raises(CalibrationFileProtocolError, match="two-file allowlist"):
build_factory_calibration_file_read(_authority(), _binding(), path)
def test_factory_file_request_rejects_a_nonreviewed_live_binding() -> None:
with pytest.raises(CalibrationFileProtocolError, match="reviewed activated"):
build_factory_calibration_file_read(
_authority(),
_binding(system_version="V3.0.3"),
FACTORY_CAMERA_CALIBRATION_PATH,
)
def test_correlated_factory_file_response_returns_exact_utf8_bytes() -> None:
request = build_factory_calibration_file_read(
_authority(),
_binding(),
FACTORY_CAMERA_CALIBRATION_PATH,
)
content = _content_for(request.path)
result = decode_factory_calibration_file_response(
_calibration_response(request.path, content),
request,
_authority(),
_binding(),
)
assert result.path == request.path
assert result.content == content
assert result.content_bytes == len(content)
assert len(result.content_sha256) == 64
assert result.result_code == OPENAPI_SUCCESS
def test_factory_file_response_rejects_write_command_path_drift_and_duplicates() -> None:
request = build_factory_calibration_file_read(
_authority(),
_binding(),
FACTORY_CAMERA_CALIBRATION_PATH,
)
with pytest.raises(CalibrationFileProtocolError, match="not a file-read"):
decode_factory_calibration_file_response(
_calibration_response(request.path, b"yaml", command=6),
request,
_authority(),
_binding(),
)
with pytest.raises(CalibrationFileProtocolError, match="path mismatch"):
decode_factory_calibration_file_response(
_calibration_response(FACTORY_CAMERA_LIDAR_EXTRINSIC_PATH, b"yaml"),
request,
_authority(),
_binding(),
)
duplicate_path = _calibration_response(request.path, b"yaml") + _text(3, request.path)
with pytest.raises(CalibrationFileProtocolError, match="duplicated"):
decode_factory_calibration_file_response(
duplicate_path,
request,
_authority(),
_binding(),
)
def test_factory_file_response_rejects_device_error_and_non_utf8_content() -> None:
request = build_factory_calibration_file_read(
_authority(),
_binding(),
FACTORY_CAMERA_CALIBRATION_PATH,
)
with pytest.raises(CalibrationFileRejected) as rejected:
decode_factory_calibration_file_response(
_calibration_response(request.path, b"yaml", result_code=123),
request,
_authority(),
_binding(),
)
assert rejected.value.result_code == 123
with pytest.raises(CalibrationFileProtocolError, match="valid UTF-8"):
decode_factory_calibration_file_response(
_calibration_response(request.path, b"\xff"),
request,
_authority(),
_binding(),
)
class FakeReasonCode:
def __init__(self, *, failure: bool = False) -> None:
self.is_failure = failure
class FakeCalibrationClient:
def __init__(self) -> None:
self.on_connect: Any = None
self.on_subscribe: Any = None
self.on_publish: Any = None
self.on_message: Any = None
self.on_disconnect: Any = None
self.connect_timeout = 0.0
self.events: deque[tuple[str, object]] = deque()
self.connect_calls: list[tuple[str, int, int]] = []
self.subscribe_calls: list[list[tuple[str, int]]] = []
self.publish_calls: list[tuple[str, bytes, int, bool]] = []
self.unsubscribe_calls: list[list[str]] = []
self.next_mid = 20
def connect(self, host: str, port: int, keepalive: int) -> mqtt.MQTTErrorCode:
self.connect_calls.append((host, port, keepalive))
self.events.append(("connect", FakeReasonCode()))
return mqtt.MQTT_ERR_SUCCESS
def subscribe(self, topics: list[tuple[str, int]]) -> tuple[mqtt.MQTTErrorCode, int]:
self.subscribe_calls.append(topics)
self.events.append(("subscribe", 7))
return mqtt.MQTT_ERR_SUCCESS, 7
def publish(
self,
topic: str,
payload: bytes,
qos: int,
retain: bool,
) -> SimpleNamespace:
self.publish_calls.append((topic, payload, qos, retain))
mid = self.next_mid
self.next_mid += 1
self.events.append(("publish", mid))
if topic == "lixel/application/request/device_info":
response_topic = "lixel/application/response/device_info"
response_payload = _device_info_response()
else:
fields = {field.number: field.value for field in iter_fields(payload)}
raw_path = fields[3]
assert isinstance(raw_path, bytes)
path = raw_path.decode()
response_topic = CALIBRATION_FILE_RESPONSE_TOPIC
response_payload = _calibration_response(path, _content_for(path))
self.events.append(("message", (response_topic, response_payload)))
return SimpleNamespace(rc=mqtt.MQTT_ERR_SUCCESS, mid=mid)
def loop(self, timeout: float) -> mqtt.MQTTErrorCode:
del timeout
if not self.events:
return mqtt.MQTT_ERR_SUCCESS
kind, value = self.events.popleft()
if kind == "connect":
self.on_connect(self, None, SimpleNamespace(), value, None)
elif kind == "subscribe":
self.on_subscribe(
self,
None,
value,
[FakeReasonCode() for _topic in CALIBRATION_READ_SUBSCRIPTIONS],
None,
)
elif kind == "publish":
self.on_publish(self, None, value, FakeReasonCode(), None)
elif kind == "message":
topic, payload = value
self.on_message(self, None, SimpleNamespace(topic=topic, payload=payload))
return mqtt.MQTT_ERR_SUCCESS
def unsubscribe(self, topics: list[str]) -> tuple[mqtt.MQTTErrorCode, int]:
self.unsubscribe_calls.append(topics)
return mqtt.MQTT_ERR_SUCCESS, 50
def disconnect(self) -> mqtt.MQTTErrorCode:
return mqtt.MQTT_ERR_SUCCESS
def test_reviewed_mqtt_reader_performs_one_identity_read_then_two_exact_file_reads() -> None:
client = FakeCalibrationClient()
reader = ReviewedCalibrationMqttReader(
"10.255.254.54",
client_factory=lambda: client, # type: ignore[arg-type]
)
result = reader.read_factory_calibration(_authority())
assert result.binding == _binding()
assert [item.path for item in result.files] == list(FACTORY_CALIBRATION_PATHS)
assert client.subscribe_calls == [list(CALIBRATION_READ_SUBSCRIPTIONS)]
assert [topic for topic, _payload, _qos, _retain in client.publish_calls] == [
"lixel/application/request/device_info",
CALIBRATION_FILE_REQUEST_TOPIC,
CALIBRATION_FILE_REQUEST_TOPIC,
]
assert all(qos == 2 and not retain for _topic, _payload, qos, retain in client.publish_calls)
assert result.transport["publish_attempts"] == 3
assert result.transport["correlated_responses"] == 3
assert result.transport["write_command_available"] is False
def test_private_snapshot_is_new_only_and_hashes_both_exact_artifacts(tmp_path: Path) -> None:
files = tuple(
decode_factory_calibration_file_response(
_calibration_response(path, _content_for(path)),
build_factory_calibration_file_read(_authority(), _binding(), path),
_authority(),
_binding(),
)
for path in FACTORY_CALIBRATION_PATHS
)
result = FactoryCalibrationReadResult(
binding=_binding(),
files=(files[0], files[1]),
transport={"automatic_retry": False, "publish_attempts": 3},
)
snapshot = seal_factory_calibration_snapshot(
result,
evidence_root=tmp_path,
compatibility_profile_id=PROFILE_ID,
captured_at=datetime(2026, 7, 20, 10, 30, tzinfo=UTC),
)
assert snapshot["status"] == "available"
internal = snapshot["device_internal_calibration"]
assert isinstance(internal, dict)
snapshot_path = Path(str(internal["private_snapshot_path"]))
assert snapshot_path.is_dir()
assert (snapshot_path / "camera.yaml").read_bytes() == _content_for(
FACTORY_CAMERA_CALIBRATION_PATH
)
assert (snapshot_path / "extrinsic_camera_lidar.yaml").read_bytes() == _content_for(
FACTORY_CAMERA_LIDAR_EXTRINSIC_PATH
)
manifest = json.loads((snapshot_path / "manifest.json").read_text(encoding="utf-8"))
assert manifest["source"]["request_command"] == 5
assert manifest["source"]["write_command_available"] is False
assert manifest["normalized_calibration"]["transform_notation"] == (
"T_destination_from_source"
)
assert [item["source_path"] for item in manifest["artifacts"]] == list(
FACTORY_CALIBRATION_PATHS
)
assert snapshot_path.stat().st_mode & 0o777 == 0o700
assert all(path.stat().st_mode & 0o777 == 0o600 for path in snapshot_path.iterdir())
assert internal["camera_stream_mapping"]["status"] == "firmware-profile-verified"
+111
View File
@@ -0,0 +1,111 @@
from __future__ import annotations
from pathlib import Path
import pytest
from k1link.device_plugins.xgrids_k1.calibration_schema import (
FactoryCalibrationSchemaError,
parse_k1_factory_calibration,
)
FIXTURE_ROOT = Path(__file__).parent / "fixtures" / "k1" / "calibration"
def _documents() -> tuple[bytes, bytes]:
return (
(FIXTURE_ROOT / "camera.yaml").read_bytes(),
(FIXTURE_ROOT / "extrinsic_camera_lidar.yaml").read_bytes(),
)
def test_factory_calibration_normalizes_main_camera_mapping_and_transforms() -> None:
calibration = parse_k1_factory_calibration(*_documents())
profile = calibration.normalized_profile()
streams = profile["stream_bindings"]
assert isinstance(streams, dict)
left = streams["sensor.camera.left"]
right = streams["sensor.camera.right"]
assert isinstance(left, dict)
assert isinstance(right, dict)
assert left["calibration_slot"] == "camera_0"
assert right["calibration_slot"] == "camera_1"
assert left["rtsp_path"] == "/live/chn_left_main"
assert right["rtsp_path"] == "/live/chn_right_main"
assert left["native_resolution"] == [4000, 3000]
assert left["admitted_resolution"] == [800, 600]
assert left["admitted_intrinsic_fx_fy_cx_cy"] == pytest.approx(
[193.6, 193.6, 400.0, 300.0]
)
assert right["admitted_intrinsic_fx_fy_cx_cy"] == pytest.approx(
[194.0, 194.2, 396.0, 302.0]
)
assert profile["transform_notation"] == "T_destination_from_source"
right_transform = calibration.t_camera_from_lidar("camera_1")
assert right_transform[0] == pytest.approx((-1.0, 0.0, 0.0, 0.007))
assert right_transform[1] == pytest.approx((0.0, 0.0, -1.0, -0.0948))
assert right_transform[2] == pytest.approx((0.0, -1.0, 0.0, -0.0328))
@pytest.mark.parametrize(
("mutation", "message"),
[
(
lambda data: data.replace(
b"calibrated: true\n",
b"calibrated: true\ncalibrated: true\n",
1,
),
"safe valid YAML",
),
(
lambda data: data.replace(
b"camera_pose: [1, 0, 0, 0,",
b"camera_pose: &pose [1, 0, 0, 0,",
1,
),
"anchors",
),
(
lambda data: data.replace(b"intrinsic: [968,", b"intrinsic: [.nan,", 1),
"finite",
),
(
lambda data: data.replace(b"image_width: 4000", b"image_width: 3999", 1),
"resolution",
),
(
lambda data: data.replace(
b"camera_model: kb4",
b"camera_model: kb4\n unexpected: true",
1,
),
"unexpected key set",
),
],
)
def test_factory_calibration_rejects_unsafe_or_nonprofile_camera_yaml(
mutation: object,
message: str,
) -> None:
camera, extrinsic = _documents()
mutate = mutation
assert callable(mutate)
with pytest.raises(FactoryCalibrationSchemaError, match=message):
parse_k1_factory_calibration(mutate(camera), extrinsic)
def test_factory_calibration_rejects_version_or_rigid_transform_mismatch() -> None:
camera, extrinsic = _documents()
mismatched = extrinsic.replace(b"V2.2.0_alpha", b"V2.2.1_alpha")
with pytest.raises(FactoryCalibrationSchemaError, match="versions do not match"):
parse_k1_factory_calibration(camera, mismatched)
invalid_rotation = extrinsic.replace(
b"transform: [1, 0, 0,",
b"transform: [2, 0, 0,",
)
with pytest.raises(FactoryCalibrationSchemaError, match="not orthonormal"):
parse_k1_factory_calibration(camera, invalid_rotation)
+40
View File
@@ -12,6 +12,7 @@ import pytest
import k1link.device_plugins.xgrids_k1.camera as camera_module
from k1link.device_plugins.xgrids_k1.camera import (
CAMERA_MEDIA_TYPE,
CommittedCameraSegment,
XgridsK1CameraGateway,
_build_ffmpeg_argv,
_read_mp4_box,
@@ -169,6 +170,45 @@ def test_camera_selection_is_exclusive_and_hides_device_transport(
gateway.close()
def test_camera_derived_observer_runs_only_after_durable_archive_commit(
tmp_path: Path,
monkeypatch: pytest.MonkeyPatch,
) -> None:
monkeypatch.setenv("MISSIONCORE_FFMPEG_BINARY", str(_fake_ffmpeg(tmp_path)))
session = tmp_path / "session"
session.mkdir()
observed: list[CommittedCameraSegment] = []
def observe(segment: CommittedCameraSegment) -> None:
archive = (
session
/ "media"
/ segment.source_id
/ f"epoch-{segment.generation}"
)
committed = (
archive / "init.mp4"
if segment.kind == "init"
else archive / "segments" / f"{segment.sequence}.m4s"
)
assert committed.read_bytes() == segment.payload
observed.append(segment)
gateway = XgridsK1CameraGateway(
tmp_path,
XGRIDS_K1_PLUGIN_ID,
committed_segment_observer=observe,
)
try:
gateway.start_recording(session)
gateway.select("sensor.camera.right", "192.168.8.52")
_wait_until(lambda: len(observed) == 2)
assert [segment.kind for segment in observed] == ["init", "media"]
assert gateway.snapshot()["derived_observer_errors"] == 0
finally:
gateway.close()
def test_camera_ffmpeg_command_is_allowlisted_copy_remux() -> None:
argv = _build_ffmpeg_argv(
Path("/trusted/ffmpeg"),
+87
View File
@@ -0,0 +1,87 @@
from __future__ import annotations
import io
import tarfile
from pathlib import Path
import pytest
import k1link.device_plugins.xgrids_k1.firmware_credential as firmware_credential
FIXTURE_SECRET = b"fixture-only-network-secret"
def _tar_gz_member(name: str, payload: bytes) -> bytes:
output = io.BytesIO()
with tarfile.open(fileobj=output, mode="w:gz") as archive:
member = tarfile.TarInfo(name)
member.size = len(payload)
archive.addfile(member, io.BytesIO(payload))
return output.getvalue()
def test_exact_official_archive_extracts_one_bounded_declaration(
monkeypatch: pytest.MonkeyPatch,
tmp_path: Path,
) -> None:
prefix = b"synthetic-rk-prefix"
apps = (
b"\x00" * 17
+ firmware_credential._AP_PSK_DECLARATION
+ FIXTURE_SECRET
+ b"\n"
+ b"\x00" * 31
)
image = prefix + apps
upgrade = _tar_gz_member(firmware_credential.K1_FW302_RK_IMAGE_MEMBER, image)
outer = _tar_gz_member(firmware_credential.K1_FW302_OUTER_MEMBER, upgrade)
archive_path = tmp_path / "official-fw.tar"
archive_path.write_bytes(outer)
monkeypatch.setattr(firmware_credential, "K1_FW302_APPS_OFFSET", len(prefix))
monkeypatch.setattr(firmware_credential, "K1_FW302_APPS_SIZE", len(apps))
monkeypatch.setattr(
firmware_credential,
"_sha256",
lambda _path: firmware_credential.K1_FW302_OFFICIAL_ARCHIVE_SHA256,
)
secret, digest = firmware_credential.extract_k1_fw302_ap_credential(archive_path)
try:
assert secret.reveal_ascii() == FIXTURE_SECRET.decode("ascii")
assert FIXTURE_SECRET.decode("ascii") not in repr(secret)
assert digest == firmware_credential.K1_FW302_OFFICIAL_ARCHIVE_SHA256
finally:
secret.zeroize()
def test_archive_hash_mismatch_stops_before_unpack(
monkeypatch: pytest.MonkeyPatch,
tmp_path: Path,
) -> None:
archive_path = tmp_path / "wrong-fw.tar"
archive_path.write_bytes(b"not-reviewed")
monkeypatch.setattr(firmware_credential, "_sha256", lambda _path: "0" * 64)
with pytest.raises(
firmware_credential.FirmwareCredentialError,
match="SHA-256",
):
firmware_credential.extract_k1_fw302_ap_credential(archive_path)
def test_duplicate_declarations_fail_closed_without_exposing_values() -> None:
payload = b"\n".join(
[
firmware_credential._AP_PSK_DECLARATION + FIXTURE_SECRET,
firmware_credential._AP_PSK_DECLARATION + b"second-fixture-secret",
]
) + b"\n"
with pytest.raises(
firmware_credential.FirmwareCredentialError,
match="not unique",
) as raised:
firmware_credential._credential_from_chunks(iter([payload]))
assert FIXTURE_SECRET.decode("ascii") not in str(raised.value)
+254 -31
View File
@@ -6,9 +6,11 @@ from pathlib import Path
import pytest
from k1link.device_plugins.xgrids_k1 import macos_wifi
from k1link.host_network import wifi
TEST_PASSWORD = "fixture-only-network-secret"
TEST_PROFILE_ID = "fixture.quick-connect.v1"
TEST_CREDENTIAL_SOURCE_ID = "fixture.firmware-provider.v1"
def _helper(tmp_path: Path) -> Path:
@@ -17,35 +19,33 @@ def _helper(tmp_path: Path) -> Path:
return helper
def test_association_passes_secret_only_through_stdin(
def test_association_exposes_only_profile_id_and_expected_ssid_to_platform_helper(
monkeypatch: pytest.MonkeyPatch,
tmp_path: Path,
) -> None:
monkeypatch.setattr(macos_wifi.sys, "platform", "darwin")
monkeypatch.setattr(wifi.sys, "platform", "darwin")
calls: list[dict[str, object]] = []
live_inputs: list[bytearray] = []
def fake_runner(argv: list[str], **kwargs: object) -> subprocess.CompletedProcess[bytes]:
assert isinstance(kwargs["input"], bytearray)
live_inputs.append(kwargs["input"])
calls.append(
{
"argv": argv,
**kwargs,
"input": bytes(kwargs["input"]),
}
)
calls.append({"argv": argv, **kwargs, "input": bytes(kwargs["input"])})
return subprocess.CompletedProcess(
argv,
0,
stdout=b'{"ok":true,"already_associated":false}',
stdout=(
b'{"ok":true,"adapter":"CoreWLAN","already_associated":false,'
b'"profile_enrolled":true,"scan_attempt_count":3,'
b'"scan_elapsed_ms":1840,"credential_source":"system-wifi-keychain"}'
),
stderr=b"",
)
result = macos_wifi.associate_with_wifi_once(
result = wifi.associate_with_wifi_profile_once(
_helper(tmp_path),
TEST_PROFILE_ID,
"XGR-OFFLINE",
TEST_PASSWORD,
runner=fake_runner,
)
@@ -54,55 +54,278 @@ def test_association_passes_secret_only_through_stdin(
"adapter": "CoreWLAN",
"outcome": "associated",
"already_associated": False,
"profile_enrolled": True,
"scan_attempt_count": 3,
"scan_elapsed_ms": 1840,
"credential_source": "system-wifi-keychain",
}
assert len(calls) == 1
call = calls[0]
assert call["argv"][:2] == ["/usr/bin/xcrun", "swift"]
assert TEST_PASSWORD not in " ".join(call["argv"])
request = json.loads(bytes(call["input"]).decode("utf-8"))
assert request == {"ssid": "XGR-OFFLINE", "password": TEST_PASSWORD}
assert request == {
"action": "associate",
"profile_id": TEST_PROFILE_ID,
"ssid": "XGR-OFFLINE",
"scan_timeout_seconds": 15.0,
}
assert call["check"] is False
assert call["timeout"] == 45.0
assert call["timeout"] == 180.0
assert live_inputs and not any(live_inputs[0])
def test_profile_store_passes_secret_only_through_stdin(
monkeypatch: pytest.MonkeyPatch,
tmp_path: Path,
) -> None:
monkeypatch.setattr(wifi.sys, "platform", "darwin")
captured: dict[str, object] = {}
live_inputs: list[bytearray] = []
def fake_runner(argv: list[str], **kwargs: object) -> subprocess.CompletedProcess[bytes]:
assert isinstance(kwargs["input"], bytearray)
live_inputs.append(kwargs["input"])
captured.update({"argv": argv, **kwargs, "input": bytes(kwargs["input"])})
return subprocess.CompletedProcess(
argv,
0,
stdout=b'{"ok":true,"adapter":"macOS Keychain","stored":true}',
stderr=b"",
)
result = wifi.store_wifi_profile_once(
_helper(tmp_path),
TEST_PROFILE_ID,
"XGR-OFFLINE",
TEST_PASSWORD,
runner=fake_runner,
)
assert result["outcome"] == "stored"
assert TEST_PASSWORD not in " ".join(captured["argv"])
request = json.loads(bytes(captured["input"]).decode("utf-8"))
assert request == {
"action": "store-profile",
"profile_id": TEST_PROFILE_ID,
"ssid": "XGR-OFFLINE",
"password": TEST_PASSWORD,
}
assert live_inputs and not any(live_inputs[0])
def test_firmware_material_store_passes_secret_only_through_stdin(
monkeypatch: pytest.MonkeyPatch,
tmp_path: Path,
) -> None:
monkeypatch.setattr(wifi.sys, "platform", "darwin")
captured: dict[str, object] = {}
live_inputs: list[bytearray] = []
def fake_runner(argv: list[str], **kwargs: object) -> subprocess.CompletedProcess[bytes]:
assert isinstance(kwargs["input"], bytearray)
live_inputs.append(kwargs["input"])
captured.update({"argv": argv, **kwargs, "input": bytes(kwargs["input"])})
return subprocess.CompletedProcess(
argv,
0,
stdout=b'{"ok":true,"adapter":"macOS Keychain","stored":true}',
stderr=b"",
)
result = wifi.store_wifi_credential_material(
_helper(tmp_path),
TEST_CREDENTIAL_SOURCE_ID,
TEST_PASSWORD,
runner=fake_runner,
)
assert result["outcome"] == "stored"
assert TEST_PASSWORD not in " ".join(captured["argv"])
request = json.loads(bytes(captured["input"]).decode("utf-8"))
assert request == {
"action": "store-credential-material",
"profile_id": TEST_CREDENTIAL_SOURCE_ID,
"password": TEST_PASSWORD,
}
assert live_inputs and not any(live_inputs[0])
def test_profile_is_materialized_from_opaque_firmware_source(
monkeypatch: pytest.MonkeyPatch,
tmp_path: Path,
) -> None:
monkeypatch.setattr(wifi.sys, "platform", "darwin")
captured: dict[str, object] = {}
def fake_runner(argv: list[str], **kwargs: object) -> subprocess.CompletedProcess[bytes]:
captured.update({"argv": argv, **kwargs, "input": bytes(kwargs["input"])})
return subprocess.CompletedProcess(
argv,
0,
stdout=(
b'{"ok":true,"adapter":"macOS Keychain","profile_available":true,'
b'"profile_enrolled":true,"credential_source":"exact-firmware-profile"}'
),
stderr=b"",
)
result = wifi.ensure_wifi_profile_from_credential_source(
_helper(tmp_path),
TEST_PROFILE_ID,
"XGR-OFFLINE",
TEST_CREDENTIAL_SOURCE_ID,
runner=fake_runner,
)
assert result == {
"schema_version": 1,
"adapter": "macOS Keychain",
"available": True,
"profile_enrolled": True,
"credential_source": "exact-firmware-profile",
}
request = json.loads(bytes(captured["input"]).decode("utf-8"))
assert request == {
"action": "ensure-profile",
"profile_id": TEST_PROFILE_ID,
"ssid": "XGR-OFFLINE",
"credential_source_id": TEST_CREDENTIAL_SOURCE_ID,
}
assert TEST_PASSWORD not in bytes(captured["input"]).decode("utf-8")
@pytest.mark.parametrize("available", [True, False])
def test_profile_preflight_checks_only_the_expected_keychain_item(
monkeypatch: pytest.MonkeyPatch,
tmp_path: Path,
available: bool,
) -> None:
monkeypatch.setattr(wifi.sys, "platform", "darwin")
captured: dict[str, object] = {}
def fake_runner(argv: list[str], **kwargs: object) -> subprocess.CompletedProcess[bytes]:
captured.update({"argv": argv, **kwargs, "input": bytes(kwargs["input"])})
encoded_available = b"true" if available else b"false"
return subprocess.CompletedProcess(
argv,
0,
stdout=(
b'{"ok":true,"adapter":"macOS Keychain","profile_available":'
+ encoded_available
+ b"}"
),
stderr=b"",
)
result = wifi.check_wifi_profile(
_helper(tmp_path),
TEST_PROFILE_ID,
"XGR-OFFLINE",
runner=fake_runner,
)
assert result == {
"schema_version": 1,
"adapter": "macOS Keychain",
"available": available,
}
request = json.loads(bytes(captured["input"]).decode("utf-8"))
assert request == {
"action": "check-profile",
"profile_id": TEST_PROFILE_ID,
"ssid": "XGR-OFFLINE",
}
def test_association_reports_only_sanitized_helper_reason(
monkeypatch: pytest.MonkeyPatch,
tmp_path: Path,
) -> None:
monkeypatch.setattr(macos_wifi.sys, "platform", "darwin")
monkeypatch.setattr(wifi.sys, "platform", "darwin")
def fake_runner(argv: list[str], **_: object) -> subprocess.CompletedProcess[bytes]:
return subprocess.CompletedProcess(
argv,
1,
stdout=b'{"ok":false,"reason_code":"network-not-found"}',
stdout=(
b'{"ok":false,"reason_code":"network-not-found",'
b'"scan_attempt_count":4,"scan_elapsed_ms":15021}'
),
stderr=f"private diagnostic {TEST_PASSWORD}".encode(),
)
with pytest.raises(
macos_wifi.HostWifiAssociationError,
match="network-not-found",
) as raised:
macos_wifi.associate_with_wifi_once(
with pytest.raises(wifi.HostWifiProfileError, match="network-not-found") as raised:
wifi.associate_with_wifi_profile_once(
_helper(tmp_path),
TEST_PROFILE_ID,
"XGR-OFFLINE",
TEST_PASSWORD,
runner=fake_runner,
)
assert TEST_PASSWORD not in str(raised.value)
assert raised.value.scan_attempt_count == 4
assert raised.value.scan_elapsed_ms == 15021
def test_association_is_macos_only(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setattr(macos_wifi.sys, "platform", "linux")
def test_association_reports_operator_timeout_separately_from_missing_helper(
monkeypatch: pytest.MonkeyPatch,
tmp_path: Path,
) -> None:
monkeypatch.setattr(wifi.sys, "platform", "darwin")
def timed_out_runner(
argv: list[str], **_: object
) -> subprocess.CompletedProcess[bytes]:
raise subprocess.TimeoutExpired(argv, timeout=180.0)
with pytest.raises(
macos_wifi.HostWifiAssociationError,
match="unsupported-platform",
):
macos_wifi.associate_with_wifi_once(
wifi.HostWifiProfileError,
match="host-wifi-operation-timeout",
) as raised:
wifi.associate_with_wifi_profile_once(
_helper(tmp_path),
TEST_PROFILE_ID,
"XGR-OFFLINE",
runner=timed_out_runner,
)
assert raised.value.reason_code == "host-wifi-operation-timeout"
def test_association_reports_an_unavailable_helper_separately_from_timeout(
monkeypatch: pytest.MonkeyPatch,
tmp_path: Path,
) -> None:
monkeypatch.setattr(wifi.sys, "platform", "darwin")
def unavailable_runner(
_: list[str], **__: object
) -> subprocess.CompletedProcess[bytes]:
raise OSError("offline fixture")
with pytest.raises(
wifi.HostWifiProfileError,
match="host-wifi-helper-unavailable",
) as raised:
wifi.associate_with_wifi_profile_once(
_helper(tmp_path),
TEST_PROFILE_ID,
"XGR-OFFLINE",
runner=unavailable_runner,
)
assert raised.value.reason_code == "host-wifi-helper-unavailable"
def test_association_rejects_an_uninstalled_platform(
tmp_path: Path,
monkeypatch: pytest.MonkeyPatch,
) -> None:
monkeypatch.setattr(wifi.sys, "platform", "linux")
with pytest.raises(wifi.HostWifiProfileError, match="unsupported-platform"):
wifi.associate_with_wifi_profile_once(
_helper(tmp_path),
TEST_PROFILE_ID,
"XGR-OFFLINE",
TEST_PASSWORD,
)