#!/usr/bin/env python3
"""Qualify a bounded replay-as-live world-state loop on immutable LAB E6 data."""

from __future__ import annotations

import argparse
import hashlib
import importlib.util
import json
import math
import os
import re
import resource
import shutil
import sys
import threading
import time
from collections import Counter
from collections.abc import Mapping, Sequence
from dataclasses import dataclass
from datetime import UTC, datetime
from pathlib import Path
from types import ModuleType
from typing import Any

import numpy as np
import numpy.typing as npt
import rerun as rr
from rerun.components import FillMode

import k1link.compute.live_perception as live_perception_module
import k1link.compute.live_replay_qualification as live_validator_module
from k1link.compute import (
    TELEMETRY_SCHEMA,
    LatestWinsQueue,
    WorldStateProjector,
    classify_health,
    validate_live_replay_qualification_result,
    validate_tracked_fusion_qualification_result,
)
from k1link.device_plugins.xgrids_k1.analyze.calibrated_projection import (
    map_points_to_lidar,
)
from k1link.device_plugins.xgrids_k1.mqtt.capture import read_capture_clock_origin

PROFILE_SCHEMA = "missioncore.e7-replay-realtime-profile/v1"
RESULT_SCHEMA = "missioncore.e7-live-replay-result/v1"
IDENTITY_SCHEMA = "missioncore.e7-live-replay-identity/v1"
REPORT_SCHEMA = "missioncore.e7-live-replay-run-report/v1"
PIPELINE_ID = "bounded-latest-wins-e6-world-state-replay/v1"
_EXECUTION_ID = re.compile(r"^[a-z0-9][a-z0-9._-]{2,95}$")


@dataclass(frozen=True, slots=True)
class ReplayFrame:
    ordinal: int
    frame: dict[str, Any]
    cloud_map: npt.NDArray[np.float32]
    position_map_xyz: tuple[float, float, float] | None
    orientation_map_from_lidar_xyzw: tuple[float, float, float, float] | None


@dataclass(frozen=True, slots=True)
class QueueEnvelope:
    replay_frame: ReplayFrame
    scheduled_monotonic: float
    enqueued_monotonic: float
    producer_lag_ms: float


def _arguments() -> argparse.Namespace:
    parser = argparse.ArgumentParser()
    parser.add_argument("--job", type=Path, required=True)
    parser.add_argument("--tracking", type=Path, required=True)
    parser.add_argument("--semantic", type=Path, required=True)
    parser.add_argument("--e6-result", type=Path, required=True)
    parser.add_argument("--session", type=Path, required=True)
    parser.add_argument("--profile", type=Path, required=True)
    parser.add_argument("--output-root", type=Path, required=True)
    parser.add_argument("--execution-id", required=True)
    return parser.parse_args()


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:
    digest = hashlib.sha256()
    with path.open("rb") as stream:
        while chunk := stream.read(1024 * 1024):
            digest.update(chunk)
    return digest.hexdigest()


def _read_profile(path: Path) -> tuple[dict[str, Any], str]:
    resolved = path.resolve(strict=True)
    profile = json.loads(resolved.read_text(encoding="utf-8"))
    if not isinstance(profile, dict) or profile.get("schema_version") != PROFILE_SCHEMA:
        raise RuntimeError("LAB E7 profile schema changed")
    selection = profile.get("selection")
    replay = profile.get("replay")
    health = profile.get("health")
    world = profile.get("world_state")
    presentation = profile.get("presentation")
    acceptance = profile.get("acceptance")
    if not all(
        isinstance(value, dict)
        for value in (selection, replay, health, world, presentation, acceptance)
    ):
        raise RuntimeError("LAB E7 profile sections are invalid")
    mode = profile.get("mode")
    if mode not in {"pilot", "qualification", "overload-negative-control"}:
        raise RuntimeError("LAB E7 mode is invalid")
    start = selection.get("start_frame_index")
    count = selection.get("frame_count")
    capacity = replay.get("queue_capacity")
    speed = replay.get("speed")
    delay = replay.get("consumer_delay_ms")
    stale = health.get("stale_after_ms")
    unavailable = health.get("unavailable_after_ms")
    if (
        not isinstance(start, int)
        or start < 0
        or not isinstance(count, int)
        or count < 2
        or not isinstance(capacity, int)
        or not 1 <= capacity <= 8
        or not isinstance(speed, int | float)
        or not 0.1 <= float(speed) <= 10.0
        or not isinstance(delay, int | float)
        or not 0 <= float(delay) <= 5000
        or not isinstance(stale, int | float)
        or not isinstance(unavailable, int | float)
        or not 0 < float(stale) < float(unavailable)
    ):
        raise RuntimeError("LAB E7 scheduling contract is invalid")
    clearance = world.get("clearance")
    if not isinstance(clearance, dict):
        raise RuntimeError("LAB E7 clearance contract is invalid")
    sectors = clearance.get("sector_count")
    if not isinstance(sectors, int) or not 12 <= sectors <= 360:
        raise RuntimeError("LAB E7 clearance sector count is invalid")
    return profile, _sha256(resolved)


