from __future__ import annotations import hashlib import json from pathlib import Path import numpy as np import pytest from fastapi import APIRouter from fastapi.routing import APIRoute from k1link.compute import ( E10_LIDAR_PACK_SCHEMA, E10LidarFieldSource, FieldReviewWindowSpec, GroundBenchmarkProfile, GroundSegmentation, LidarFieldReviewV1, LidarGroundError, build_lidar_field_review, ) from k1link.web.lidar_api import build_lidar_router class _Candidate: @property def identity(self) -> dict[str, object]: return { "provider_id": "test-patchwork/v1", "source_commit": "c" * 40, } def segment(self, xyzi: np.ndarray) -> GroundSegmentation: ground = xyzi[:, 0] <= 0.25 assigned = np.ones(xyzi.shape[0], dtype=np.bool_) return GroundSegmentation(ground, assigned, 0.25) def _canonical_json(value: object) -> bytes: return json.dumps( value, ensure_ascii=False, sort_keys=True, separators=(",", ":"), allow_nan=False, ).encode() def _sha256(path: Path) -> str: return hashlib.sha256(path.read_bytes()).hexdigest() def _source_pack(root: Path) -> Path: base_points = np.asarray( [ [-1.0, -1.0, 0.00], [-0.5, -1.0, 0.02], [0.0, -1.0, 0.01], [0.5, -1.0, 0.03], [1.0, -1.0, 0.00], [-1.0, 0.0, 0.01], [-0.5, 0.0, 0.02], [0.0, 0.0, 0.04], [0.5, 0.0, 0.35], [1.0, 0.0, 0.70], ], dtype=np.float32, ) points = np.concatenate( [base_points + np.asarray([index * 0.1, index, 0], dtype=np.float32) for index in range(4)] ).astype(" 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 test_field_review_is_accumulated_path_free_visual_evidence( tmp_path: Path, ) -> None: source = E10LidarFieldSource(_source_pack(tmp_path / "source")) windows = ( FieldReviewWindowSpec("street-a", "Улица A", 0.5, 2.1, 100), FieldReviewWindowSpec("street-b", "Улица B", 2.5, 4.1, 120), ) previews = {} for window in windows: preview = tmp_path / f"{window.key}.jpg" preview.write_bytes(b"\xff\xd8synthetic-jpeg\xff\xd9") previews[window.key] = preview profile = GroundBenchmarkProfile( profile_id="synthetic-ravnoves00-field-review/v1", patchwork_sensor_height_proxy_m=1.27, patchwork_map_vertical_origin_offset_m=1.27, patchwork_height_evidence="operator-estimated", ) try: output = build_lidar_field_review( source, tmp_path / "reviews", patchwork=_Candidate(), profile=profile, preview_paths=previews, windows=windows, default_window_index=1, maximum_display_points=12, ) finally: source.close() review = LidarFieldReviewV1(output) try: detail = review.window_detail(1) assert review.report["status"] == "diagnostic-only" assert review.report["source"]["intensity_available"] is False assert review.report["selection"]["default_window_index"] == 1 assert len(review.report["windows"]) == 2 assert review.report["windows"][0]["source_lidar_samples"] == 2 assert detail["point_count"] == 12 intensity = detail["intensity"] authority = detail["authority"] assert isinstance(intensity, dict) assert isinstance(authority, dict) assert intensity["available"] is False assert detail["ground_truth"] is False assert authority["commands_enabled"] is False assert str(tmp_path) not in repr(detail) finally: review.close() router = build_lidar_router( root_provider=lambda: None, ground_root_provider=lambda: None, field_review_root_provider=lambda: output.parent, ) catalog_route = _endpoint(router, "/api/v1/lidar/field-reviews") window_route = _endpoint( router, "/api/v1/lidar/field-reviews/{review_id}/windows/{window_index}", ) preview_route = _endpoint( router, "/api/v1/lidar/field-reviews/{review_id}/windows/{window_index}/preview", ) catalog = catalog_route(limit=10) # type: ignore[operator] window = window_route(review_id=output.name, window_index=0) # type: ignore[operator] preview = preview_route(review_id=output.name, window_index=0) # type: ignore[operator] assert catalog["valid_total"] == 1 assert catalog["items"][0]["display_name"] assert window["preview_url"].endswith("/windows/0/preview") assert preview.media_type == "image/jpeg" assert preview.body.startswith(b"\xff\xd8") assert str(tmp_path) not in repr({"catalog": catalog, "window": window}) def test_field_review_reader_rejects_tampered_identity(tmp_path: Path) -> None: source = E10LidarFieldSource(_source_pack(tmp_path / "source")) window = FieldReviewWindowSpec("street-a", "Улица A", 0.5, 4.1, 100) preview = tmp_path / "street-a.jpg" preview.write_bytes(b"\xff\xd8synthetic-jpeg\xff\xd9") try: output = build_lidar_field_review( source, tmp_path / "reviews", patchwork=_Candidate(), profile=GroundBenchmarkProfile(), preview_paths={window.key: preview}, windows=(window,), default_window_index=0, maximum_display_points=12, ) finally: source.close() manifest_path = output / "manifest.json" manifest = json.loads(manifest_path.read_text(encoding="utf-8")) manifest["identity"]["display_name"] = "tampered" manifest_path.write_text(json.dumps(manifest), encoding="utf-8") with pytest.raises(LidarGroundError, match="identity"): LidarFieldReviewV1(output)