"""Persistent map-frame support evidence for conservative object motion.

LAB E25 keeps the detector, semantic masks, full LiDAR cloud, calibration and
source cuboids immutable. It replays the already recorded inputs once, rebuilds
per-object LiDAR support, and compares current occupied cells with older cells
in ``k1-map``. A 3D box remains presentation geometry; motion is not inferred
from the completed box center alone.
"""

from __future__ import annotations

import hashlib
import json
import math
import os
import secrets
import shutil
import time
from collections import Counter, defaultdict, deque
from collections.abc import Mapping, Sequence
from dataclasses import dataclass, field
from datetime import UTC, datetime
from pathlib import Path
from typing import Any

import numpy as np
import numpy.typing as npt

from k1link.artifacts import write_json_atomic
from k1link.device_plugins.xgrids_k1.analyze.calibrated_projection import (
    Kb4ProjectionProfile,
    map_points_to_lidar,
    project_map_points_kb4,
)
from k1link.sessions import SessionIntegrityError

from .integrated_perception import IntegratedPerceptionResult
from .jobs import CameraComputeJob
from .world_motion import (
    WorldMotionTracker,
    _artifact,
    _box_arrays,
    _canonical,
    _percentiles,
    _read_jsonl,
    _read_object,
    _rewrite_npz_boxes,
    _robust_motion,
    _sha256,
    _write_jsonl,
    read_world_motion_profile,
)

PROFILE_SCHEMA = "missioncore.e25-persistent-support-profile/v1"
BENCHMARK_SCHEMA = "missioncore.e25-motion-benchmark/v1"
PIPELINE_ID = "map-frame-persistent-support-dual-hypothesis/v1"

FloatArray = npt.NDArray[np.float64]
IntArray = npt.NDArray[np.int64]
Cell = tuple[int, int]


@dataclass(frozen=True, slots=True)
class SupportMeasurement:
    source_track_id: int
    label: str
    group: str
    score: float
    points_map: FloatArray
    source_indices: IntArray


@dataclass(slots=True)
class _SupportSnapshot:
    session_seconds: float
    cells: frozenset[Cell]
    center_map: np.ndarray


@dataclass(slots=True)
class _OccupancyTrack:
    track_id: int
    group: str
    aliases: set[int]
    snapshots: deque[_SupportSnapshot] = field(default_factory=deque)
    motion_state: str = "unknown"
    static_evidence: int = 0
    dynamic_evidence: int = 0
    contradictions: int = 0
    overlap_fraction: float | None = None
    speed_mps: float | None = None
    direction_consistency: float = 0.0
    displacement_m: float | None = None
    confidence: float = 0.0
    velocity_map_mps: np.ndarray | None = None
    last_observed_seconds: float = 0.0
    support_observations: int = 0
    current_cells: frozenset[Cell] = frozenset()


@dataclass(frozen=True, slots=True)
class PersistentSupportBuild:
    result_root: Path
    profile_sha256: str
    benchmark_sha256: str
    report: dict[str, Any]