def _load_e6_runner() -> ModuleType:
    path = Path(__file__).with_name("fuse_e6_tracking_lidar.py").resolve(strict=True)
    spec = importlib.util.spec_from_file_location("missioncore_e6_replay_adapter", path)
    if spec is None or spec.loader is None:
        raise RuntimeError("LAB E6 replay adapter cannot be loaded")
    module = importlib.util.module_from_spec(spec)
    sys.modules[spec.name] = module
    spec.loader.exec_module(module)
    return module


def _read_jsonl(path: Path) -> list[dict[str, Any]]:
    rows: list[dict[str, Any]] = []
    with path.open(encoding="utf-8") as stream:
        for line in stream:
            value = json.loads(line)
            if not isinstance(value, dict):
                raise RuntimeError("LAB E7 input JSONL row is invalid")
            rows.append(value)
    return rows


def _artifact_path(artifacts: Sequence[Mapping[str, Any]], kind: str, root: Path) -> Path:
    matches = [item for item in artifacts if item.get("kind") == kind]
    if len(matches) != 1 or not isinstance(matches[0].get("path"), str):
        raise RuntimeError(f"LAB E7 upstream artifact is missing: {kind}")
    return root / str(matches[0]["path"])


def _prepare_frames(
    *,
    e6: Any,
    session: Path,
    selection_start: int,
    selection_count: int,
) -> list[ReplayFrame]:
    if selection_start + selection_count > e6.frame_count:
        raise RuntimeError("LAB E7 selection exceeds the E6 frame range")
    runner = _load_e6_runner()
    frames_path = _artifact_path(
        e6.artifacts,
        "tracked-lidar-frame-metadata",
        e6.result_root,
    )
    frame_rows = _read_jsonl(frames_path)
    arrays_path = _artifact_path(e6.artifacts, "tracked-lidar-arrays", e6.result_root)
    tracking_frames = runner._read_tracking_frames(
        e6.tracking.artifact("tracking-frame-metadata").path,
        e6.tracking.frame_count,
        e6.tracking.source_start_frame_index,
    )
    origin = read_capture_clock_origin(
        session / "captures" / "mqtt_live" / "mqtt.timeline.origin.json"
    )
    epoch_root = (
        e6.job.job_root
        / "input"
        / "camera"
        / e6.job.source_id
        / f"epoch-{e6.job.codec_epoch}"
    )
    anchors = runner._camera_anchors(
        epoch_root / "index.jsonl",
        tracking_frames,
        origin_monotonic_ns=origin.started_monotonic_ns,
    )
    temporal = json.loads(
        (e6.result_root / "run-report.json").read_text(encoding="utf-8")
    )["identity"]["configuration"]["temporal"]
    samples = list(
        runner._lidar_samples(
            session / "captures" / "mqtt_live" / "mqtt.raw.k1mqtt",
            anchors,
            origin_monotonic_ns=origin.started_monotonic_ns,
            maximum_lidar_camera_delta_s=float(
                temporal["maximum_lidar_camera_delta_ms"]
            )
            / 1000.0,
            maximum_pose_point_delta_s=float(temporal["maximum_pose_point_delta_ms"])
            / 1000.0,
        )
    )
    prepared: list[ReplayFrame] = []
    with np.load(arrays_path, allow_pickle=False) as arrays:
        offsets = arrays["cloud_offsets"]
        clouds = arrays["cloud_points"]
        for ordinal in range(selection_start, selection_start + selection_count):
            frame = frame_rows[ordinal]
            sample = samples[ordinal]
            if (frame["state"] == "fused") != (sample is not None):
                raise RuntimeError("LAB E7 pose binding changed from the accepted E6 result")
            start = int(offsets[ordinal])
            end = int(offsets[ordinal + 1])
            prepared.append(
                ReplayFrame(
                    ordinal=ordinal,
                    frame=frame,
                    cloud_map=np.asarray(clouds[start:end], dtype=np.float32).copy(),
                    position_map_xyz=(
                        None
                        if sample is None
                        else tuple(float(value) for value in sample.pose_frame.position_xyz)
                    ),
                    orientation_map_from_lidar_xyzw=(
                        None
                        if sample is None
                        else tuple(
                            float(value)
                            for value in sample.pose_frame.orientation_xyzw
                        )
                    ),
                )
            )
    return prepared


