feat(perception): add PointPillars visual audit

This commit is contained in:
DCCONSTRUCTIONS
2026-07-31 11:47:04 +03:00
parent 8fe6184c52
commit a2cb50d1ad
16 changed files with 2351 additions and 4 deletions
+170
View File
@@ -0,0 +1,170 @@
from __future__ import annotations
import hashlib
import json
from pathlib import Path
from fastapi import APIRouter
from fastapi.routing import APIRoute
from pytest import raises
from k1link.web.l3_pointpillars_visual_api import (
build_l3_pointpillars_visual_router,
)
def _endpoint(router: APIRouter, path: str) -> object:
for route in router.routes:
if (
isinstance(route, APIRoute)
and route.path == path
and route.methods is not None
and "GET" in route.methods
):
return route.endpoint
raise AssertionError(f"GET {path} route is missing")
def _canonical(payload: object) -> bytes:
return json.dumps(
payload,
ensure_ascii=False,
separators=(",", ":"),
sort_keys=True,
).encode("utf-8")
def _write(path: Path, payload: object) -> dict[str, object]:
content = _canonical(payload)
path.parent.mkdir(parents=True, exist_ok=True)
path.write_bytes(content)
return {
"sha256": hashlib.sha256(content).hexdigest(),
"byte_length": len(content),
}
def _result(root: Path) -> tuple[str, str]:
frame_id = "000001"
identity = {
"source_run_id": f"l3-pointpillars-kitti-{'1' * 64}",
"source_frame_results_identity_sha256": "2" * 64,
"dataset_source_id": "kitti-3d-object/v2017",
"dataset_release_identity_sha256": "3" * 64,
"matching": {"metric": "oriented-3d-iou"},
"point_sampling": {"maximum_points_per_frame": 12000},
"authority": {
"read_only": True,
"commands_enabled": False,
"navigation_or_safety_accepted": False,
},
}
identity_sha = hashlib.sha256(_canonical(identity)).hexdigest()
result_id = f"l3-pointpillars-visual-audit-{identity_sha}"
candidate = root / result_id
summary = {
"frame_id": frame_id,
"inference_ms": 12.5,
"prediction_count": 2,
"evaluated_prediction_count": 1,
"outside_shared_range_count": 1,
"truth_count": 1,
"true_positive_count": 0,
"false_positive_count": 1,
"false_negative_count": 1,
"truth_classes": ["Car"],
}
detail = {
"schema_version": "missioncore.l3-pointpillars-visual-frame/v1",
"frame_id": frame_id,
"summary": summary,
"points": {
"layout": "flat-xyzi",
"source_point_count": 1,
"shared_range_point_count": 1,
"sampled_point_count": 1,
"values": [1, 2, 3, 0.5],
},
"truth_boxes": [],
"prediction_boxes": [],
}
detail_descriptor = _write(candidate / "frames" / f"{frame_id}.json", detail)
descriptor = {
**summary,
"detail_path": f"frames/{frame_id}.json",
"detail_sha256": detail_descriptor["sha256"],
"detail_byte_length": detail_descriptor["byte_length"],
}
catalog = {
"schema_version": (
"missioncore.l3-pointpillars-visual-audit-catalog/v1"
),
"result_id": result_id,
"source_run_id": identity["source_run_id"],
"frame_count": 1,
"frames": [descriptor],
}
catalog_descriptor = _write(candidate / "catalog.json", catalog)
manifest = {
"schema_version": "missioncore.l3-pointpillars-visual-audit/v1",
"result_id": result_id,
"identity_sha256": identity_sha,
"identity": identity,
"created_at_utc": "2026-07-31T10:00:00Z",
"status": "operator-visual-review-required",
"source_metrics": {"frame_count": 3769, "aggregates": {}},
"catalog": {
"path": "catalog.json",
"role": "visual-frame-catalog",
**catalog_descriptor,
},
"authority": identity["authority"],
}
_write(candidate / "manifest.json", manifest)
return result_id, frame_id
def test_l3_visual_catalog_and_frame_are_read_only(tmp_path: Path) -> None:
result_id, frame_id = _result(tmp_path)
router = build_l3_pointpillars_visual_router(root_provider=lambda: tmp_path)
catalog_route = _endpoint(
router,
"/api/v1/laboratory/l3/pointpillars-visual-audits/results",
)
frame_route = _endpoint(
router,
(
"/api/v1/laboratory/l3/pointpillars-visual-audits/"
"{result_id}/frames/{frame_id}"
),
)
catalog = catalog_route(limit=1) # type: ignore[operator]
assert catalog["configured"] is True
assert catalog["invalid_total"] == 0
assert catalog["items"][0]["result_id"] == result_id
assert catalog["items"][0]["frames"][0]["frame_id"] == frame_id
frame = frame_route(result_id=result_id, frame_id=frame_id) # type: ignore[operator]
assert frame["schema_version"] == "missioncore.l3-pointpillars-visual-frame/v1"
assert frame["access"] == "read-only"
def test_l3_visual_frame_fails_closed_after_mutation(tmp_path: Path) -> None:
result_id, frame_id = _result(tmp_path)
router = build_l3_pointpillars_visual_router(root_provider=lambda: tmp_path)
frame_route = _endpoint(
router,
(
"/api/v1/laboratory/l3/pointpillars-visual-audits/"
"{result_id}/frames/{frame_id}"
),
)
(tmp_path / result_id / "frames" / f"{frame_id}.json").write_text(
"{}",
encoding="utf-8",
)
with raises(Exception) as caught:
frame_route(result_id=result_id, frame_id=frame_id) # type: ignore[operator]
assert getattr(caught.value, "status_code", None) == 404