class PersistentSupportTracker:
    """Bounded occupancy-evidence state keyed by the E24 world track."""

    def __init__(self, profile: dict[str, Any]) -> None:
        self.profile = profile
        self.tracks: dict[int, _OccupancyTrack] = {}
        self.peak_tracks = 0
        self.created_tracks = 0
        self.support_observations = 0
        self.held_states = 0
        self.published_states: Counter[str] = Counter()

    def observe(
        self,
        *,
        track_id: int,
        source_track_id: int,
        group: str,
        session_seconds: float,
        points_map: FloatArray,
    ) -> dict[str, Any]:
        track = self.tracks.get(track_id)
        if track is None:
            track = _OccupancyTrack(
                track_id=track_id,
                group=group,
                aliases={source_track_id},
                last_observed_seconds=session_seconds,
            )
            self.tracks[track_id] = track
            self.created_tracks += 1
        else:
            track.aliases.add(source_track_id)
        cells = _voxel_cells(
            points_map,
            voxel_size=float(self.profile["occupancy"]["voxel_size_m"]),
            maximum=int(self.profile["occupancy"]["maximum_cells_per_snapshot"]),
        )
        center = np.median(points_map, axis=0).astype(np.float64, copy=False)
        self._classify(track, session_seconds, cells, center)
        track.last_observed_seconds = session_seconds
        track.support_observations += 1
        track.current_cells = cells
        self.support_observations += 1
        self._prune(session_seconds)
        self.peak_tracks = max(self.peak_tracks, len(self.tracks))
        self.published_states[track.motion_state] += 1
        return self._evidence(track, session_seconds, current=True)

    def hold(self, track_id: int, session_seconds: float) -> dict[str, Any] | None:
        track = self.tracks.get(track_id)
        if track is None:
            return None
        age = session_seconds - track.last_observed_seconds
        if age > float(self.profile["occupancy"]["maximum_support_hold_seconds"]):
            return None
        self.held_states += 1
        self.published_states[track.motion_state] += 1
        return self._evidence(track, session_seconds, current=False)

    def snapshot(self) -> dict[str, Any]:
        active = Counter(track.motion_state for track in self.tracks.values())
        return {
            "active_tracks": len(self.tracks),
            "peak_tracks": self.peak_tracks,
            "created_tracks": self.created_tracks,
            "support_observations": self.support_observations,
            "held_states": self.held_states,
            "active_motion_states": dict(active),
            "published_motion_states": dict(self.published_states),
        }

    def _classify(
        self,
        track: _OccupancyTrack,
        now: float,
        cells: frozenset[Cell],
        center: np.ndarray,
    ) -> None:
        config = self.profile["occupancy"]
        minimum_age = _group_value(
            config["reference_minimum_age_seconds"],
            track.group,
        )
        maximum_age = float(config["reference_maximum_age_seconds"])
        reference: set[Cell] = set()
        for snapshot in track.snapshots:
            age = now - snapshot.session_seconds
            if minimum_age <= age <= maximum_age:
                reference.update(snapshot.cells)
        overlap = (
            None
            if not reference
            else _cell_overlap(
                cells,
                reference,
                radius=int(config["neighbor_radius_cells"]),
            )
        )
        track.overlap_fraction = overlap
        track.snapshots.append(
            _SupportSnapshot(
                session_seconds=now,
                cells=cells,
                center_map=center.copy(),
            )
        )
        history_seconds = float(config["history_seconds"])
        while track.snapshots and now - track.snapshots[0].session_seconds > max(
            maximum_age,
            history_seconds,
        ):
            track.snapshots.popleft()
        maximum_snapshots = int(config["maximum_snapshots_per_track"])
        while len(track.snapshots) > maximum_snapshots:
            track.snapshots.popleft()
        history: deque[tuple[float, np.ndarray]] = deque(
            (
                snapshot.session_seconds,
                snapshot.center_map,
            )
            for snapshot in track.snapshots
            if now - snapshot.session_seconds <= history_seconds
        )
        speed, direction = _robust_motion(history)
        track.speed_mps = speed
        track.direction_consistency = direction
        track.displacement_m = (
            None
            if len(history) < 2
            else float(np.linalg.norm(history[-1][1][:2] - history[0][1][:2]))
        )
        track.velocity_map_mps = _median_velocity(history)
        if overlap is None or speed is None or track.displacement_m is None:
            track.motion_state = "unknown"
            track.confidence = 0.0
            return
        dynamic = (
            overlap <= float(config["dynamic_overlap_enter"])
            and speed >= _group_value(config["dynamic_minimum_speed_mps"], track.group)
            and track.displacement_m
            >= _group_value(config["dynamic_minimum_displacement_m"], track.group)
            and direction >= float(config["minimum_direction_consistency"])
        )
        static = overlap >= float(config["static_overlap_enter"])
        track.dynamic_evidence = track.dynamic_evidence + 1 if dynamic else 0
        track.static_evidence = track.static_evidence + 1 if static else 0
        raw_contradiction = not dynamic and not static
        track.contradictions = track.contradictions + 1 if raw_contradiction else 0
        dynamic_frames = int(_group_value(config["dynamic_confirmation_frames"], track.group))
        static_frames = int(config["static_confirmation_frames"])
        if track.dynamic_evidence >= dynamic_frames:
            track.motion_state = "dynamic"
        elif track.static_evidence >= static_frames:
            track.motion_state = "static"
        elif (
            track.motion_state == "dynamic" and overlap >= float(config["dynamic_overlap_exit"])
        ) or (track.motion_state == "static" and overlap < float(config["static_overlap_exit"])):
            track.motion_state = "unknown"
        if track.contradictions >= int(config["contradiction_frames"]):
            track.motion_state = "unknown"
        if track.motion_state == "dynamic":
            overlap_confidence = max(
                0.0,
                1.0 - overlap / max(float(config["dynamic_overlap_exit"]), 1e-6),
            )
            track.confidence = min(
                1.0,
                0.5 * overlap_confidence + 0.5 * direction,
            )
        elif track.motion_state == "static":
            track.confidence = min(
                1.0,
                overlap / max(float(config["static_overlap_enter"]), 1e-6),
            )
        else:
            track.confidence = 0.0

    def _evidence(
        self,
        track: _OccupancyTrack,
        now: float,
        *,
        current: bool,
    ) -> dict[str, Any]:
        voxel_size = float(self.profile["occupancy"]["voxel_size_m"])
        footprint = _footprint(track.current_cells, voxel_size)
        velocity = (
            None
            if track.motion_state == "unknown" or track.velocity_map_mps is None
            else track.velocity_map_mps.tolist()
        )
        if track.motion_state == "static":
            velocity = [0.0, 0.0, 0.0]
        return {
            "motion_state": track.motion_state,
            "motion_confidence": track.confidence,
            "motion_status": ("e25-current-map-support" if current else "e25-held-map-support"),
            "speed_mps": track.speed_mps,
            "velocity_map_mps": velocity,
            "occupancy_overlap_fraction": track.overlap_fraction,
            "occupancy_displacement_m": track.displacement_m,
            "occupancy_direction_consistency": track.direction_consistency,
            "occupancy_support_observations": track.support_observations,
            "occupancy_cell_count": len(track.current_cells),
            "occupancy_resolution_m": voxel_size,
            "occupancy_footprint_map_xy": footprint,
            "occupancy_evidence_current": current,
            "occupancy_observation_age_ms": max(
                0.0,
                (now - track.last_observed_seconds) * 1000.0,
            ),
            "source_track_aliases": sorted(track.aliases),
        }

    def _prune(self, now: float) -> None:
        maximum_idle = float(self.profile["bounds"]["maximum_track_idle_seconds"])
        stale = [
            track_id
            for track_id, track in self.tracks.items()
            if now - track.last_observed_seconds > maximum_idle
        ]
        for track_id in stale:
            self.tracks.pop(track_id, None)
        maximum_tracks = int(self.profile["bounds"]["maximum_tracks"])
        if len(self.tracks) <= maximum_tracks:
            return
        ordered = sorted(
            self.tracks.values(),
            key=lambda track: track.last_observed_seconds,
        )
        for track in ordered[: len(self.tracks) - maximum_tracks]:
            self.tracks.pop(track.track_id, None)