def _transform_to_lidar(
    points_map: npt.NDArray[np.float32] | npt.NDArray[np.float64],
    frame: ReplayFrame,
) -> npt.NDArray[np.float64]:
    if frame.position_map_xyz is None or frame.orientation_map_from_lidar_xyzw is None:
        return np.empty((0, 3), dtype=np.float64)
    return map_points_to_lidar(
        np.asarray(points_map, dtype=np.float64),
        position_map_xyz=frame.position_map_xyz,
        orientation_map_from_lidar_xyzw=frame.orientation_map_from_lidar_xyzw,
    )


def _clearance(
    points_lidar: npt.NDArray[np.float64],
    profile: Mapping[str, Any],
) -> dict[str, Any]:
    sector_count = int(profile["sector_count"])
    empty = {
        "schema": "diagnostic-polar-obstacle-clearance/v1",
        "state": "unavailable",
        "frame": "k1-lidar",
        "front_m": None,
        "observed_sector_fraction": 0.0,
        "sector_ranges_m": [None] * sector_count,
    }
    if points_lidar.size == 0:
        return empty
    finite = np.all(np.isfinite(points_lidar), axis=1)
    points = points_lidar[finite]
    if points.size == 0:
        return empty
    ground_z = float(np.percentile(points[:, 2], float(profile["ground_percentile"])))
    ranges = np.linalg.norm(points[:, :2], axis=1)
    keep = (
        (ranges >= float(profile["minimum_range_m"]))
        & (ranges <= float(profile["maximum_range_m"]))
        & (points[:, 2] >= ground_z + float(profile["minimum_height_above_ground_m"]))
        & (points[:, 2] <= ground_z + float(profile["maximum_height_above_ground_m"]))
    )
    points = points[keep]
    ranges = ranges[keep]
    if points.size == 0:
        return {**empty, "ground_z_estimate_m": ground_z}
    angles = np.arctan2(points[:, 1], points[:, 0])
    indices = np.floor((angles + math.pi) / (2.0 * math.pi) * sector_count).astype(int)
    indices = np.clip(indices, 0, sector_count - 1)
    sector_ranges = np.full(sector_count, np.inf, dtype=np.float64)
    np.minimum.at(sector_ranges, indices, ranges)
    observed = np.isfinite(sector_ranges)
    front_half = math.radians(float(profile["front_half_angle_degrees"]))
    front = ranges[np.abs(angles) <= front_half]
    return {
        "schema": "diagnostic-polar-obstacle-clearance/v1",
        "state": "observed" if np.any(observed) else "unavailable",
        "frame": "k1-lidar",
        "ground_z_estimate_m": ground_z,
        "front_m": None if front.size == 0 else float(np.min(front)),
        "observed_sector_fraction": float(np.mean(observed)),
        "sector_ranges_m": [
            None if not math.isfinite(value) else float(value) for value in sector_ranges
        ],
        "safety_accepted": False,
    }


def _percentile(values: Sequence[float], quantile: float) -> float:
    return float(np.percentile(np.asarray(values, dtype=np.float64), quantile))


def _peak_rss_mib() -> float:
    value = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
    return float(value / (1024 * 1024) if sys.platform == "darwin" else value / 1024)


def _queue_document(queue: LatestWinsQueue[Any]) -> dict[str, Any]:
    snapshot = queue.snapshot()
    return {
        "capacity": snapshot.capacity,
        "depth": snapshot.depth,
        "maximum_depth": snapshot.maximum_depth,
        "published": snapshot.published,
        "consumed": snapshot.consumed,
        "dropped_overflow": snapshot.dropped_overflow,
        "dropped_superseded": snapshot.dropped_superseded,
        "closed": snapshot.closed,
    }


