feat(perception): add lossless lidar replay v2

This commit is contained in:
DCCONSTRUCTIONS
2026-07-25 01:35:03 +03:00
parent 3f549f91f1
commit e4fdd9fa20
18 changed files with 2538 additions and 11 deletions
@@ -0,0 +1,311 @@
export interface LidarDistribution {
sampleCount: number;
minimum: number | null;
mean: number | null;
p50: number | null;
p95: number | null;
maximum: number | null;
}
export interface LidarPackSummary {
packId: string;
sessionId: string;
profileId: string;
pointFrames: number;
poseFrames: number;
points: number;
meanPointsPerFrame: number | null;
p95FrameIntervalMs: number | null;
poseCoverageFraction: number | null;
equivalenceStatus: "passed";
logicalContentSha256: string;
createdAtUtc: string | null;
}
export interface LidarReplayCatalog {
configured: boolean;
validTotal: number;
invalidTotal: number;
duplicateTotal: number;
items: LidarPackSummary[];
}
export interface LidarStageReadiness {
stage: string;
readiness: "ready" | "degraded" | "blocked";
reasons: string[];
}
export interface LidarReplayDetail {
pack: LidarPackSummary;
quality: {
fieldRetention: Record<string, boolean>;
pointCountPerFrame: LidarDistribution;
pointFrameIntervalMs: LidarDistribution;
intensity: LidarDistribution;
poseBinding: {
thresholdMs: number;
coveredPointFrames: number;
coverageFraction: number;
nearestDeltaMs: LidarDistribution;
};
limitations: string[];
};
equivalence: {
status: "passed";
arraysCompared: number;
arrayMismatches: number;
};
stages: LidarStageReadiness[];
}
export class LidarReplayContractError extends Error {}
export class LidarReplayApiError extends Error {
constructor(message: string, readonly status: number | null = null) {
super(message);
}
}
type LidarFetch = (
input: RequestInfo | URL,
init?: RequestInit,
) => Promise<Response>;
const SAFE_PACK_ID = /^lidar-replay-pack-[a-f0-9]{64}$/;
const SAFE_ID = /^[A-Za-z0-9][A-Za-z0-9._:/-]{0,159}$/;
const SHA256 = /^[a-f0-9]{64}$/;
function record(value: unknown, label: string): Record<string, unknown> {
if (!value || typeof value !== "object" || Array.isArray(value)) {
throw new LidarReplayContractError(`${label}: ожидался объект`);
}
return value as Record<string, unknown>;
}
function array(value: unknown, label: string): unknown[] {
if (!Array.isArray(value)) {
throw new LidarReplayContractError(`${label}: ожидался массив`);
}
return value;
}
function string(value: unknown, label: string, pattern?: RegExp): string {
if (typeof value !== "string" || !value || (pattern && !pattern.test(value))) {
throw new LidarReplayContractError(`${label}: некорректная строка`);
}
return value;
}
function number(value: unknown, label: string, nullable = false): number | null {
if (nullable && value === null) return null;
if (typeof value !== "number" || !Number.isFinite(value)) {
throw new LidarReplayContractError(`${label}: некорректное число`);
}
return value;
}
function integer(value: unknown, label: string): number {
const parsed = number(value, label);
if (parsed === null || !Number.isInteger(parsed) || parsed < 0) {
throw new LidarReplayContractError(`${label}: ожидалось неотрицательное целое`);
}
return parsed;
}
function boolean(value: unknown, label: string): boolean {
if (typeof value !== "boolean") {
throw new LidarReplayContractError(`${label}: ожидался boolean`);
}
return value;
}
function distribution(value: unknown, label: string): LidarDistribution {
const source = record(value, label);
return {
sampleCount: integer(source.sample_count, `${label}.sample_count`),
minimum: number(source.minimum, `${label}.minimum`, true),
mean: number(source.mean, `${label}.mean`, true),
p50: number(source.p50, `${label}.p50`, true),
p95: number(source.p95, `${label}.p95`, true),
maximum: number(source.maximum, `${label}.maximum`, true),
};
}
function packSummary(value: unknown): LidarPackSummary {
const source = record(value, "LiDAR pack");
if (source.equivalence_status !== "passed") {
throw new LidarReplayContractError("LiDAR pack не прошёл equivalence gate");
}
return {
packId: string(source.pack_id, "pack_id", SAFE_PACK_ID),
sessionId: string(source.session_id, "session_id", SAFE_ID),
profileId: string(source.profile_id, "profile_id", SAFE_ID),
pointFrames: integer(source.point_frames, "point_frames"),
poseFrames: integer(source.pose_frames, "pose_frames"),
points: integer(source.points, "points"),
meanPointsPerFrame: number(source.mean_points_per_frame, "mean_points_per_frame", true),
p95FrameIntervalMs: number(source.p95_frame_interval_ms, "p95_frame_interval_ms", true),
poseCoverageFraction: number(
source.pose_coverage_fraction,
"pose_coverage_fraction",
true,
),
equivalenceStatus: "passed",
logicalContentSha256: string(
source.logical_content_sha256,
"logical_content_sha256",
SHA256,
),
createdAtUtc:
source.created_at_utc === null || source.created_at_utc === undefined
? null
: string(source.created_at_utc, "created_at_utc"),
};
}
export function parseLidarReplayCatalog(value: unknown): LidarReplayCatalog {
const source = record(value, "LiDAR catalog");
if (source.schema_version !== "missioncore.lidar-replay-pack-catalog/v1") {
throw new LidarReplayContractError("LiDAR catalog schema несовместима");
}
return {
configured: boolean(source.configured, "configured"),
validTotal: integer(source.valid_total, "valid_total"),
invalidTotal: integer(source.invalid_total, "invalid_total"),
duplicateTotal: integer(source.duplicate_total, "duplicate_total"),
items: array(source.items, "items").map(packSummary),
};
}
export function parseLidarReplayDetail(value: unknown): LidarReplayDetail {
const source = record(value, "LiDAR detail");
if (
source.schema_version !== "missioncore.lidar-replay-pack-detail/v1"
|| source.access !== "read-only"
) {
throw new LidarReplayContractError("LiDAR detail contract несовместим");
}
const quality = record(source.quality, "quality");
const retention = record(quality.field_retention, "field_retention");
const fieldRetention: Record<string, boolean> = {};
for (const [key, retained] of Object.entries(retention)) {
fieldRetention[key] = boolean(retained, `field_retention.${key}`);
}
const poseBinding = record(quality.pose_binding, "pose_binding");
const equivalence = record(source.equivalence, "equivalence");
if (equivalence.status !== "passed") {
throw new LidarReplayContractError("LiDAR equivalence gate не пройден");
}
const readiness = record(source.readiness, "readiness");
const stages = array(readiness.stages, "readiness.stages").map((value) => {
const stage = record(value, "readiness stage");
const readinessValue = stage.readiness;
if (
readinessValue !== "ready"
&& readinessValue !== "degraded"
&& readinessValue !== "blocked"
) {
throw new LidarReplayContractError("Неизвестный LiDAR readiness status");
}
const normalizedReadiness: LidarStageReadiness["readiness"] = readinessValue;
return {
stage: string(stage.stage, "stage", SAFE_ID),
readiness: normalizedReadiness,
reasons: array(stage.reasons, "stage.reasons").map((reason) =>
string(reason, "stage reason", SAFE_ID)
),
};
});
return {
pack: packSummary(source.pack),
quality: {
fieldRetention,
pointCountPerFrame: distribution(quality.point_count_per_frame, "point_count"),
pointFrameIntervalMs: distribution(
quality.point_frame_interval_ms,
"point_interval",
),
intensity: distribution(quality.intensity_0_255, "intensity"),
poseBinding: {
thresholdMs: number(poseBinding.threshold_ms, "pose threshold") ?? 0,
coveredPointFrames: integer(
poseBinding.covered_point_frames,
"covered point frames",
),
coverageFraction: number(
poseBinding.coverage_fraction,
"pose coverage",
) ?? 0,
nearestDeltaMs: distribution(
poseBinding.nearest_delta_ms,
"nearest pose delta",
),
},
limitations: array(quality.limitations, "limitations").map((item) =>
string(item, "limitation")
),
},
equivalence: {
status: "passed",
arraysCompared: integer(equivalence.arrays_compared, "arrays_compared"),
arrayMismatches: integer(
equivalence.array_mismatches,
"array_mismatches",
),
},
stages,
};
}
async function responseJson(
response: Response,
fallback: string,
): Promise<unknown> {
let value: unknown;
try {
value = await response.json();
} catch {
throw new LidarReplayApiError(fallback, response.status);
}
if (!response.ok) {
const detail = record(value, "API error").detail;
throw new LidarReplayApiError(
typeof detail === "string" && detail.trim() ? detail : fallback,
response.status,
);
}
return value;
}
export async function fetchLidarReplayCatalog(
options: { signal?: AbortSignal; fetcher?: LidarFetch } = {},
): Promise<LidarReplayCatalog> {
const fetcher = options.fetcher ?? fetch;
const response = await fetcher("/api/v1/lidar/replay-packs?limit=50", {
method: "GET",
headers: { Accept: "application/json" },
signal: options.signal,
});
return parseLidarReplayCatalog(
await responseJson(response, "Не удалось получить каталог LiDAR replay."),
);
}
export async function fetchLidarReplayDetail(
packId: string,
options: { signal?: AbortSignal; fetcher?: LidarFetch } = {},
): Promise<LidarReplayDetail> {
if (!SAFE_PACK_ID.test(packId)) {
throw new LidarReplayContractError("Некорректный LiDAR pack id");
}
const fetcher = options.fetcher ?? fetch;
const response = await fetcher(`/api/v1/lidar/replay-packs/${packId}`, {
method: "GET",
headers: { Accept: "application/json" },
signal: options.signal,
});
return parseLidarReplayDetail(
await responseJson(response, "Не удалось получить LiDAR quality report."),
);
}
+13
View File
@@ -18,6 +18,7 @@ export type WorkspaceKind =
| "timeline"
| "missions"
| "catalog"
| "lidar-quality"
| "polygon-run";
export type CapabilityStatus = "active" | "ready" | "contract" | "later";
@@ -586,6 +587,18 @@ export const workspaces: WorkspaceDefinition[] = [
},
],
},
{
id: "lidar-quality",
root: "data",
label: "Качество LiDAR",
title: "Качество LiDAR",
eyebrow: "ДАННЫЕ / LIDAR EVIDENCE",
description:
"Проверенные поля сканера, частота, плотность, intensity, pose coverage и допуск следующих алгоритмов.",
icon: "activity",
kind: "lidar-quality",
groups: [],
},
{
id: "entities",
root: "data",
@@ -13,7 +13,8 @@
.mission-layout,
.polygon-live-layout,
.polygon-run-layout,
.polygon-run-evidence-grid {
.polygon-run-evidence-grid,
.lidar-quality-grid {
grid-template-columns: 1fr;
}
@@ -157,6 +158,10 @@
grid-template-columns: 1fr;
}
.lidar-quality-facts {
grid-template-columns: 1fr;
}
.polygon-run-identity dl {
grid-template-columns: 1fr;
}
@@ -803,6 +803,157 @@
font-weight: 650;
}
.lidar-quality-workspace {
gap: 1rem;
}
.lidar-quality-message {
display: grid;
min-height: 12rem;
align-content: center;
justify-items: start;
gap: 0.7rem;
}
.lidar-quality-message h2,
.lidar-quality-message p {
margin: 0;
}
.lidar-quality-message p {
max-width: 46rem;
color: var(--nodedc-text-muted);
font-size: 0.76rem;
line-height: 1.55;
}
.lidar-quality-grid {
display: grid;
grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
gap: 0.85rem;
}
.lidar-quality-panel {
min-width: 0;
}
.lidar-quality-facts {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 0.65rem;
margin-top: 1rem;
}
.lidar-quality-facts > div {
display: grid;
gap: 0.32rem;
border: 1px solid var(--station-hairline);
border-radius: 0.8rem;
background: rgb(255 255 255 / 0.025);
padding: 0.72rem;
}
.lidar-quality-facts span,
.lidar-pack-catalog footer,
.lidar-readiness-list small {
color: var(--nodedc-text-muted);
font-size: 0.62rem;
line-height: 1.45;
}
.lidar-quality-facts strong {
overflow: hidden;
color: var(--nodedc-text-primary);
font-size: 0.72rem;
text-overflow: ellipsis;
}
.lidar-retention-list {
display: flex;
flex-wrap: wrap;
gap: 0.42rem;
margin-top: 0.8rem;
}
.lidar-retention-list span {
display: inline-flex;
align-items: center;
gap: 0.35rem;
border: 1px solid var(--station-hairline);
border-radius: 999px;
padding: 0.34rem 0.52rem;
color: var(--nodedc-text-secondary);
font-size: 0.58rem;
}
.lidar-retention-list i {
width: 0.38rem;
height: 0.38rem;
border-radius: 50%;
background: rgb(185 255 74 / 0.9);
}
.lidar-retention-list span[data-retained="false"] i {
background: rgb(255 97 97 / 0.9);
}
.lidar-readiness-list,
.lidar-pack-list {
display: grid;
gap: 0.48rem;
margin-top: 1rem;
}
.lidar-readiness-list > div,
.lidar-pack-list > button {
display: flex;
min-width: 0;
align-items: center;
justify-content: space-between;
gap: 0.8rem;
border: 1px solid var(--station-hairline);
border-radius: 0.78rem;
background: rgb(255 255 255 / 0.02);
padding: 0.68rem 0.76rem;
}
.lidar-readiness-list > div > div,
.lidar-pack-list > button > div {
display: grid;
min-width: 0;
gap: 0.24rem;
}
.lidar-readiness-list strong,
.lidar-pack-list strong {
color: var(--nodedc-text-primary);
font-size: 0.68rem;
}
.lidar-pack-list > button {
width: 100%;
color: inherit;
text-align: left;
cursor: pointer;
}
.lidar-pack-list > button:hover,
.lidar-pack-list > button[data-selected="true"] {
border-color: rgb(185 255 74 / 0.42);
background: rgb(185 255 74 / 0.055);
}
.lidar-pack-list small {
color: var(--nodedc-text-muted);
font-size: 0.6rem;
}
.lidar-pack-catalog footer {
display: grid;
gap: 0.22rem;
margin-top: 0.8rem;
}
.overview-grid {
display: grid;
grid-template-columns: minmax(0, 1.55fr) minmax(19rem, 0.75fr);
@@ -0,0 +1,269 @@
import { useEffect, useState } from "react";
import {
Button,
GlassSurface,
StatusBadge,
} from "@nodedc/ui-react";
import {
fetchLidarReplayCatalog,
fetchLidarReplayDetail,
type LidarReplayCatalog,
type LidarReplayDetail,
type LidarStageReadiness,
} from "../core/lidar/replayQuality";
import { MetricCard } from "../components/MetricCard";
import type { WorkspaceDefinition } from "../productModel";
function formatNumber(value: number | null, digits = 1): string {
if (value === null) return "—";
return value.toLocaleString("ru-RU", { maximumFractionDigits: digits });
}
function formatFraction(value: number | null): string {
return value === null ? "—" : `${(value * 100).toLocaleString("ru-RU", {
maximumFractionDigits: 1,
})}%`;
}
function readinessTone(
readiness: LidarStageReadiness["readiness"],
): "success" | "warning" | "danger" {
if (readiness === "ready") return "success";
if (readiness === "degraded") return "warning";
return "danger";
}
function readinessLabel(readiness: LidarStageReadiness["readiness"]): string {
if (readiness === "ready") return "Готов";
if (readiness === "degraded") return "С ограничениями";
return "Заблокирован";
}
function errorMessage(error: unknown): string {
return error instanceof Error && error.message.trim()
? error.message
: "Не удалось прочитать LiDAR evidence.";
}
export function LidarQualityWorkspace({
definition,
}: {
definition: WorkspaceDefinition;
}) {
const [catalog, setCatalog] = useState<LidarReplayCatalog | null>(null);
const [detail, setDetail] = useState<LidarReplayDetail | null>(null);
const [selectedPackId, setSelectedPackId] = useState<string | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const [reloadGeneration, setReloadGeneration] = useState(0);
useEffect(() => {
const controller = new AbortController();
setLoading(true);
setError(null);
void (async () => {
try {
const nextCatalog = await fetchLidarReplayCatalog({
signal: controller.signal,
});
if (controller.signal.aborted) return;
setCatalog(nextCatalog);
const target = selectedPackId ?? nextCatalog.items[0]?.packId ?? null;
if (!target) {
setDetail(null);
return;
}
const nextDetail = await fetchLidarReplayDetail(target, {
signal: controller.signal,
});
if (controller.signal.aborted) return;
setSelectedPackId(target);
setDetail(nextDetail);
} catch (loadError) {
if (controller.signal.aborted) return;
setDetail(null);
setError(errorMessage(loadError));
} finally {
if (!controller.signal.aborted) setLoading(false);
}
})();
return () => controller.abort();
}, [reloadGeneration, selectedPackId]);
return (
<div className="standard-workspace lidar-quality-workspace">
<section className="workspace-lead workspace-lead--compact">
<div>
<span className="section-eyebrow">{definition.eyebrow}</span>
<h2>{definition.title}</h2>
<p>{definition.description}</p>
</div>
<span className="workspace-lead__note">Только проверенные replay-артефакты</span>
</section>
{loading && !detail ? (
<GlassSurface className="lidar-quality-message" padding="lg">
<StatusBadge tone="accent">Проверка evidence</StatusBadge>
<h2>Читаем LiDAR replay и quality report</h2>
<p>Интерфейс покажет pack только после проверки manifest, hashes и equivalence gate.</p>
</GlassSurface>
) : error ? (
<GlassSurface className="lidar-quality-message" padding="lg">
<StatusBadge tone="danger">Данные недоступны</StatusBadge>
<h2>LiDAR quality report не открыт</h2>
<p>{error}</p>
<Button
size="compact"
variant="secondary"
onClick={() => setReloadGeneration((value) => value + 1)}
>
Повторить
</Button>
</GlassSurface>
) : !detail ? (
<GlassSurface className="lidar-quality-message" padding="lg">
<StatusBadge tone={catalog?.configured ? "neutral" : "warning"}>
{catalog?.configured ? "Каталог пуст" : "Storage не настроен"}
</StatusBadge>
<h2>Lossless LiDAR replay пока не опубликован</h2>
<p>
После подготовки первого v2 pack здесь появятся field retention, cadence,
intensity, pose coverage и readiness следующих стадий.
</p>
</GlassSurface>
) : (
<>
<section className="metrics-grid" aria-label="Качество LiDAR replay">
<MetricCard
featured
eyebrow="ТОЧЕЧНЫХ КАДРОВ"
value={detail.pack.pointFrames.toLocaleString("ru-RU")}
detail={`${detail.pack.points.toLocaleString("ru-RU")} точек сохранено`}
/>
<MetricCard
eyebrow="СРЕДНЕЕ ТОЧЕК"
value={formatNumber(detail.pack.meanPointsPerFrame, 0)}
detail="На один lio_pcl кадр"
/>
<MetricCard
eyebrow="P95 ИНТЕРВАЛА"
value={formatNumber(detail.pack.p95FrameIntervalMs)}
unit="мс"
detail="По exact host monotonic time"
/>
<MetricCard
eyebrow="POSE COVERAGE"
value={formatFraction(detail.pack.poseCoverageFraction)}
detail={`Порог ${formatNumber(detail.quality.poseBinding.thresholdMs)} мс`}
/>
</section>
<div className="lidar-quality-grid">
<GlassSurface className="lidar-quality-panel" padding="lg">
<header className="panel-heading">
<div>
<span className="section-eyebrow">ЦЕЛОСТНОСТЬ</span>
<h2>Lossless replay v2</h2>
</div>
<StatusBadge tone="success">Equivalence passed</StatusBadge>
</header>
<div className="lidar-quality-facts">
<div>
<span>Сессия</span>
<strong>{detail.pack.sessionId}</strong>
</div>
<div>
<span>Сверено массивов</span>
<strong>{detail.equivalence.arraysCompared}</strong>
</div>
<div>
<span>Несовпадений</span>
<strong>{detail.equivalence.arrayMismatches}</strong>
</div>
<div>
<span>Intensity p50 / p95</span>
<strong>
{formatNumber(detail.quality.intensity.p50)} /{" "}
{formatNumber(detail.quality.intensity.p95)}
</strong>
</div>
</div>
<div className="lidar-retention-list">
{Object.entries(detail.quality.fieldRetention).map(([field, retained]) => (
<span key={field} data-retained={retained ? "true" : "false"}>
<i aria-hidden="true" />
{field.replaceAll("_", " ")}
</span>
))}
</div>
</GlassSurface>
<GlassSurface className="lidar-quality-panel" padding="lg">
<header className="panel-heading">
<div>
<span className="section-eyebrow">ДОПУСК СТАДИЙ</span>
<h2>Что можно запускать</h2>
</div>
</header>
<div className="lidar-readiness-list">
{detail.stages.map((stage) => (
<div key={stage.stage}>
<div>
<strong>{stage.stage}</strong>
<small>
{stage.reasons.length
? stage.reasons.join(" · ")
: "Входной контракт выполнен"}
</small>
</div>
<StatusBadge tone={readinessTone(stage.readiness)}>
{readinessLabel(stage.readiness)}
</StatusBadge>
</div>
))}
</div>
</GlassSurface>
</div>
<GlassSurface className="lidar-pack-catalog" padding="lg">
<header className="panel-heading">
<div>
<span className="section-eyebrow">REPLAY PACKS</span>
<h2>Проверенные записи</h2>
</div>
<small>
{catalog?.validTotal ?? 0} valid · {catalog?.duplicateTotal ?? 0} superseded ·{" "}
{catalog?.invalidTotal ?? 0} rejected
</small>
</header>
<div className="lidar-pack-list">
{catalog?.items.map((pack) => (
<button
type="button"
key={pack.packId}
data-selected={pack.packId === detail.pack.packId ? "true" : undefined}
onClick={() => setSelectedPackId(pack.packId)}
>
<div>
<strong>{pack.sessionId}</strong>
<small>
{pack.pointFrames.toLocaleString("ru-RU")} кадров ·{" "}
{pack.points.toLocaleString("ru-RU")} точек
</small>
</div>
<StatusBadge tone="success">Passed</StatusBadge>
</button>
))}
</div>
<footer>
{detail.quality.limitations.map((limitation) => (
<span key={limitation}>{limitation}</span>
))}
</footer>
</GlassSurface>
</>
)}
</div>
);
}
@@ -57,6 +57,7 @@ import {
import { finiteMetric, formatNumber, pipelineLatency, sourceModeLabel } from "../presentation";
import type { SceneSettings } from "../sceneSettings";
import { PolygonRunWorkspace } from "./PolygonRunWorkspace";
import { LidarQualityWorkspace } from "./LidarQualityWorkspace";
function statusTone(status: CapabilityStatus): "success" | "accent" | "warning" | "neutral" {
if (status === "active") return "success";
@@ -1306,6 +1307,8 @@ export function WorkspaceRenderer(props: WorkspaceRendererProps) {
return <MissionWorkspace {...props} />;
case "catalog":
return <CatalogWorkspace {...props} />;
case "lidar-quality":
return <LidarQualityWorkspace definition={props.definition} />;
case "polygon-run":
return <PolygonRunWorkspace route={props.polygonRunRoute} />;
case "device":
@@ -0,0 +1,179 @@
import assert from "node:assert/strict";
import { after, before, test } from "node:test";
import { createServer } from "vite";
let server;
let parseLidarReplayCatalog;
let parseLidarReplayDetail;
let fetchLidarReplayCatalog;
let fetchLidarReplayDetail;
let LidarReplayContractError;
let workspaceById;
before(async () => {
server = await createServer({
appType: "custom",
logLevel: "silent",
server: { middlewareMode: true },
});
({
parseLidarReplayCatalog,
parseLidarReplayDetail,
fetchLidarReplayCatalog,
fetchLidarReplayDetail,
LidarReplayContractError,
} = await server.ssrLoadModule("/src/core/lidar/replayQuality.ts"));
({ workspaceById } = await server.ssrLoadModule("/src/productModel.ts"));
});
after(async () => {
await server?.close();
});
const packId = `lidar-replay-pack-${"a".repeat(64)}`;
function summary(overrides = {}) {
return {
pack_id: packId,
session_id: "20260719T220917Z_viewer_live",
profile_id: "xgrids-k1-lidar-replay-pack/v2",
point_frames: 10,
pose_frames: 12,
points: 1234,
mean_points_per_frame: 123.4,
p95_frame_interval_ms: 98.7,
pose_coverage_fraction: 0.9,
equivalence_status: "passed",
logical_content_sha256: "b".repeat(64),
created_at_utc: "2026-07-25T00:00:00Z",
authority: {
commands_enabled: false,
navigation_or_safety_accepted: false,
},
...overrides,
};
}
function distribution() {
return {
sample_count: 10,
minimum: 1,
mean: 2,
p50: 2,
p95: 3,
maximum: 4,
};
}
function catalog(overrides = {}) {
return {
schema_version: "missioncore.lidar-replay-pack-catalog/v1",
configured: true,
items: [summary()],
valid_total: 1,
invalid_total: 0,
duplicate_total: 0,
access: "read-only",
...overrides,
};
}
function detail() {
return {
schema_version: "missioncore.lidar-replay-pack-detail/v1",
access: "read-only",
pack: summary({ created_at_utc: undefined }),
quality: {
schema_version: "missioncore.lidar-quality-report/v1",
field_retention: {
xyz_map: true,
raw_xyz: true,
raw_rgbi: true,
intensity_low_byte: true,
source_sequence: true,
header_seq_stamp_scaler: true,
host_epoch_ns: true,
host_monotonic_ns: true,
},
point_count_per_frame: distribution(),
point_frame_interval_ms: distribution(),
intensity_0_255: distribution(),
pose_binding: {
threshold_ms: 100,
covered_point_frames: 9,
coverage_fraction: 0.9,
nearest_delta_ms: distribution(),
},
limitations: ["vendor-mapped increment"],
},
equivalence: {
schema_version: "missioncore.lidar-live-replay-equivalence/v1",
status: "passed",
arrays_compared: 24,
array_mismatches: 0,
},
readiness: {
stages: [
{
stage: "lidar-3d-detection",
readiness: "degraded",
reasons: ["pretrained-domain-expects-sensor-scan"],
},
{
stage: "lidar-inertial-slam",
readiness: "blocked",
reasons: ["lio-requires-unregistered-sensor-scans"],
},
],
},
};
}
function jsonResponse(payload, status = 200) {
return new Response(JSON.stringify(payload), {
status,
headers: { "content-type": "application/json" },
});
}
test("LiDAR catalog and detail decode only passed, path-free evidence", () => {
const parsedCatalog = parseLidarReplayCatalog(catalog());
const parsedDetail = parseLidarReplayDetail(detail());
assert.equal(parsedCatalog.items[0].packId, packId);
assert.equal(parsedDetail.quality.fieldRetention.raw_rgbi, true);
assert.equal(parsedDetail.equivalence.arrayMismatches, 0);
assert.equal(parsedDetail.stages[0].readiness, "degraded");
assert.equal("path" in parsedCatalog.items[0], false);
});
test("LiDAR contract refuses replay that did not pass equivalence", () => {
assert.throws(
() => parseLidarReplayCatalog(catalog({
items: [summary({ equivalence_status: "failed" })],
})),
LidarReplayContractError,
);
});
test("LiDAR fetchers use read-only endpoints and workspace is registered", async () => {
const calls = [];
const fetcher = async (input, init) => {
calls.push({ input: String(input), method: init?.method });
return String(input).includes(packId)
? jsonResponse(detail())
: jsonResponse(catalog());
};
const parsedCatalog = await fetchLidarReplayCatalog({ fetcher });
const parsedDetail = await fetchLidarReplayDetail(packId, { fetcher });
assert.equal(parsedCatalog.validTotal, 1);
assert.equal(parsedDetail.pack.packId, packId);
assert.deepEqual(calls, [
{ input: "/api/v1/lidar/replay-packs?limit=50", method: "GET" },
{ input: `/api/v1/lidar/replay-packs/${packId}`, method: "GET" },
]);
assert.equal(workspaceById("lidar-quality").root, "data");
assert.equal(workspaceById("lidar-quality").kind, "lidar-quality");
});