class RecordedSupportExtractor:
    """Rebuild sparse per-object support from immutable recorded inputs."""

    def __init__(
        self,
        *,
        source: IntegratedPerceptionResult,
        lidar_pack: Path,
        association: dict[str, Any],
        profile: dict[str, Any],
    ) -> None:
        self.source = source
        self.association = association
        self.profile = profile
        semantic_rows = _read_jsonl(source.semantic_path)
        with np.load(source.arrays_path, allow_pickle=False) as source_arrays:
            semantic_indices = source_arrays["semantic_frame_indices"]
            self.semantic_masks = source_arrays["semantic_masks"]
        if not np.array_equal(
            semantic_indices,
            np.asarray([row["frame_index"] for row in semantic_rows], dtype=np.int64),
        ):
            raise SessionIntegrityError("LAB E25 semantic frame binding changed")
        self.semantic_by_source = {
            int(row["source_frame_index"]): index for index, row in enumerate(semantic_rows)
        }
        required = {
            "frame_indices",
            "source_frame_indices",
            "session_seconds",
            "sample_available",
            "cloud_offsets",
            "cloud_points_map",
            "pose_positions_map",
            "pose_quaternions_map_from_lidar",
            "lidar_camera_delta_ms",
            "pose_point_delta_ms",
            "intrinsic_fx_fy_cx_cy",
            "distortion_kb4",
            "t_camera_from_lidar",
        }
        with np.load(lidar_pack / "lidar-pack.npz", allow_pickle=False) as lidar_arrays:
            if set(lidar_arrays.files) != required:
                raise SessionIntegrityError("LAB E25 LiDAR replay array set changed")
            if lidar_arrays["frame_indices"].shape != (source.frame_count,):
                raise SessionIntegrityError("LAB E25 LiDAR replay frame count changed")
            self.sample_available = lidar_arrays["sample_available"]
            self.cloud_offsets = lidar_arrays["cloud_offsets"]
            self.cloud_points_map = lidar_arrays["cloud_points_map"]
            self.pose_positions_map = lidar_arrays["pose_positions_map"]
            self.pose_quaternions_map_from_lidar = lidar_arrays["pose_quaternions_map_from_lidar"]
            intrinsic_values = np.asarray(
                lidar_arrays["intrinsic_fx_fy_cx_cy"],
                dtype=np.float64,
            )
            distortion_values = np.asarray(
                lidar_arrays["distortion_kb4"],
                dtype=np.float64,
            )
            t_camera_from_lidar = np.asarray(
                lidar_arrays["t_camera_from_lidar"],
                dtype=np.float64,
            )
        configuration = _read_object(source.result_root / "result.json")["identity"][
            "configuration"
        ]
        source_profile = configuration["profile"]["source"]
        if intrinsic_values.shape != (4,) or distortion_values.shape != (4,):
            raise SessionIntegrityError("LAB E25 calibration vector shape changed")
        intrinsic = (
            float(intrinsic_values[0]),
            float(intrinsic_values[1]),
            float(intrinsic_values[2]),
            float(intrinsic_values[3]),
        )
        distortion = (
            float(distortion_values[0]),
            float(distortion_values[1]),
            float(distortion_values[2]),
            float(distortion_values[3]),
        )
        self.projection = Kb4ProjectionProfile(
            source_id=str(source_profile["source_id"]),
            calibration_slot=str(source_profile["calibration_slot"]),
            width=int(source_profile["resolution"][0]),
            height=int(source_profile["resolution"][1]),
            intrinsic_fx_fy_cx_cy=intrinsic,
            distortion_kb4=distortion,
            t_camera_from_lidar=t_camera_from_lidar,
        )
        self.frames_with_support = 0
        self.measurements = 0
        self.points = 0

    def close(self) -> None:
        return None

    def frame(
        self,
        frame_index: int,
        fusion: dict[str, Any],
    ) -> dict[int, SupportMeasurement]:
        if not bool(self.sample_available[frame_index]):
            return {}
        semantic_source = fusion.get("semantic_source_frame_index")
        if not isinstance(semantic_source, int):
            return {}
        semantic_index = self.semantic_by_source.get(semantic_source)
        if semantic_index is None:
            return {}
        start = int(self.cloud_offsets[frame_index])
        end = int(self.cloud_offsets[frame_index + 1])
        points_map = np.asarray(
            self.cloud_points_map[start:end],
            dtype=np.float64,
        )
        position_values = np.asarray(
            self.pose_positions_map[frame_index],
            dtype=np.float64,
        )
        quaternion_values = np.asarray(
            self.pose_quaternions_map_from_lidar[frame_index],
            dtype=np.float64,
        )
        if position_values.shape != (3,) or quaternion_values.shape != (4,):
            raise SessionIntegrityError("LAB E25 pose vector shape changed")
        position = (
            float(position_values[0]),
            float(position_values[1]),
            float(position_values[2]),
        )
        quaternion = (
            float(quaternion_values[0]),
            float(quaternion_values[1]),
            float(quaternion_values[2]),
            float(quaternion_values[3]),
        )
        projected = project_map_points_kb4(
            points_map,
            position_map_xyz=position,
            orientation_map_from_lidar_xyzw=quaternion,
            profile=self.projection,
        )
        visible = _visible_projection_indices(
            projected.pixels_xy,
            projected.depths_m,
            self.projection.width,
        )
        pixels = projected.pixels_xy[visible]
        depths = projected.depths_m[visible]
        source_indices = projected.source_indices[visible]
        points_lidar = map_points_to_lidar(
            points_map,
            position_map_xyz=position,
            orientation_map_from_lidar_xyzw=quaternion,
        )
        semantic = self.semantic_masks[semantic_index]
        pixel_x = np.clip(
            np.rint(pixels[:, 0]).astype(np.int64),
            0,
            self.projection.width - 1,
        )
        pixel_y = np.clip(
            np.rint(pixels[:, 1]).astype(np.int64),
            0,
            self.projection.height - 1,
        )
        sampled_semantic = semantic[pixel_y, pixel_x]
        candidates: list[SupportMeasurement] = []
        for source_object in fusion["objects"]:
            measurement = self._object_support(
                source_object,
                pixels=pixels,
                depths=depths,
                source_indices=source_indices,
                sampled_semantic=sampled_semantic,
                points_map=points_map,
                points_lidar=points_lidar,
            )
            if measurement is not None:
                candidates.append(measurement)
        selected = _suppress_duplicate_measurements(
            candidates,
            overlap_threshold=float(self.association["support_duplicate_overlap_threshold"]),
        )
        if selected:
            self.frames_with_support += 1
        self.measurements += len(selected)
        self.points += sum(item.points_map.shape[0] for item in selected)
        return {item.source_track_id: item for item in selected}

    def snapshot(self) -> dict[str, int]:
        return {
            "frames_with_support": self.frames_with_support,
            "support_measurements": self.measurements,
            "support_points": self.points,
        }

    def _object_support(
        self,
        source: dict[str, Any],
        *,
        pixels: FloatArray,
        depths: FloatArray,
        source_indices: IntArray,
        sampled_semantic: npt.NDArray[np.uint8],
        points_map: FloatArray,
        points_lidar: FloatArray,
    ) -> SupportMeasurement | None:
        group = str(source.get("association_group", source.get("label", "object")))
        if group not in self.association["semantic_ids"]:
            return None
        x1, y1, x2, y2 = (float(value) for value in source["bbox_xyxy"])
        width, height = x2 - x1, y2 - y1
        inset = self.association["box_inset"]
        inside = (
            (pixels[:, 0] >= x1 + width * float(inset["horizontal_fraction"]))
            & (pixels[:, 0] < x2 - width * float(inset["horizontal_fraction"]))
            & (pixels[:, 1] >= y1 + height * float(inset["top_fraction"]))
            & (pixels[:, 1] < y2 - height * float(inset["bottom_fraction"]))
        )
        candidates = np.flatnonzero(inside).astype(np.int64)
        allowed = np.asarray(
            self.association["semantic_ids"][group],
            dtype=np.uint8,
        )
        compatible = candidates[np.isin(sampled_semantic[candidates], allowed)]
        clustered = _depth_cluster(compatible, depths, self.association)
        selected = _spatial_cluster(
            source_indices[clustered],
            points_lidar,
            float(self.association["spatial_cluster_radius_m"][group]),
        )
        selected = _filter_support_by_ground(
            selected,
            points_map,
            group=group,
            profile=self.association["object_support_ground_filter"],
        )
        minimum = int(
            _group_value(
                self.profile["support"]["minimum_evidence_points"],
                group,
            )
        )
        if selected.size < minimum:
            return None
        maximum_points = int(self.profile["support"]["maximum_points_per_object"])
        if selected.size > maximum_points:
            step = selected.size / maximum_points
            selected = selected[np.floor(np.arange(maximum_points) * step).astype(np.int64)]
        return SupportMeasurement(
            source_track_id=int(source.get("source_track_id", source["track_id"])),
            label=str(source.get("label", "object")),
            group=group,
            score=float(source.get("score", 0.0)),
            points_map=points_map[selected],
            source_indices=selected,
        )