def _artifact(path: Path, kind: str, media_type: str, schema: str | None = None) -> dict[str, Any]:
    value: dict[str, Any] = {
        "kind": kind,
        "path": path.name,
        "media_type": media_type,
        "byte_length": path.stat().st_size,
        "sha256": _sha256(path),
    }
    if schema is not None:
        value["schema_version"] = schema
    return value


def _accepted(profile: Mapping[str, Any], metrics: Mapping[str, Any]) -> tuple[bool, list[str]]:
    acceptance = profile["acceptance"]
    reasons: list[str] = []
    if metrics["queue"]["maximum_depth"] > int(acceptance["maximum_queue_depth"]):
        reasons.append("queue-depth")
    if metrics["process_peak_rss_mib"] > float(acceptance["maximum_process_rss_mib"]):
        reasons.append("process-rss")
    if profile["mode"] == "overload-negative-control":
        if metrics["drop_fraction"] < float(acceptance["minimum_drop_fraction"]):
            reasons.append("negative-control-did-not-overload")
    else:
        if metrics["delivery_rate_hz"] < float(acceptance["minimum_delivery_rate_hz"]):
            reasons.append("delivery-rate")
        if metrics["end_to_end_latency_ms"]["p95"] > float(
            acceptance["maximum_end_to_end_p95_ms"]
        ):
            reasons.append("latency-p95")
        if metrics["drop_fraction"] > float(acceptance["maximum_drop_fraction"]):
            reasons.append("drop-fraction")
    return not reasons, reasons