def read_persistent_support_profile(path: Path) -> tuple[dict[str, Any], str]:
    resolved = path.expanduser().resolve(strict=True)
    profile = _read_object(resolved)
    occupancy = profile.get("occupancy")
    if (
        profile.get("schema_version") != PROFILE_SCHEMA
        or profile.get("mode") != "recorded-streaming-qualification"
        or profile.get("authority")
        != {"commands_enabled": False, "navigation_or_safety_accepted": False}
        or not isinstance(occupancy, dict)
        or not 0.05 <= float(occupancy.get("voxel_size_m", 0.0)) <= 1.0
        or not 1 <= int(profile.get("bounds", {}).get("maximum_tracks", 0)) <= 512
        or float(occupancy.get("dynamic_overlap_enter", 1.0))
        >= float(occupancy.get("static_overlap_enter", 0.0))
    ):
        raise SessionIntegrityError("LAB E25 persistent-support profile is invalid")
    return profile, _sha256(resolved)


def read_persistent_support_benchmark(
    path: Path,
) -> tuple[dict[str, Any], str]:
    resolved = path.expanduser().resolve(strict=True)
    benchmark = _read_object(resolved)
    events = benchmark.get("events")
    if (
        benchmark.get("schema_version") != BENCHMARK_SCHEMA
        or benchmark.get("source_session_id") != "20260720T065719Z_viewer_live"
        or not isinstance(events, list)
        or not events
    ):
        raise SessionIntegrityError("LAB E25 motion benchmark is invalid")
    identifiers: set[str] = set()
    for event in events:
        if (
            not isinstance(event, dict)
            or not isinstance(event.get("id"), str)
            or event["id"] in identifiers
            or event.get("kind") not in {"target-motion", "static-control"}
            or event.get("expected_motion") not in {"static", "dynamic"}
            or event.get("class_group")
            not in {"person", "vehicle", "bicycle", "vulnerable_road_user"}
            or not isinstance(event.get("window_seconds"), list)
            or len(event["window_seconds"]) != 2
            or float(event["window_seconds"][0]) >= float(event["window_seconds"][1])
        ):
            raise SessionIntegrityError("LAB E25 benchmark event is invalid")
        if event["kind"] == "target-motion":
            targets = event.get("target_source_track_ids")
            if (
                not isinstance(targets, list)
                or not targets
                or not all(isinstance(value, int) and value > 0 for value in targets)
            ):
                raise SessionIntegrityError("LAB E25 target binding is invalid")
        identifiers.add(event["id"])
    return benchmark, _sha256(resolved)


def evaluate_persistent_support_benchmark(
    source_rows: list[dict[str, Any]],
    fusion_rows: list[dict[str, Any]],
    benchmark: dict[str, Any],
) -> dict[str, Any]:
    outcomes: list[dict[str, Any]] = []
    for event in benchmark["events"]:
        start, end = (float(value) for value in event["window_seconds"])
        targets = set(int(value) for value in event.get("target_source_track_ids", []))
        source_keys: set[tuple[int, int]] = set()
        for row in source_rows:
            timestamp = float(row["session_seconds"])
            if not start <= timestamp <= end:
                continue
            for item in row["objects"]:
                source_id = int(item.get("source_track_id", item["track_id"]))
                if _event_class_matches(item, event) and (
                    event["kind"] == "static-control" or source_id in targets
                ):
                    source_keys.add((_benchmark_frame_key(row, timestamp), source_id))
        source_observations = len(source_keys)
        evidence_by_key: dict[
            tuple[int, int],
            tuple[float, dict[str, Any]],
        ] = {}
        duplicate_evidence_observations = 0
        for row in fusion_rows:
            timestamp = float(row["session_seconds"])
            if not start <= timestamp <= end:
                continue
            for item in row["objects"]:
                source_id = item.get("source_track_id")
                if (
                    isinstance(source_id, int)
                    and _event_class_matches(item, event)
                    and (event["kind"] == "static-control" or source_id in targets)
                    and item.get("occupancy_evidence_current") is True
                ):
                    key = (_benchmark_frame_key(row, timestamp), source_id)
                    previous = evidence_by_key.get(key)
                    if previous is not None:
                        duplicate_evidence_observations += 1
                    if previous is None or _benchmark_evidence_rank(
                        item
                    ) > _benchmark_evidence_rank(previous[1]):
                        evidence_by_key[key] = (timestamp, item)
        matched = sorted(evidence_by_key.values(), key=lambda value: value[0])
        coverage = len(matched) / max(1, source_observations)
        if event["kind"] == "static-control":
            state_counts = Counter(str(item["motion_state"]) for _, item in matched)
            classified = state_counts["static"] + state_counts["dynamic"]
            classified_fraction = classified / max(1, len(matched))
            false_dynamic_fraction = state_counts["dynamic"] / max(1, len(matched))
            passed = (
                source_observations >= int(event["minimum_source_observations"])
                and coverage >= float(event["minimum_coverage_fraction"])
                and classified_fraction >= float(event["minimum_classified_fraction"])
                and false_dynamic_fraction <= float(event["maximum_false_dynamic_fraction"])
            )
            outcomes.append(
                {
                    "id": event["id"],
                    "kind": event["kind"],
                    "expected_motion": event["expected_motion"],
                    "class_group": event["class_group"],
                    "window_seconds": [start, end],
                    "passed": passed,
                    "source_observations": source_observations,
                    "evidence_observations": len(matched),
                    "duplicate_evidence_observations": (duplicate_evidence_observations),
                    "coverage_fraction": coverage,
                    "classified_fraction": classified_fraction,
                    "false_dynamic_fraction": false_dynamic_fraction,
                    "state_counts": dict(state_counts),
                }
            )
            continue
        by_track: dict[int, list[tuple[float, dict[str, Any]]]] = defaultdict(list)
        for timestamp, item in matched:
            if item.get("motion_state") == event["expected_motion"]:
                by_track[int(item["track_id"])].append((timestamp, item))
        best_track: int | None = None
        best_hits = 0
        best_span = 0.0
        for track_id, observations in by_track.items():
            timestamps = [value[0] for value in observations]
            span = max(timestamps) - min(timestamps)
            if (len(observations), span) > (best_hits, best_span):
                best_track = track_id
                best_hits = len(observations)
                best_span = span
        passed = (
            coverage >= float(event["minimum_coverage_fraction"])
            and best_hits >= int(event["minimum_hits"])
            and best_span >= float(event["minimum_span_seconds"])
        )
        outcomes.append(
            {
                "id": event["id"],
                "kind": event["kind"],
                "expected_motion": event["expected_motion"],
                "class_group": event["class_group"],
                "target_source_track_ids": sorted(targets),
                "window_seconds": [start, end],
                "passed": passed,
                "source_observations": source_observations,
                "evidence_observations": len(matched),
                "duplicate_evidence_observations": duplicate_evidence_observations,
                "coverage_fraction": coverage,
                "best_track_id": best_track,
                "best_hits": best_hits,
                "best_span_seconds": best_span,
            }
        )
    return {
        "schema_version": "missioncore.e25-motion-benchmark-result/v1",
        "passed": all(item["passed"] for item in outcomes),
        "passed_events": sum(item["passed"] for item in outcomes),
        "total_events": len(outcomes),
        "events": outcomes,
    }