def main() -> int:
    args = _arguments()
    if _EXECUTION_ID.fullmatch(args.execution_id) is None:
        raise RuntimeError("LAB E7 execution ID is invalid")
    profile, profile_sha256 = _read_profile(args.profile)
    session = args.session.resolve(strict=True)
    preparation_started = time.perf_counter()
    e6 = validate_tracked_fusion_qualification_result(
        args.job,
        args.tracking,
        args.semantic,
        args.e6_result,
    )
    if session.name != e6.job.session_id:
        raise RuntimeError("LAB E7 session does not match the E6 result")
    selection = profile["selection"]
    replay_frames = _prepare_frames(
        e6=e6,
        session=session,
        selection_start=int(selection["start_frame_index"]),
        selection_count=int(selection["frame_count"]),
    )
    preparation_wall = time.perf_counter() - preparation_started
    identity = {
        "schema_version": IDENTITY_SCHEMA,
        "execution_id": args.execution_id,
        "pipeline": PIPELINE_ID,
        "e6_result_id": e6.result_id,
        "job_id": e6.job.job_id,
        "input_sha256": e6.job.input_sha256,
        "session_id": e6.job.session_id,
        "source_id": e6.job.source_id,
        "calibration_sha256": e6.semantic.calibration_sha256,
        "camera_slot": e6.semantic.calibration_slot,
        "selection": selection,
        "configuration": profile,
        "profile_sha256": profile_sha256,
        "producer_sha256": _sha256(Path(__file__).resolve(strict=True)),
        "runtime_contract_sha256": _sha256(
            Path(live_perception_module.__file__).resolve(strict=True)
        ),
        "result_validator_sha256": _sha256(
            Path(live_validator_module.__file__).resolve(strict=True)
        ),
        "e6_adapter_sha256": _sha256(
            Path(__file__).with_name("fuse_e6_tracking_lidar.py").resolve(strict=True)
        ),
    }
    identity_sha256 = hashlib.sha256(_canonical_json(identity)).hexdigest()
    result_id = f"e7-live-replay-{identity_sha256}"
    parent = args.output_root.resolve()
    parent.mkdir(mode=0o700, parents=True, exist_ok=True)
    output = parent / result_id
    if output.exists():
        print(json.dumps({"result_id": result_id, "output": str(output), "reused": True}))
        return 0
    staging = parent / f".{result_id}.{os.getpid()}.incomplete"
    staging.mkdir(mode=0o700, exist_ok=False)
    world_path = staging / "world-state.jsonl"
    telemetry_path = staging / "telemetry.jsonl"
    rrd_path = staging / "world-state.rrd"
    report_path = staging / "run-report.json"
    queue = LatestWinsQueue[QueueEnvelope](int(profile["replay"]["queue_capacity"]))
    producer_error: list[BaseException] = []
    recording: rr.RecordingStream | None = None
    try:
        recording = rr.RecordingStream("nodedc_mission_core_e7", recording_id=result_id)
        recording.set_sinks(rr.FileSink(rrd_path, write_footer=True))
        recording.log("/world", rr.ViewCoordinates.RIGHT_HAND_Z_UP, static=True)
        recording.log(
            "/contract",
            rr.TextDocument(
                "LAB E7 replay-as-live: bounded latest-wins derived queue, explicit age and "
                "degradation, E6 diagnostic objects, no vehicle-control authority."
            ),
            static=True,
        )
        replay_speed = float(profile["replay"]["speed"])
        first_session = float(replay_frames[0].frame["session_seconds"])
        replay_started = time.perf_counter() + 0.25

        def produce() -> None:
            try:
                for replay_frame in replay_frames:
                    offset = (
                        float(replay_frame.frame["session_seconds"]) - first_session
                    ) / replay_speed
                    deadline = replay_started + offset
                    remaining = deadline - time.perf_counter()
                    if remaining > 0:
                        time.sleep(remaining)
                    enqueued = time.perf_counter()
                    queue.publish(
                        QueueEnvelope(
                            replay_frame=replay_frame,
                            scheduled_monotonic=deadline,
                            enqueued_monotonic=enqueued,
                            producer_lag_ms=max(0.0, (enqueued - deadline) * 1000.0),
                        )
                    )
            except BaseException as exc:  # noqa: BLE001 - forwarded to main thread
                producer_error.append(exc)
            finally:
                queue.close()

        producer = threading.Thread(target=produce, name="e7-replay-producer", daemon=True)
        producer.start()
        projector = WorldStateProjector(
            velocity_history_limit_s=float(
                profile["world_state"]["velocity_history_limit_s"]
            )
        )
        health_counts: Counter[str] = Counter()
        end_to_end: list[float] = []
        queue_wait: list[float] = []
        processing: list[float] = []
        rerun_latency: list[float] = []
        producer_lag: list[float] = []
        published_indices: list[int] = []
        consumer_delay = float(profile["replay"]["consumer_delay_ms"]) / 1000.0
        with world_path.open("w", encoding="utf-8") as world_stream, telemetry_path.open(
            "w", encoding="utf-8"
        ) as telemetry_stream:
            while True:
                envelope = queue.take_next(timeout=0.5)
                if envelope is None:
                    if queue.snapshot().closed:
                        break
                    continue
                dequeued = time.perf_counter()
                if consumer_delay > 0:
                    time.sleep(consumer_delay)
                stage_started = time.perf_counter()
                replay_frame = envelope.replay_frame
                cloud_lidar = _transform_to_lidar(replay_frame.cloud_map, replay_frame)
                accepted = [
                    item
                    for item in replay_frame.frame.get("objects", [])
                    if str(item.get("cuboid_status", "")).startswith("accepted-")
                ]
                centers_map = np.asarray(
                    [item["cuboid_center_map"] for item in accepted], dtype=np.float64
                ).reshape((-1, 3))
                centers_lidar = _transform_to_lidar(centers_map, replay_frame)
                lidar_positions = {
                    int(item["track_id"]): centers_lidar[index]
                    for index, item in enumerate(accepted)
                }
                world = projector.project(
                    frame=replay_frame.frame,
                    lidar_positions=lidar_positions,
                    clearance=_clearance(
                        cloud_lidar,
                        profile["world_state"]["clearance"],
                    ),
                )
                projection_finished = time.perf_counter()
                relative_seconds = (
                    float(replay_frame.frame["session_seconds"]) - first_session
                )
                recording.set_time(
                    "replay_time",
                    duration=np.timedelta64(round(relative_seconds * 1e9), "ns"),
                )
                if bool(profile["presentation"]["log_point_cloud"]) and replay_frame.cloud_map.size:
                    recording.log(
                        "/world/lidar",
                        rr.Points3D(
                            replay_frame.cloud_map,
                            colors=np.tile(
                                np.asarray([[145, 145, 145]], dtype=np.uint8),
                                (replay_frame.cloud_map.shape[0], 1),
                            ),
                            radii=rr.Radius.ui_points(
                                float(profile["presentation"]["point_radius_ui"])
                            ),
                        ),
                    )
                elif not replay_frame.cloud_map.size:
                    recording.log("/world/lidar", rr.Clear(recursive=False))
                if accepted:
                    colors = []
                    labels = []
                    for item in accepted:
                        group = str(item["association_group"])
                        colors.append(
                            {
                                "person": [255, 70, 170, 88],
                                "vehicle": [130, 90, 255, 88],
                                "bicycle": [80, 220, 255, 88],
                                "motorcycle": [255, 180, 65, 88],
                            }.get(group, [220, 220, 220, 88])
                        )
                        labels.append(
                            f"{group} #{item['track_id']} · "
                            f"{float(item['distance_smoothed_m']):.1f} m"
                        )
                    recording.log(
                        "/world/perception/boxes3d",
                        rr.Boxes3D(
                            centers=centers_map.astype(np.float32),
                            half_sizes=np.asarray(
                                [item["cuboid_half_size"] for item in accepted],
                                dtype=np.float32,
                            ),
                            quaternions=np.asarray(
                                [item["cuboid_quaternion_xyzw"] for item in accepted],
                                dtype=np.float32,
                            ),
                            colors=np.asarray(colors, dtype=np.uint8),
                            labels=labels,
                            fill_mode=FillMode.Solid,
                            show_labels=True,
                        ),
                    )
                else:
                    recording.log("/world/perception/boxes3d", rr.Clear(recursive=False))
                rerun_finished = time.perf_counter()
                age_ms = (rerun_finished - envelope.scheduled_monotonic) * 1000.0
                health, reasons = classify_health(
                    source_available=True,
                    fusion_state=str(replay_frame.frame["state"]),
                    result_age_ms=age_ms,
                    stale_after_ms=float(profile["health"]["stale_after_ms"]),
                    unavailable_after_ms=float(profile["health"]["unavailable_after_ms"]),
                )
                health_counts[health] += 1
                world["delivery"] = {
                    "health": health,
                    "reasons": list(reasons),
                    "result_age_ms": age_ms,
                    "queue_policy": "bounded-latest-wins",
                }
                world_stream.write(json.dumps(world, ensure_ascii=False, allow_nan=False) + "\n")
                published = time.perf_counter()
                latency_ms = (published - envelope.scheduled_monotonic) * 1000.0
                recording.log("/telemetry/end_to_end_latency_ms", rr.Scalars([latency_ms]))
                recording.log("/telemetry/queue_depth", rr.Scalars([queue.snapshot().depth]))
                recording.log(
                    "/telemetry/health_code",
                    rr.Scalars(
                        [{"healthy": 0, "degraded": 1, "stale": 2, "unavailable": 3}[health]]
                    ),
                )
                telemetry = {
                    "schema_version": TELEMETRY_SCHEMA,
                    "frame_index": int(replay_frame.frame["frame_index"]),
                    "source_frame_index": int(replay_frame.frame["source_frame_index"]),
                    "session_seconds": float(replay_frame.frame["session_seconds"]),
                    "producer_lag_ms": envelope.producer_lag_ms,
                    "queue_wait_ms": (dequeued - envelope.enqueued_monotonic) * 1000.0,
                    "world_projection_ms": (projection_finished - stage_started) * 1000.0,
                    "rerun_publish_ms": (rerun_finished - projection_finished) * 1000.0,
                    "end_to_end_latency_ms": latency_ms,
                    "health": health,
                    "queue": _queue_document(queue),
                }
                telemetry_stream.write(
                    json.dumps(telemetry, ensure_ascii=False, allow_nan=False) + "\n"
                )
                end_to_end.append(latency_ms)
                queue_wait.append(telemetry["queue_wait_ms"])
                processing.append(telemetry["world_projection_ms"])
                rerun_latency.append(telemetry["rerun_publish_ms"])
                producer_lag.append(envelope.producer_lag_ms)
                published_indices.append(int(replay_frame.frame["frame_index"]))
        producer.join(timeout=5)
        if producer.is_alive():
            raise RuntimeError("LAB E7 replay producer did not stop")
        if producer_error:
            raise RuntimeError("LAB E7 replay producer failed") from producer_error[0]
        if recording is not None:
            recording.flush()
            recording.disconnect()
            recording = None
        finished = time.perf_counter()
        queue_metrics = queue.snapshot()
        replay_span = (
            float(replay_frames[-1].frame["session_seconds"])
            - float(replay_frames[0].frame["session_seconds"])
        ) / replay_speed
        replay_wall = finished - replay_started
        attempted = len(replay_frames)
        processed = len(published_indices)
        metrics = {
            "frames_attempted": attempted,
            "frames_processed": processed,
            "frames_dropped": queue_metrics.dropped_total,
            "drop_fraction": queue_metrics.dropped_total / attempted,
            "delivery_rate_hz": processed / replay_span,
            "replay_span_seconds": replay_span,
            "replay_wall_seconds": replay_wall,
            "preparation_wall_seconds": preparation_wall,
            "process_peak_rss_mib": _peak_rss_mib(),
            "health_counts": dict(health_counts),
            "queue": {
                "capacity": queue_metrics.capacity,
                "maximum_depth": queue_metrics.maximum_depth,
                "final_depth": queue_metrics.depth,
                "published": queue_metrics.published,
                "consumed": queue_metrics.consumed,
                "dropped_overflow": queue_metrics.dropped_overflow,
                "dropped_superseded": queue_metrics.dropped_superseded,
            },
            "end_to_end_latency_ms": {
                "mean": float(np.mean(end_to_end)),
                "p50": _percentile(end_to_end, 50),
                "p95": _percentile(end_to_end, 95),
                "max": max(end_to_end),
            },
            "queue_wait_ms": {
                "mean": float(np.mean(queue_wait)),
                "p95": _percentile(queue_wait, 95),
                "max": max(queue_wait),
            },
            "world_projection_ms": {
                "mean": float(np.mean(processing)),
                "p95": _percentile(processing, 95),
                "max": max(processing),
            },
            "rerun_publish_ms": {
                "mean": float(np.mean(rerun_latency)),
                "p95": _percentile(rerun_latency, 95),
                "max": max(rerun_latency),
            },
            "producer_lag_ms": {
                "mean": float(np.mean(producer_lag)),
                "p95": _percentile(producer_lag, 95),
                "max": max(producer_lag),
            },
            "published_frame_index_start": min(published_indices),
            "published_frame_index_end": max(published_indices),
        }
        accepted, rejection_reasons = _accepted(profile, metrics)
        report = {
            "schema_version": REPORT_SCHEMA,
            "result_id": result_id,
            "created_at_utc": datetime.now(UTC).isoformat(timespec="milliseconds").replace(
                "+00:00", "Z"
            ),
            "identity": identity,
            "acceptance": {
                "accepted": accepted,
                "mode": profile["mode"],
                "rejection_reasons": rejection_reasons,
                "navigation_or_safety_accepted": False,
                "scope": "replay-scheduler-and-world-state-not-live-inference",
            },
            "metrics": metrics,
        }
        report_path.write_text(
            json.dumps(report, ensure_ascii=False, indent=2, sort_keys=True) + "\n",
            encoding="utf-8",
        )
        artifacts = [
            _artifact(
                world_path,
                "live-world-state",
                "application/x-ndjson",
                "missioncore.live-perception-world-state/v1",
            ),
            _artifact(
                telemetry_path,
                "live-telemetry",
                "application/x-ndjson",
                TELEMETRY_SCHEMA,
            ),
            _artifact(rrd_path, "live-rerun", "application/vnd.rerun.rrd"),
            _artifact(report_path, "live-run-report", "application/json", REPORT_SCHEMA),
        ]
        result = {
            "schema_version": RESULT_SCHEMA,
            "result_id": result_id,
            "identity_sha256": identity_sha256,
            "identity": identity,
            "ground_truth": False,
            "publication_scope": "replay-qualification-only",
            "acceptance_state": "accepted" if accepted else "rejected",
            "metrics": metrics,
            "artifacts": artifacts,
        }
        (staging / "result.json").write_text(
            json.dumps(result, ensure_ascii=False, indent=2, sort_keys=True) + "\n",
            encoding="utf-8",
        )
        staging.rename(output)
        validated = validate_live_replay_qualification_result(
            args.job,
            args.tracking,
            args.semantic,
            args.e6_result,
            output,
        )
        if validated.result_id != result_id or validated.accepted != accepted:
            raise RuntimeError("LAB E7 published result failed identity validation")
        print(
            json.dumps(
                {
                    "result_id": result_id,
                    "output": str(output),
                    "accepted": accepted,
                    "metrics": metrics,
                },
                ensure_ascii=False,
            )
        )
        return 0 if accepted else 2
    except BaseException:
        if recording is not None:
            recording.disconnect()
        queue.close()
        shutil.rmtree(staging, ignore_errors=True)
        raise


if __name__ == "__main__":
    raise SystemExit(main())