def build_persistent_support_result(
    *,
    source: IntegratedPerceptionResult,
    lab_job: CameraComputeJob,
    lab_pack: Path,
    results_root: Path,
    world_motion_profile_path: Path,
    profile_path: Path,
    benchmark_path: Path,
) -> PersistentSupportBuild:
    """Build one immutable E25 result from the accepted E19 source."""

    if not source.accepted:
        raise SessionIntegrityError("LAB E25 source result is not accepted")
    world_profile, world_profile_sha256 = read_world_motion_profile(world_motion_profile_path)
    profile, profile_sha256 = read_persistent_support_profile(profile_path)
    benchmark, benchmark_sha256 = read_persistent_support_benchmark(benchmark_path)
    if source.job.session_id != benchmark["source_session_id"]:
        raise SessionIntegrityError("LAB E25 benchmark source session differs")
    source_document = _read_object(source.result_root / "result.json")
    source_report = _read_object(source.report_path)
    source_fusion = _read_jsonl(source.fusion_path)
    source_world = _read_jsonl(source.world_path)
    if len(source_fusion) != source.frame_count or len(source_world) != source.frame_count:
        raise SessionIntegrityError("LAB E25 source timelines are incomplete")
    configuration = source_document["identity"].get("configuration")
    association = (
        configuration.get("profile", {}).get("association")
        if isinstance(configuration, dict)
        else None
    )
    if not isinstance(association, dict):
        raise SessionIntegrityError("LAB E25 source association profile is unavailable")

    world_tracker = WorldMotionTracker(world_profile)
    occupancy_tracker = PersistentSupportTracker(profile)
    extractor = RecordedSupportExtractor(
        source=source,
        lidar_pack=lab_pack,
        association=association,
        profile=profile,
    )
    fusion_rows: list[dict[str, Any]] = []
    world_rows: list[dict[str, Any]] = []
    frame_ms: list[float] = []
    support_offsets = [0]
    support_points: list[np.ndarray] = []
    support_colors: list[np.ndarray] = []
    try:
        for index, (source_fusion_row, source_world_row) in enumerate(
            zip(source_fusion, source_world, strict=True)
        ):
            started = time.perf_counter()
            measurements = extractor.frame(index, source_fusion_row)
            augmented = [
                _augment_source_object(item, measurements) for item in source_fusion_row["objects"]
            ]
            session_seconds = float(source_fusion_row["session_seconds"])
            fusion_objects, world_objects = world_tracker.update(
                frame_index=int(source_fusion_row["frame_index"]),
                session_seconds=session_seconds,
                objects=augmented,
            )
            normalized_objects = _apply_occupancy_evidence(
                fusion_objects,
                measurements,
                occupancy_tracker,
                session_seconds,
            )
            normalized_fusion = json.loads(json.dumps(source_fusion_row))
            normalized_fusion["objects"] = normalized_objects
            normalized_fusion["world_motion"] = {
                "schema_version": "missioncore.e25-persistent-support-frame/v1",
                "coordinate_frame": "k1-map",
                "lookahead_frames": 0,
                "measurement": "persistent-object-support-occupancy",
            }
            normalized_world = json.loads(json.dumps(source_world_row))
            normalized_world["objects"] = _update_world_objects(
                world_objects,
                normalized_objects,
            )
            normalized_world["object_count"] = len(normalized_world["objects"])
            delivery = normalized_world.setdefault("delivery", {})
            delivery["world_motion"] = "e25-persistent-support-dual-hypothesis"
            elapsed = (time.perf_counter() - started) * 1000.0
            delivery["world_motion_processing_ms"] = elapsed
            fusion_rows.append(normalized_fusion)
            world_rows.append(normalized_world)
            frame_ms.append(elapsed)
            frame_points, frame_colors = _support_arrays(measurements)
            if frame_points.size:
                support_points.append(frame_points)
                support_colors.append(frame_colors)
            support_offsets.append(support_offsets[-1] + frame_points.shape[0])
    finally:
        extractor.close()

    benchmark_result = evaluate_persistent_support_benchmark(
        source_fusion,
        fusion_rows,
        benchmark,
    )
    runtime = _percentiles(frame_ms)
    tracker_metrics = occupancy_tracker.snapshot()
    checks = {
        "source_payloads_immutable": True,
        "diagnostic_authority_only": True,
        "single_pass_no_lookahead": True,
        "track_state_bound": tracker_metrics["peak_tracks"]
        <= int(profile["acceptance"]["maximum_tracks_observed"]),
        "processing_p95_ms": runtime["p95"]
        <= float(profile["acceptance"]["maximum_processing_p95_ms"]),
    }
    accepted = all(checks.values())
    source_identity = source_document["identity"]
    result_configuration = {
        "pipeline": PIPELINE_ID,
        "world_motion_profile_sha256": world_profile_sha256,
        "world_motion_profile": world_profile,
        "profile_sha256": profile_sha256,
        "profile": profile,
        "implementation_sha256": _sha256(Path(__file__).resolve()),
        "benchmark_sha256": benchmark_sha256,
        "benchmark": benchmark,
        "source_result_id": source.result_id,
        "source_result_sha256": _sha256(source.result_root / "result.json"),
        "source_session_id": source.job.session_id,
        "processing": "single-pass-bounded-state-no-lookahead",
    }
    identity = {
        "schema_version": "missioncore.e10-integrated-perception-identity/v1",
        "job_id": lab_job.job_id,
        "input_sha256": lab_job.input_sha256,
        "session_id": lab_job.session_id,
        "source_id": lab_job.source_id,
        "lidar_pack_id": lab_pack.name,
        "selection": json.loads(json.dumps(source_identity["selection"])),
        "configuration": result_configuration,
        "models": source_identity["models"],
    }
    identity_sha256 = hashlib.sha256(_canonical(identity)).hexdigest()
    result_id = f"e10-integrated-perception-{identity_sha256}"
    destination = results_root / result_id
    created_at = (
        datetime.now(UTC)
        .isoformat(timespec="milliseconds")
        .replace(
            "+00:00",
            "Z",
        )
    )
    report = {
        "schema_version": "missioncore.e10-integrated-perception-report/v1",
        "result_id": result_id,
        "created_at_utc": created_at,
        "state": "accepted" if accepted else "rejected",
        "ground_truth": False,
        "identity": identity,
        "acceptance": {
            "accepted": accepted,
            "navigation_or_safety_accepted": False,
            "checks": checks,
        },
        "metrics": {
            "runtime": {
                "persistent_support_frame_processing_ms": runtime,
                **tracker_metrics,
                **extractor.snapshot(),
            },
            "benchmark": benchmark_result,
            "source_realtime_envelope": source_report.get("metrics", {}),
        },
        "runtime": {
            "executor": "local-deterministic-postprocessor",
            "numpy": np.__version__,
            "streaming_equivalent": True,
            "lookahead_frames": 0,
        },
        "limitations": [
            "Recorded diagnostic qualification only; no navigation or command authority.",
            (
                "Operator timestamps and detector-track bindings are reviewed annotations, "
                "not ground truth."
            ),
            (
                "Unknown remains an occupied obstacle and is intentional when motion "
                "evidence is insufficient."
            ),
            (
                "Motion uses persistent map-frame support overlap; the completed cuboid "
                "center is not the sole measurement."
            ),
            "Raw LiDAR, ground returns, camera media, calibration and model outputs are unchanged.",
        ],
    }
    if destination.exists():
        existing = _read_object(destination / "result.json")
        if existing.get("identity") != identity:
            raise SessionIntegrityError("LAB E25 result id collides")
        return PersistentSupportBuild(
            destination,
            profile_sha256,
            benchmark_sha256,
            _read_object(destination / "run-report.json"),
        )

    results_root.mkdir(mode=0o700, parents=True, exist_ok=True)
    staging = results_root / f".{result_id}.{secrets.token_hex(12)}.tmp"
    staging.mkdir(mode=0o700)
    try:
        semantic_path = staging / "semantic-frames.jsonl"
        fusion_path = staging / "fusion-frames.jsonl"
        world_path = staging / "world-state.jsonl"
        arrays_path = staging / "transient-perception.npz"
        gpu_path = staging / "gpu-telemetry.jsonl"
        report_path = staging / "run-report.json"
        os.link(source.semantic_path, semantic_path, follow_symlinks=False)
        _write_jsonl(fusion_path, fusion_rows)
        _write_jsonl(world_path, world_rows)
        box_offsets, centers, half_sizes, quaternions, box_colors = _box_arrays(fusion_rows)
        all_support = (
            np.concatenate(support_points).astype(np.float32, copy=False)
            if support_points
            else np.empty((0, 3), dtype=np.float32)
        )
        all_support_colors = (
            np.concatenate(support_colors).astype(np.uint8, copy=False)
            if support_colors
            else np.empty((0, 3), dtype=np.uint8)
        )
        _rewrite_npz_boxes(
            source.arrays_path,
            arrays_path,
            {
                "support_offsets": np.asarray(support_offsets, dtype=np.int64),
                "support_points": all_support,
                "support_colors": all_support_colors,
                "box_offsets": box_offsets,
                "box_centers": centers,
                "box_half_sizes": half_sizes,
                "box_quaternions": quaternions,
                "box_colors": box_colors,
            },
        )
        os.link(
            source.result_root / "gpu-telemetry.jsonl",
            gpu_path,
            follow_symlinks=False,
        )
        write_json_atomic(report_path, report)
        artifacts = [
            _artifact(
                "e10-semantic-frames",
                semantic_path,
                "missioncore.e10-semantic-frame/v1",
            ),
            _artifact(
                "e10-fusion-frames",
                fusion_path,
                "missioncore.e10-fusion-frame/v1",
            ),
            _artifact(
                "e10-world-state",
                world_path,
                "missioncore.live-perception-world-state/v1",
            ),
            _artifact("e10-transient-perception", arrays_path, None),
            _artifact("worker-gpu-telemetry", gpu_path, None),
            _artifact(
                "e10-run-report",
                report_path,
                "missioncore.e10-integrated-perception-report/v1",
            ),
        ]
        write_json_atomic(
            staging / "result.json",
            {
                "schema_version": "missioncore.e10-integrated-perception-result/v1",
                "result_id": result_id,
                "identity_sha256": identity_sha256,
                "identity": identity,
                "created_at_utc": created_at,
                "ground_truth": False,
                "publication_scope": "recorded-integrated-realtime-qualification-only",
                "acceptance_state": "accepted" if accepted else "rejected",
                "frames_processed": source.frame_count,
                "artifacts": artifacts,
            },
        )
        os.replace(staging, destination)
    finally:
        if staging.exists():
            shutil.rmtree(staging)
    return PersistentSupportBuild(
        destination,
        profile_sha256,
        benchmark_sha256,
        report,
    )


def _augment_source_object(
    source: dict[str, Any],
    measurements: dict[int, SupportMeasurement],
) -> dict[str, Any]:
    normalized: dict[str, Any] = json.loads(json.dumps(source))
    source_track_id = int(source.get("source_track_id", source["track_id"]))
    measurement = measurements.get(source_track_id)
    if measurement is None:
        return normalized
    normalized["e25_source_clustered_points"] = normalized.get("clustered_points", 0)
    normalized["clustered_points"] = int(measurement.points_map.shape[0])
    if not _valid_vector(normalized.get("observed_cuboid_center_map"), 3):
        normalized["observed_cuboid_center_map"] = np.median(
            measurement.points_map,
            axis=0,
        ).tolist()
        normalized["observed_cuboid_quaternion_xyzw"] = [0.0, 0.0, 0.0, 1.0]
        normalized["e25_support_recovered"] = True
    return normalized


def _apply_occupancy_evidence(
    objects: list[dict[str, Any]],
    measurements: dict[int, SupportMeasurement],
    tracker: PersistentSupportTracker,
    session_seconds: float,
) -> list[dict[str, Any]]:
    result: list[dict[str, Any]] = []
    for source in objects:
        item = json.loads(json.dumps(source))
        source_track_id = item.get("source_track_id")
        track_id = item.get("track_id")
        evidence: dict[str, Any] | None = None
        if isinstance(source_track_id, int) and isinstance(track_id, int):
            measurement = measurements.get(source_track_id)
            if measurement is not None and item.get("temporal_status") == "e24-observed":
                evidence = tracker.observe(
                    track_id=track_id,
                    source_track_id=source_track_id,
                    group=measurement.group,
                    session_seconds=session_seconds,
                    points_map=measurement.points_map,
                )
            else:
                evidence = tracker.hold(track_id, session_seconds)
        if evidence is None:
            item["motion_state"] = "unknown"
            item["motion_confidence"] = 0.0
            item["motion_status"] = "e25-unavailable-no-persistent-support"
            item["occupancy_evidence_current"] = False
        else:
            item.update(evidence)
            item["temporal_status"] = (
                "e25-support-observed"
                if evidence["occupancy_evidence_current"]
                else "e25-support-held"
            )
        result.append(item)
    return result


def _update_world_objects(
    world_objects: list[dict[str, Any]],
    fusion_objects: list[dict[str, Any]],
) -> list[dict[str, Any]]:
    by_track = {
        int(item["track_id"]): item
        for item in fusion_objects
        if isinstance(item.get("track_id"), int) and isinstance(item.get("source_track_id"), int)
    }
    result: list[dict[str, Any]] = []
    for source in world_objects:
        item = json.loads(json.dumps(source))
        fusion = by_track.get(int(item["track_id"]))
        if fusion is None:
            item["motion_state"] = "unknown"
            item["motion_confidence"] = 0.0
            item["velocity_status"] = "e25-unavailable-no-persistent-support"
            result.append(item)
            continue
        for key in (
            "motion_state",
            "motion_confidence",
            "speed_mps",
            "velocity_map_mps",
            "occupancy_overlap_fraction",
            "occupancy_displacement_m",
            "occupancy_direction_consistency",
            "occupancy_support_observations",
            "occupancy_cell_count",
            "occupancy_resolution_m",
            "occupancy_footprint_map_xy",
            "occupancy_evidence_current",
            "occupancy_observation_age_ms",
            "source_track_aliases",
        ):
            item[key] = fusion.get(key)
        item["velocity_status"] = fusion["motion_status"]
        item["temporal_status"] = fusion["temporal_status"]
        result.append(item)
    return result


def _support_arrays(
    measurements: dict[int, SupportMeasurement],
) -> tuple[np.ndarray, np.ndarray]:
    points: list[np.ndarray] = []
    colors: list[np.ndarray] = []
    for source_track_id, measurement in sorted(measurements.items()):
        values = measurement.points_map.astype(np.float32, copy=False)
        seed = hashlib.sha256(f"e25:{measurement.group}:{source_track_id}".encode()).digest()
        color = np.asarray(
            [[64 + value % 176 for value in seed[:3]]],
            dtype=np.uint8,
        )
        points.append(values)
        colors.append(np.tile(color, (values.shape[0], 1)))
    if not points:
        return (
            np.empty((0, 3), dtype=np.float32),
            np.empty((0, 3), dtype=np.uint8),
        )
    return np.concatenate(points), np.concatenate(colors)


def _event_class_matches(
    item: dict[str, Any],
    event: dict[str, Any],
) -> bool:
    group = str(
        item.get(
            "association_group",
            item.get("class", item.get("label", "object")),
        )
    )
    if event["class_group"] == "vulnerable_road_user":
        return group in {"person", "bicycle", "motorcycle"}
    return group == str(event["class_group"])


def _benchmark_frame_key(row: dict[str, Any], timestamp: float) -> int:
    frame_index = row.get("frame_index")
    if isinstance(frame_index, int):
        return frame_index
    return round(timestamp * 1_000_000)


def _benchmark_evidence_rank(item: dict[str, Any]) -> tuple[int, int, float, int]:
    return (
        int(item.get("occupancy_cell_count", 0)),
        int(item.get("occupancy_support_observations", 0)),
        float(item.get("motion_confidence", 0.0)),
        -int(item.get("track_id", 0)),
    )


def _visible_projection_indices(
    pixels: FloatArray,
    depths: FloatArray,
    width: int,
) -> IntArray:
    if depths.size == 0:
        return np.empty((0,), dtype=np.int64)
    px = np.rint(pixels[:, 0]).astype(np.int64)
    py = np.rint(pixels[:, 1]).astype(np.int64)
    keys = py * width + px
    order = np.lexsort((depths, keys))
    ordered_keys = keys[order]
    first = np.concatenate(([True], ordered_keys[1:] != ordered_keys[:-1]))
    return np.sort(order[first]).astype(np.int64, copy=False)


def _depth_cluster(
    indices: IntArray,
    depths: FloatArray,
    profile: Mapping[str, Any],
) -> IntArray:
    if indices.size < 2:
        return indices
    ordered = indices[np.argsort(depths[indices])]
    groups: list[IntArray] = []
    start = 0
    for offset, gap in enumerate(np.diff(depths[ordered]), start=1):
        threshold = max(
            float(profile["depth_cluster_minimum_gap_m"]),
            float(profile["depth_cluster_gap_fraction"]) * float(depths[ordered[offset - 1]]),
        )
        if float(gap) > threshold:
            groups.append(ordered[start:offset])
            start = offset
    groups.append(ordered[start:])
    return min(
        groups,
        key=lambda group: (-int(group.size), float(np.median(depths[group]))),
    )


def _spatial_cluster(
    indices: IntArray,
    points_lidar: FloatArray,
    radius: float,
) -> IntArray:
    if indices.size < 2:
        return indices
    points = points_lidar[indices]
    adjacent = np.sum((points[:, None, :] - points[None, :, :]) ** 2, axis=2) <= radius * radius
    unseen = set(range(indices.size))
    groups: list[list[int]] = []
    while unseen:
        seed = unseen.pop()
        group = [seed]
        pending = [seed]
        while pending:
            current = pending.pop()
            for neighbor in [value for value in tuple(unseen) if adjacent[current, value]]:
                unseen.remove(neighbor)
                pending.append(neighbor)
                group.append(neighbor)
        groups.append(group)
    selected = min(
        groups,
        key=lambda group: (
            -len(group),
            float(np.median(np.linalg.norm(points[group], axis=1))),
        ),
    )
    return indices[np.asarray(selected, dtype=np.int64)]


def _filter_support_by_ground(
    indices: IntArray,
    points_map: FloatArray,
    *,
    group: str,
    profile: Mapping[str, Any],
) -> IntArray:
    if indices.size == 0:
        return indices
    support = points_map[indices]
    support_lower = float(np.percentile(support[:, 2], 5.0))
    center = np.median(support[:, :2], axis=0)
    distances = np.linalg.norm(points_map[:, :2] - center, axis=1)
    candidates = points_map[distances <= float(profile["local_radius_m"]), 2]
    ground = (
        float(np.percentile(candidates, float(profile["lower_percentile"])))
        if candidates.size
        else math.nan
    )
    if (
        not math.isfinite(ground)
        or ground < support_lower - float(profile["maximum_below_support_m"])
        or ground > support_lower + float(profile["maximum_above_support_m"])
    ):
        ground = support_lower - float(profile["fallback_below_support_m"])
    minimum = ground + float(profile["minimum_height_above_ground_m"][group])
    maximum_height = ground + float(profile["maximum_height_above_ground_m"][group])
    keep = (support[:, 2] >= minimum) & (support[:, 2] <= maximum_height)
    return indices[keep]


def _suppress_duplicate_measurements(
    measurements: Sequence[SupportMeasurement],
    *,
    overlap_threshold: float,
) -> list[SupportMeasurement]:
    accepted: list[SupportMeasurement] = []
    for item in sorted(
        measurements,
        key=lambda value: (-value.score, value.source_track_id),
    ):
        if any(
            other.group == item.group
            and _index_overlap(other.source_indices, item.source_indices) >= overlap_threshold
            for other in accepted
        ):
            continue
        accepted.append(item)
    return accepted


def _index_overlap(one: IntArray, two: IntArray) -> float:
    if one.size == 0 or two.size == 0:
        return 0.0
    shared = np.intersect1d(one, two, assume_unique=False).size
    return float(shared / min(one.size, two.size))


def _voxel_cells(
    points: FloatArray,
    *,
    voxel_size: float,
    maximum: int,
) -> frozenset[Cell]:
    values = sorted(
        {
            (int(value[0]), int(value[1]))
            for value in np.floor(points[:, :2] / voxel_size).astype(np.int64)
        }
    )
    if len(values) > maximum:
        step = len(values) / maximum
        values = [values[math.floor(index * step)] for index in range(maximum)]
    return frozenset(values)


def _cell_overlap(
    current: frozenset[Cell],
    reference: set[Cell],
    *,
    radius: int,
) -> float:
    if not current or not reference:
        return 0.0
    expanded = {
        (x + delta_x, y + delta_y)
        for x, y in reference
        for delta_x in range(-radius, radius + 1)
        for delta_y in range(-radius, radius + 1)
    }
    return sum(cell in expanded for cell in current) / len(current)


def _footprint(
    cells: frozenset[Cell],
    voxel_size: float,
) -> list[list[float]] | None:
    if not cells:
        return None
    x_values = [value[0] for value in cells]
    y_values = [value[1] for value in cells]
    minimum_x = min(x_values) * voxel_size
    minimum_y = min(y_values) * voxel_size
    maximum_x = (max(x_values) + 1) * voxel_size
    maximum_y = (max(y_values) + 1) * voxel_size
    return [
        [minimum_x, minimum_y],
        [maximum_x, minimum_y],
        [maximum_x, maximum_y],
        [minimum_x, maximum_y],
    ]


def _median_velocity(
    history: deque[tuple[float, np.ndarray]],
) -> np.ndarray | None:
    if len(history) < 3:
        return None
    values = list(history)
    velocities: list[np.ndarray] = []
    for start in range(len(values) - 1):
        for end in range(start + 1, len(values)):
            delta = values[end][0] - values[start][0]
            if delta < 0.35:
                continue
            velocities.append((values[end][1] - values[start][1]) / delta)
    if not velocities:
        return None
    return np.asarray(
        np.median(np.stack(velocities), axis=0),
        dtype=np.float64,
    )


def _group_value(values: Mapping[str, Any], group: str) -> float:
    return float(values.get(group, values["default"]))


def _valid_vector(value: Any, length: int) -> bool:
    return (
        isinstance(value, list)
        and len(value) == length
        and all(
            isinstance(item, int | float)
            and not isinstance(item, bool)
            and math.isfinite(float(item))
            for item in value
        )
    )
