feat(lab): separate RAVNOVES transfer from public benchmark

This commit is contained in:
DCCONSTRUCTIONS
2026-07-31 14:35:51 +03:00
parent 55b7821a5c
commit c1b0f6f8a3
15 changed files with 1018 additions and 61 deletions
@@ -14,9 +14,11 @@ import { fetchE34TemporalLayerResult } from "./e34TemporalLayer";
import { fetchE35DegradationRecoveryResult } from "./e35DegradationRecovery";
import { fetchE40ProductGateResult } from "./e40ProductGate";
import { fetchL3PointPillarsVisualAudit } from "./l3PointPillarsVisualAudit";
import { fetchL31PointPillarsRavnoves } from "./l31PointPillarsRavnoves";
export type AdvancedLaboratoryWorkId =
| "l3-pointpillars-visual-audit"
| "l31-pointpillars-ravnoves"
| "e31-source-binding"
| "e32-track-geometry"
| "e33-worker-shadow"
@@ -35,6 +37,7 @@ export interface AdvancedLaboratoryIndexItem {
const WORK_IDS: readonly AdvancedLaboratoryWorkId[] = [
"l3-pointpillars-visual-audit",
"l31-pointpillars-ravnoves",
"e31-source-binding",
"e32-track-geometry",
"e33-worker-shadow",
@@ -48,6 +51,7 @@ const WORK_IDS: readonly AdvancedLaboratoryWorkId[] = [
const RESULT_PREFIX: Readonly<Record<AdvancedLaboratoryWorkId, string>> = {
"l3-pointpillars-visual-audit": "l3-pointpillars-visual-audit",
"l31-pointpillars-ravnoves": "l31-pointpillars-ravnoves",
"e31-source-binding": "e31-source-qualification",
"e32-track-geometry": "e32-track-geometry",
"e33-worker-shadow": "e33-worker-shadow",
@@ -68,6 +72,7 @@ export function isAdvancedLaboratoryWorkId(
export function emptyAdvancedLaboratoryResults(): AdvancedLaboratoryResults {
return {
l3: null,
l31: null,
e31: null,
e32: null,
e33: null,
@@ -169,6 +174,7 @@ export function advancedLaboratoryResultAvailable(
results: AdvancedLaboratoryResults,
): boolean {
return workId === "l3-pointpillars-visual-audit" ? results.l3 !== null
: workId === "l31-pointpillars-ravnoves" ? results.l31 !== null
: workId === "e31-source-binding" ? results.e31 !== null
: workId === "e32-track-geometry" ? results.e32 !== null
: workId === "e33-worker-shadow" ? results.e33 !== null
@@ -193,6 +199,8 @@ export async function fetchAdvancedLaboratoryResult(
const results = emptyAdvancedLaboratoryResults();
if (workId === "l3-pointpillars-visual-audit") {
results.l3 = await fetchL3PointPillarsVisualAudit({ fetcher, signal });
} else if (workId === "l31-pointpillars-ravnoves") {
results.l31 = await fetchL31PointPillarsRavnoves({ fetcher, signal });
} else if (workId === "e31-source-binding") {
results.e31 = await fetchOne(
"/api/v1/laboratory/e31/results?limit=1",
@@ -0,0 +1,27 @@
import type {
E31LaboratoryResult,
E32LaboratoryResult,
E33LaboratoryResult,
E37AcceptanceContractResult,
E38PerceptionBaselineResult,
E39PerceptionRefinementResult,
} from "./advancedResults";
import type { E34TemporalLayerResult } from "./e34TemporalLayer";
import type { E35DegradationRecoveryResult } from "./e35DegradationRecovery";
import type { E40PerceptionProductGateResult } from "./e40ProductGate";
import type { L3PointPillarsVisualAuditResult } from "./l3PointPillarsVisualAudit";
import type { L31PointPillarsRavnovesResult } from "./l31PointPillarsRavnoves";
export interface AdvancedLaboratoryResults {
l3: L3PointPillarsVisualAuditResult | null;
l31: L31PointPillarsRavnovesResult | null;
e31: E31LaboratoryResult | null;
e32: E32LaboratoryResult | null;
e33: E33LaboratoryResult | null;
e34: E34TemporalLayerResult | null;
e35: E35DegradationRecoveryResult | null;
e37: E37AcceptanceContractResult | null;
e38: E38PerceptionBaselineResult | null;
e39: E39PerceptionRefinementResult | null;
e40: E40PerceptionProductGateResult | null;
}
@@ -1,17 +1,15 @@
import {
fetchE34TemporalLayerResult,
type E34TemporalLayerResult,
} from "./e34TemporalLayer";
import {
fetchE35DegradationRecoveryResult,
type E35DegradationRecoveryResult,
} from "./e35DegradationRecovery";
import {
fetchE40ProductGateResult,
type E40PerceptionProductGateResult,
} from "./e40ProductGate";
import { settledCatalogValue } from "./catalogTransport";
import type { L3PointPillarsVisualAuditResult } from "./l3PointPillarsVisualAudit";
import type { AdvancedLaboratoryResults } from "./advancedLaboratoryResults";
export type { AdvancedLaboratoryResults } from "./advancedLaboratoryResults";
export interface E31LaboratoryResult {
resultId: string;
@@ -238,19 +236,6 @@ export interface E39PerceptionRefinementResult {
access: "read-only";
}
export interface AdvancedLaboratoryResults {
l3: L3PointPillarsVisualAuditResult | null;
e31: E31LaboratoryResult | null;
e32: E32LaboratoryResult | null;
e33: E33LaboratoryResult | null;
e34: E34TemporalLayerResult | null;
e35: E35DegradationRecoveryResult | null;
e37: E37AcceptanceContractResult | null;
e38: E38PerceptionBaselineResult | null;
e39: E39PerceptionRefinementResult | null;
e40: E40PerceptionProductGateResult | null;
}
export class AdvancedLaboratoryContractError extends Error {
constructor(message: string) {
super(message);
@@ -990,5 +975,17 @@ export async function fetchAdvancedLaboratoryResults({
const e38 = settledCatalogValue(settled[6]);
const e39 = settledCatalogValue(settled[7]);
const e40 = settledCatalogValue(settled[8]);
return { l3: null, e31, e32, e33, e34, e35, e37, e38, e39, e40 };
return {
l3: null,
l31: null,
e31,
e32,
e33,
e34,
e35,
e37,
e38,
e39,
e40,
};
}
@@ -0,0 +1,475 @@
import {
AdvancedLaboratoryContractError,
type LaboratoryFetch,
} from "./advancedResults";
import type { L3VisualBox } from "./l3PointPillarsVisualAudit";
export interface L31ClassCounts {
Vehicle: number;
Pedestrian: number;
Cyclist: number;
}
export interface L31VisualFrameSummary {
frameId: string;
frameIndex: number;
sessionSeconds: number;
sourcePointCount: number;
predictionCount: number;
classCounts: L31ClassCounts;
inferenceMs: number;
}
export interface L31PointPillarsRavnovesResult {
resultId: string;
createdAtUtc: string;
status: "cross-domain-transfer-measured-visual-review-required";
sourceSessionId: string;
sourcePackId: string;
sourceLogicalContentSha256: string;
model: {
name: "pointpillars";
sourceModelSha256: string;
engineSha256: string;
embeddedScoreThreshold: number;
};
execution: {
workerHostId: "worker-006";
sequential: true;
parallelWorkers: 1;
sourcePaced: false;
existingTritonOnly: true;
};
metrics: {
frameCount: number;
inputAdmissionFraction: number;
outputSchemaValidFraction: number;
framesWithPredictions: number;
framesWithVehiclePredictions: number;
predictionCount: number;
classCounts: L31ClassCounts;
inferenceLatencyMs: { p50: number; p95: number; maximum: number };
poseBindingAgeMs: { p50: number; p95: number; maximum: number };
deterministicReplayFraction: number;
deterministicReplayFrames: number;
};
frames: readonly L31VisualFrameSummary[];
limitations: readonly string[];
}
export interface L31VisualFrame {
frameId: string;
summary: L31VisualFrameSummary & {
deterministicReplay: boolean;
replayInferenceMs: number;
visualBoxCount: number;
visualBoxTruncated: boolean;
};
sourcePointCount: number;
modelRangePointCount: number;
sampledPointCount: number;
pointsXyzi: readonly number[];
truthBoxes: readonly L3VisualBox[];
predictionBoxes: readonly L3VisualBox[];
}
const RESULT_ID = /^l31-pointpillars-ravnoves-[a-f0-9]{64}$/;
const PACK_ID = /^lidar-replay-pack-[a-f0-9]{64}$/;
const SHA256 = /^[a-f0-9]{64}$/;
const FRAME_ID = /^[0-9]{6}$/;
function record(value: unknown, label: string): Record<string, unknown> {
if (!value || typeof value !== "object" || Array.isArray(value)) {
throw new AdvancedLaboratoryContractError(`${label}: ожидался объект.`);
}
return value as Record<string, unknown>;
}
function array(value: unknown, label: string): readonly unknown[] {
if (!Array.isArray(value)) {
throw new AdvancedLaboratoryContractError(`${label}: ожидался массив.`);
}
return value;
}
function string(value: unknown, label: string): string {
if (typeof value !== "string" || !value.trim()) {
throw new AdvancedLaboratoryContractError(`${label}: ожидалась строка.`);
}
return value;
}
function exact<T extends string>(value: unknown, expected: T, label: string): T {
if (value !== expected) {
throw new AdvancedLaboratoryContractError(`${label}: нарушен контракт.`);
}
return expected;
}
function number(value: unknown, label: string, minimum = 0): number {
if (
typeof value !== "number"
|| !Number.isFinite(value)
|| value < minimum
) {
throw new AdvancedLaboratoryContractError(`${label}: неверное число.`);
}
return value;
}
function integer(value: unknown, label: string): number {
const parsed = number(value, label);
if (!Number.isInteger(parsed)) {
throw new AdvancedLaboratoryContractError(`${label}: ожидалось целое.`);
}
return parsed;
}
function boolean(value: unknown, label: string): boolean {
if (typeof value !== "boolean") {
throw new AdvancedLaboratoryContractError(`${label}: ожидался boolean.`);
}
return value;
}
function exactBoolean(
value: unknown,
expected: boolean,
label: string,
): boolean {
const parsed = boolean(value, label);
if (parsed !== expected) {
throw new AdvancedLaboratoryContractError(`${label}: нарушен контракт.`);
}
return parsed;
}
function classCounts(value: unknown, label: string): L31ClassCounts {
const counts = record(value, label);
if (
Object.keys(counts).sort().join(",") !== "Cyclist,Pedestrian,Vehicle"
) {
throw new AdvancedLaboratoryContractError(`${label}: классы изменились.`);
}
return {
Vehicle: integer(counts.Vehicle, `${label}.Vehicle`),
Pedestrian: integer(counts.Pedestrian, `${label}.Pedestrian`),
Cyclist: integer(counts.Cyclist, `${label}.Cyclist`),
};
}
function distribution(
value: unknown,
label: string,
): { p50: number; p95: number; maximum: number } {
const item = record(value, label);
return {
p50: number(item.p50, `${label}.p50`),
p95: number(item.p95, `${label}.p95`),
maximum: number(item.maximum, `${label}.maximum`),
};
}
function parseSummary(value: unknown): L31VisualFrameSummary {
const item = record(value, "L3.1 frame");
const frameId = string(item.frame_id, "L3.1 frame_id");
if (!FRAME_ID.test(frameId)) {
throw new AdvancedLaboratoryContractError("L3.1 frame_id: неверный формат.");
}
return {
frameId,
frameIndex: integer(item.frame_index, "L3.1 frame_index"),
sessionSeconds: number(item.session_seconds, "L3.1 session_seconds"),
sourcePointCount: integer(
item.source_point_count,
"L3.1 source_point_count",
),
predictionCount: integer(
item.prediction_count,
"L3.1 prediction_count",
),
classCounts: classCounts(item.class_counts, "L3.1 class_counts"),
inferenceMs: number(
item.inference_ms,
"L3.1 inference_ms",
Number.MIN_VALUE,
),
};
}
function parseResult(value: unknown): L31PointPillarsRavnovesResult {
const item = record(value, "L3.1 result");
exact(
item.schema_version,
"missioncore.l31-pointpillars-ravnoves-result/v1",
"L3.1 schema_version",
);
exact(item.access, "read-only", "L3.1 access");
const resultId = string(item.result_id, "L3.1 result_id");
const sourcePackId = string(item.source_pack_id, "L3.1 source_pack_id");
const logicalSha = string(
item.source_logical_content_sha256,
"L3.1 logical content",
);
if (
!RESULT_ID.test(resultId)
|| !PACK_ID.test(sourcePackId)
|| !SHA256.test(logicalSha)
) {
throw new AdvancedLaboratoryContractError(
"L3.1: нарушена идентичность результата.",
);
}
const model = record(item.model, "L3.1 model");
const execution = record(item.execution, "L3.1 execution");
const metrics = record(item.metrics, "L3.1 metrics");
const frames = array(item.frames, "L3.1 frames").map(parseSummary);
if (
!frames.length
|| frames.length > 18
|| new Set(frames.map(({ frameId }) => frameId)).size !== frames.length
) {
throw new AdvancedLaboratoryContractError("L3.1 frames: неверный каталог.");
}
return {
resultId,
createdAtUtc: string(item.created_at_utc, "L3.1 created_at_utc"),
status: exact(
item.status,
"cross-domain-transfer-measured-visual-review-required",
"L3.1 status",
),
sourceSessionId: exact(
item.source_session_id,
"20260720T065719Z_viewer_live",
"L3.1 source_session_id",
),
sourcePackId,
sourceLogicalContentSha256: logicalSha,
model: {
name: exact(model.name, "pointpillars", "L3.1 model.name"),
sourceModelSha256: string(
model.source_model_sha256,
"L3.1 model sha",
),
engineSha256: string(model.engine_sha256, "L3.1 engine sha"),
embeddedScoreThreshold: number(
model.embedded_score_threshold,
"L3.1 score threshold",
),
},
execution: {
workerHostId: exact(
execution.worker_host_id,
"worker-006",
"L3.1 worker",
),
sequential: exactBoolean(
execution.sequential,
true,
"L3.1 sequential",
) as true,
parallelWorkers: (
integer(execution.parallel_workers, "L3.1 parallel workers") === 1
? 1
: (() => {
throw new AdvancedLaboratoryContractError(
"L3.1 parallel workers: нарушен контракт.",
);
})()
),
sourcePaced: exactBoolean(
execution.source_paced,
false,
"L3.1 source paced",
) as false,
existingTritonOnly: exactBoolean(
execution.existing_triton_only,
true,
"L3.1 Triton",
) as true,
},
metrics: {
frameCount: integer(metrics.frame_count, "L3.1 frame count"),
inputAdmissionFraction: number(
metrics.input_admission_fraction,
"L3.1 admission",
),
outputSchemaValidFraction: number(
metrics.output_schema_valid_fraction,
"L3.1 schema valid",
),
framesWithPredictions: integer(
metrics.frames_with_predictions,
"L3.1 frames with predictions",
),
framesWithVehiclePredictions: integer(
metrics.frames_with_vehicle_predictions,
"L3.1 frames with vehicles",
),
predictionCount: integer(
metrics.prediction_count,
"L3.1 predictions",
),
classCounts: classCounts(metrics.class_counts, "L3.1 metric classes"),
inferenceLatencyMs: distribution(
metrics.inference_latency_ms,
"L3.1 latency",
),
poseBindingAgeMs: distribution(
metrics.pose_binding_age_ms,
"L3.1 pose age",
),
deterministicReplayFraction: number(
metrics.deterministic_replay_fraction,
"L3.1 determinism",
),
deterministicReplayFrames: integer(
metrics.deterministic_replay_frames,
"L3.1 determinism frames",
),
},
frames,
limitations: array(item.limitations, "L3.1 limitations").map(
(entry) => string(entry, "L3.1 limitation"),
),
};
}
function parseBox(value: unknown): L3VisualBox {
const box = record(value, "L3.1 box");
const center = [
number(box.x_m, "L3.1 box.x", -Infinity),
number(box.y_m, "L3.1 box.y", -Infinity),
number(box.z_m, "L3.1 box.z", -Infinity),
] as const;
const size = [
number(box.length_m, "L3.1 box.length", Number.MIN_VALUE),
number(box.width_m, "L3.1 box.width", Number.MIN_VALUE),
number(box.height_m, "L3.1 box.height", Number.MIN_VALUE),
] as const;
const modelClass = string(box.model_class, "L3.1 box.class");
if (!["Vehicle", "Pedestrian", "Cyclist"].includes(modelClass)) {
throw new AdvancedLaboratoryContractError("L3.1 box.class: неизвестен.");
}
return {
benchmarkClass: modelClass,
centerXyzM: center,
sizeLwhM: size,
yawRad: number(box.yaw_rad, "L3.1 box.yaw", -Infinity),
status: "model-prediction",
score: number(box.score, "L3.1 box.score"),
};
}
export async function fetchL31PointPillarsRavnoves({
fetcher = fetch,
signal,
}: {
fetcher?: LaboratoryFetch;
signal?: AbortSignal;
} = {}): Promise<L31PointPillarsRavnovesResult | null> {
const response = await fetcher(
"/api/v1/laboratory/l31/pointpillars-ravnoves/results?limit=1",
{ method: "GET", headers: { Accept: "application/json" }, signal },
);
if (!response.ok) {
throw new AdvancedLaboratoryContractError(
`L3.1 RAVNOVES недоступен: HTTP ${response.status}.`,
);
}
const catalog = record(await response.json(), "L3.1 catalog");
exact(
catalog.schema_version,
"missioncore.l31-pointpillars-ravnoves-catalog-results/v1",
"L3.1 catalog schema",
);
const items = array(catalog.items, "L3.1 catalog.items");
if (items.length > 1) {
throw new AdvancedLaboratoryContractError("L3.1 catalog: лишние результаты.");
}
return items.length ? parseResult(items[0]) : null;
}
export async function fetchL31PointPillarsRavnovesFrame(
resultId: string,
frameId: string,
{
fetcher = fetch,
signal,
}: {
fetcher?: LaboratoryFetch;
signal?: AbortSignal;
} = {},
): Promise<L31VisualFrame> {
if (!RESULT_ID.test(resultId) || !FRAME_ID.test(frameId)) {
throw new AdvancedLaboratoryContractError("L3.1 frame: неверная identity.");
}
const response = await fetcher(
`/api/v1/laboratory/l31/pointpillars-ravnoves/${resultId}/frames/${frameId}`,
{ method: "GET", headers: { Accept: "application/json" }, signal },
);
if (!response.ok) {
throw new AdvancedLaboratoryContractError(
`L3.1 frame недоступен: HTTP ${response.status}.`,
);
}
const payload = record(await response.json(), "L3.1 visual frame");
exact(
payload.schema_version,
"missioncore.l31-pointpillars-ravnoves-visual-frame/v1",
"L3.1 visual schema",
);
exact(payload.frame_id, frameId, "L3.1 visual frame_id");
const summaryRaw = record(payload.summary, "L3.1 visual summary");
const summary = parseSummary(summaryRaw);
const points = record(payload.points, "L3.1 points");
exact(points.layout, "flat-xyzi", "L3.1 points.layout");
const pointValues = array(points.values, "L3.1 points.values").map(
(entry, index) => number(entry, `L3.1 points[${index}]`, -Infinity),
);
const sampledPointCount = integer(
points.sampled_point_count,
"L3.1 sampled points",
);
if (sampledPointCount > 12_000 || pointValues.length !== sampledPointCount * 4) {
throw new AdvancedLaboratoryContractError("L3.1 points: нарушен bound.");
}
return {
frameId,
summary: {
...summary,
deterministicReplay: boolean(
summaryRaw.deterministic_replay,
"L3.1 deterministic replay",
),
replayInferenceMs: number(
summaryRaw.replay_inference_ms,
"L3.1 replay latency",
),
visualBoxCount: integer(
summaryRaw.visual_box_count,
"L3.1 visual box count",
),
visualBoxTruncated: boolean(
summaryRaw.visual_box_truncated,
"L3.1 visual box truncated",
),
},
sourcePointCount: integer(
points.source_point_count,
"L3.1 source points",
),
modelRangePointCount: integer(
points.model_range_point_count,
"L3.1 model range points",
),
sampledPointCount,
pointsXyzi: pointValues,
truthBoxes: [],
predictionBoxes: array(
payload.prediction_boxes,
"L3.1 prediction boxes",
).map(parseBox),
};
}
@@ -21,7 +21,12 @@ export interface L3VisualBox {
centerXyzM: readonly [number, number, number];
sizeLwhM: readonly [number, number, number];
yawRad: number;
status: "matched" | "false-negative" | "true-positive" | "false-positive";
status:
| "matched"
| "false-negative"
| "true-positive"
| "false-positive"
| "model-prediction";
score: number | null;
}
@@ -131,6 +131,10 @@
background: rgb(var(--nodedc-warning-rgb));
}
.l3-visual-audit__legend span[data-tone="prediction"]::before {
background: rgb(var(--nodedc-accent-rgb));
}
@media (max-width: 900px) {
.l3-visual-audit__overlay {
grid-template-columns: repeat(2, minmax(0, 1fr));
@@ -19,6 +19,7 @@ import { E38Result } from "./E38Result";
import { E39Result } from "./E39Result";
import { E40Result } from "./E40Result";
import { L3PointPillarsResult } from "./L3PointPillarsResult";
import { L31PointPillarsRavnovesResult } from "./L31PointPillarsRavnovesResult";
import { RecordedReplayEvidence } from "./RecordedReplayEvidence";
export { isAdvancedLaboratoryWorkId };
@@ -33,9 +34,13 @@ export function advancedLaboratoryWorkOptions(
): readonly LaboratoryOption<AdvancedLaboratoryWorkId>[] {
const available = new Set(index.map(({ workId }) => workId));
const options: readonly LaboratoryOption<AdvancedLaboratoryWorkId>[] = [
{
id: "l31-pointpillars-ravnoves",
label: "L3.1 · PointPillars на RAVNOVES00",
},
{
id: "l3-pointpillars-visual-audit",
label: "L3 · визуальный аудит PointPillars",
label: "L3 · KITTI · внешний PointPillars benchmark",
},
{ id: "e31-source-binding", label: "LAB E31 · source binding" },
{ id: "e32-track-geometry", label: "LAB E32 · TrackGeometry v1" },
@@ -90,6 +95,9 @@ export function AdvancedLaboratoryResult({
if (workId === "l3-pointpillars-visual-audit" && results.l3) {
return <L3PointPillarsResult result={results.l3} />;
}
if (workId === "l31-pointpillars-ravnoves" && results.l31) {
return <L31PointPillarsRavnovesResult result={results.l31} />;
}
if (workId === "e40-perception-product-gate" && results.e40) {
return <E40Result rigLabel={rigLabel} result={results.e40} />;
}
@@ -0,0 +1,141 @@
import {
LaboratoryEvidence,
LaboratoryResultSummary,
LaboratorySummary,
LaboratoryWorkTemplate,
} from "../../components/laboratory/LaboratoryPresentation";
import type {
L31PointPillarsRavnovesResult,
} from "../../core/laboratory/l31PointPillarsRavnoves";
import { L31PointPillarsRavnovesVisual } from "./L31PointPillarsRavnovesVisual";
function percent(value: number, digits = 1): string {
return `${(value * 100).toLocaleString("ru-RU", {
maximumFractionDigits: digits,
})}%`;
}
export function L31PointPillarsRavnovesResult({
result,
}: {
result: L31PointPillarsRavnovesResult;
}) {
const metrics = result.metrics;
return (
<LaboratoryWorkTemplate
summary={(
<LaboratorySummary
title="L3.1 · PointPillars на RAVNOVES00"
description="Полный последовательный transfer-прогон PointPillars по 4570 реальным LiDAR-кадрам RAVNOVES00. Визуальная производная показывает точки нашего сканера и неподтверждённые боксы модели; внешний KITTI в эту работу не входит."
status="Измерено · требуется визуальная ревизия"
statusTone="warning"
facts={[
{
label: "Источник",
value: `RAVNOVES00 · ${metrics.frameCount.toLocaleString("ru-RU")} кадров`,
},
{
label: "Гипотезы Vehicle",
value: metrics.classCounts.Vehicle.toLocaleString("ru-RU"),
},
{
label: "Исполнение",
value: "Worker 006 · 1 последовательный поток · existing Triton",
},
{
label: "Полномочия",
value: "Shadow-only · accuracy не принята",
},
]}
brief={{
question: "Работает ли текущий LiDAR-native PointPillars на реальном потоке RAVNOVES00 и выглядят ли его объектные гипотезы правдоподобно?",
approach: "Lossless replay RAVNOVES00 проверен по SHA-256, каждая map-frame порция связана с ближайшей pose и переведена обратно в sensor-frame XYZI. Все 4570 кадров последовательно пропущены через неизменённый Triton engine; 18 route-wide кадров повторены и опубликованы в 3D/BEV.",
principalResult: `Вход и выход прошли контракт на ${percent(metrics.inputAdmissionFraction)} кадров; p95 inference ${metrics.inferenceLatencyMs.p95.toLocaleString("ru-RU", { maximumFractionDigits: 2 })} мс. Модель выдала ${metrics.predictionCount.toLocaleString("ru-RU")} гипотез, из них ${metrics.classCounts.Vehicle.toLocaleString("ru-RU")} Vehicle.`,
limitation: "У RAVNOVES00 нет независимых ориентированных 3D truth-боксов. Поэтому здесь нельзя считать accuracy, TP/FP/FN; боксы являются только гипотезами. Повтор 18 кадров совпал лишь частично, что отдельно блокирует эксплуатационный допуск модели.",
}}
method={{
completeness: "complete",
executionClass: "ai-inference",
pipelineId: "l31-pointpillars-ravnoves/transfer-v1",
components: [
{
kind: "source",
name: result.sourcePackId,
version: "lossless LiDAR replay v2",
role: "RAVNOVES00 point-cloud + best-effort pose",
identitySha256: result.sourceLogicalContentSha256,
},
{
kind: "algorithm",
name: "map-frame → sensor-frame XYZI",
version: "nearest pose ≤ 100 ms",
role: "восстановление входной системы координат детектора",
identitySha256: null,
},
{
kind: "model",
name: "NVIDIA PointPillars candidate",
version: result.model.sourceModelSha256,
role: "неизменённый cross-domain LiDAR-native transfer",
identitySha256: result.model.engineSha256,
},
{
kind: "runtime",
name: "Worker 006 canonical Triton",
version: result.resultId,
role: "последовательное shadow-исполнение без команд",
identitySha256: result.resultId.split("-").at(-1) ?? null,
},
],
}}
/>
)}
evidence={(
<LaboratoryEvidence
eyebrow="RAVNOVES00 → ВИЗУАЛЬНОЕ ДОКАЗАТЕЛЬСТВО"
title="Точки сканера и гипотезы PointPillars"
kind="diagnostic-model"
resizable
>
<L31PointPillarsRavnovesVisual result={result} />
</LaboratoryEvidence>
)}
result={(
<LaboratoryResultSummary
title="Runtime-контракт выполнен; модель пока не допущена"
status="Требует доработки"
statusTone="warning"
metrics={[
{
label: "Input admission",
value: percent(metrics.inputAdmissionFraction),
hint: `${metrics.frameCount.toLocaleString("ru-RU")} / ${metrics.frameCount.toLocaleString("ru-RU")} frames`,
},
{
label: "Inference p95",
value: `${metrics.inferenceLatencyMs.p95.toLocaleString("ru-RU", {
maximumFractionDigits: 2,
})} мс`,
hint: `max ${metrics.inferenceLatencyMs.maximum.toLocaleString("ru-RU", { maximumFractionDigits: 2 })} мс`,
},
{
label: "Vehicle hypotheses",
value: metrics.classCounts.Vehicle.toLocaleString("ru-RU"),
hint: `${metrics.framesWithVehiclePredictions.toLocaleString("ru-RU")} кадров с Vehicle`,
},
{
label: "Детерминизм повтора",
value: percent(metrics.deterministicReplayFraction),
hint: `${metrics.deterministicReplayFrames} sealed visual frames`,
},
]}
conclusion={{
proved: "Полный поток RAVNOVES00 принимается текущим PointPillars engine без ошибок контракта; inference на Worker 006 остаётся bounded, а реальные точки сканера и боксы модели доступны для 3D/BEV-проверки.",
notProved: "Не доказаны корректность классов, точность и полнота боксов, пригодность для навигации или safety. Без независимой разметки эти гипотезы нельзя называть детекциями.",
decision: "Сохранить L3.1 как фактический RAVNOVES transfer baseline. Текущий кандидат не подключать к operational detector: сначала разобрать визуальные боксы, причину частичного детерминизма и измерить независимый ground truth на ограниченном наборе.",
}}
/>
)}
/>
);
}
@@ -0,0 +1,178 @@
import { useEffect, useState } from "react";
import { Icon, IconButton, Select } from "@nodedc/ui-react";
import { LaboratoryEvidenceViewer } from "../../components/laboratory/LaboratoryEvidenceViewer";
import {
fetchL31PointPillarsRavnovesFrame,
type L31PointPillarsRavnovesResult,
type L31VisualFrame,
} from "../../core/laboratory/l31PointPillarsRavnoves";
import {
L3PointPillarsScene,
type L3VisualMode,
} from "./L3PointPillarsScene";
function frameLabel(
frame: L31PointPillarsRavnovesResult["frames"][number],
): string {
return (
`${frame.sessionSeconds.toLocaleString("ru-RU", {
maximumFractionDigits: 1,
})} с · кадр ${frame.frameId}`
+ ` · Vehicle ${frame.classCounts.Vehicle}`
);
}
export function L31PointPillarsRavnovesVisual({
result,
}: {
result: L31PointPillarsRavnovesResult;
}) {
const [selectedFrameId, setSelectedFrameId] = useState(
result.frames[0]?.frameId ?? "",
);
const [frame, setFrame] = useState<L31VisualFrame | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const [mode, setMode] = useState<L3VisualMode>("3d");
const [expanded, setExpanded] = useState(false);
useEffect(() => {
if (!selectedFrameId) return;
const controller = new AbortController();
setFrame(null);
setLoading(true);
setError(null);
void fetchL31PointPillarsRavnovesFrame(
result.resultId,
selectedFrameId,
{ signal: controller.signal },
).then((next) => {
if (!controller.signal.aborted) setFrame(next);
}).catch((caught: unknown) => {
if (controller.signal.aborted) return;
setError(
caught instanceof Error
? caught.message
: "Визуальный кадр L3.1 недоступен.",
);
}).finally(() => {
if (!controller.signal.aborted) setLoading(false);
});
return () => controller.abort();
}, [result.resultId, selectedFrameId]);
const selectedIndex = result.frames.findIndex(
({ frameId }) => frameId === selectedFrameId,
);
const navigate = (offset: -1 | 1) => {
if (!result.frames.length || selectedIndex < 0) return;
const index = (
selectedIndex + offset + result.frames.length
) % result.frames.length;
setSelectedFrameId(result.frames[index].frameId);
};
const controls = (
<div className="l3-visual-audit__actions">
<div className="l3-visual-audit__pagination">
<IconButton
label="Предыдущий кадр RAVNOVES00"
onClick={() => navigate(-1)}
>
<Icon name="chevron-left" size={16} />
</IconButton>
<IconButton
label="Следующий кадр RAVNOVES00"
onClick={() => navigate(1)}
>
<Icon name="chevron-right" size={16} />
</IconButton>
</div>
<Select
label="Выбрать кадр L3.1 RAVNOVES00"
value={selectedFrameId}
options={result.frames.map((item) => ({
value: item.frameId,
label: frameLabel(item),
}))}
variant="split"
menuWidth="anchor"
onChange={setSelectedFrameId}
/>
</div>
);
const overlay = frame ? (
<div className="l3-visual-audit__overlay">
<div>
<span>RAVNOVES00</span>
<strong>
{frame.summary.sessionSeconds.toLocaleString("ru-RU", {
maximumFractionDigits: 1,
})} с · кадр {frame.frameId}
</strong>
<small>
{frame.modelRangePointCount.toLocaleString("ru-RU")} из{" "}
{frame.sourcePointCount.toLocaleString("ru-RU")} точек в range модели
</small>
</div>
<div>
<span>Гипотезы модели · не ground truth</span>
<strong>
Vehicle {frame.summary.classCounts.Vehicle}
{" · "}Pedestrian {frame.summary.classCounts.Pedestrian}
{" · "}Cyclist {frame.summary.classCounts.Cyclist}
</strong>
<small>
{frame.summary.inferenceMs.toLocaleString("ru-RU", {
maximumFractionDigits: 2,
})} мс · повтор{" "}
{frame.summary.deterministicReplay ? "совпал" : "не совпал"}
</small>
</div>
<div className="l3-visual-audit__legend">
<span data-tone="prediction">
Бокс · неподтверждённое предсказание PointPillars
</span>
</div>
</div>
) : undefined;
return (
<div className="l3-visual-audit">
<LaboratoryEvidenceViewer
label="PointPillars на RAVNOVES00"
mode={mode}
modes={[
{ value: "3d", label: "3D" },
{ value: "bev", label: "BEV" },
]}
expanded={expanded}
onModeChange={setMode}
onExpandedChange={setExpanded}
actions={controls}
overlay={overlay}
>
{loading ? (
<div className="l3-visual-audit__state" role="status">
<span className="busy-indicator" aria-hidden="true" />
<span>Открываем выбранный кадр RAVNOVES00</span>
</div>
) : error || !frame ? (
<div className="l3-visual-audit__state" role="status">
<Icon name="alert" size={18} />
<span>{error ?? "Визуальный кадр L3.1 недоступен."}</span>
</div>
) : (
<L3PointPillarsScene
frame={frame}
mode={mode}
bevCenterX={0}
bevHalfExtent={55}
/>
)}
</LaboratoryEvidenceViewer>
</div>
);
}
@@ -26,7 +26,7 @@ export function L3PointPillarsResult({
summary={(
<LaboratorySummary
title="L3 · визуальный аудит PointPillars"
description="Визуальная производная полного KITTI transfer-прогона: исходные LiDAR-точки, независимые truth-боксы и предсказания модели сопоставлены тем же глобальным 3D IoU-контрактом. Производная не меняет метрики и не выдает результат за K1 accuracy."
description="Визуальная производная полного KITTI transfer-прогона: исходные LiDAR-точки, независимые truth-боксы и предсказания модели сопоставлены тем же глобальным 3D IoU-контрактом. Производная не меняет метрики и не выдаёт результат за точность целевого сканера."
status="Требуется визуальная проверка"
statusTone="warning"
facts={[
@@ -51,7 +51,7 @@ export function L3PointPillarsResult({
question: "Соответствуют ли измеренные провал переноса и почти сплошная ложная занятость фактической геометрии исходных LiDAR-кадров?",
approach: "Полный sealed run проверен по hash identity. Global score-order matching повторён с исходными порогами IoU, после чего детерминированно выбраны TP-, FP-, FN- и class-coverage кадры. В браузер поступает только выбранный кадр.",
principalResult: `Полный прогон: BEV mAP40 ${percent(metrics.bevMap40)}, 3D mAP40 ${percent(metrics.threeDMap40, 6)}, false occupied ${percent(metrics.falseOccupiedRate)}. Визуальный аудит теперь доступен в 3D и BEV.`,
limitation: "Это cross-domain KITTI probe модели, обученной на proprietary solid-state LiDAR. Он проверяет перенос и корректность измерителя, но не доказывает точность K1, camera-first детектор, навигацию или safety.",
limitation: "Это cross-domain KITTI probe модели, обученной на proprietary solid-state LiDAR. Он проверяет перенос и корректность измерителя, но не доказывает точность целевого сканера, camera-first детектор, навигацию или safety.",
}}
method={{
completeness: "complete",
@@ -131,7 +131,7 @@ export function L3PointPillarsResult({
]}
conclusion={{
proved: "Полный cross-domain прогон воспроизводим, его численные артефакты связаны с исходными LiDAR-кадрами, а TP/FP/FN можно проверить в 3D и BEV без повторного inference.",
notProved: "Не доказаны пригодность этой модели для K1, точность camera-first семантики, метрическая геометрия K1 в других условиях, навигация, команды или safety.",
notProved: "Не доказаны пригодность этой модели для целевого сканера, точность camera-first семантики, метрическая геометрия в других условиях, навигация, команды или safety.",
decision: "Не переносить этот публичный PointPillars-кандидат в operational pipeline. Использовать визуальный аудит для проверки природы провала и сохранить архитектуру camera-first semantics + LiDAR metric geometry как основной продуктовый путь.",
}}
/>
@@ -94,9 +94,16 @@ function addBoxes(
export function L3PointPillarsScene({
frame,
mode,
bevCenterX = 30,
bevHalfExtent = 42,
}: {
frame: L3VisualFrame;
frame: Pick<
L3VisualFrame,
"frameId" | "pointsXyzi" | "truthBoxes" | "predictionBoxes"
>;
mode: L3VisualMode;
bevCenterX?: number;
bevHalfExtent?: number;
}) {
const hostRef = useRef<HTMLDivElement | null>(null);
const [renderError, setRenderError] = useState<string | null>(null);
@@ -138,7 +145,7 @@ export function L3PointPillarsScene({
);
const pointsMaterial = new THREE.PointsMaterial({
color: tokenColor(host, "--nodedc-text-secondary", [187, 190, 196]),
size: mode === "bev" ? 1.4 : 1.8,
size: mode === "bev" ? 2.2 : 1.8,
sizeAttenuation: false,
transparent: true,
opacity: 0.52,
@@ -163,6 +170,11 @@ export function L3PointPillarsScene({
"--nodedc-danger-rgb",
[255, 98, 112],
),
"model-prediction": tokenColor(
host,
"--nodedc-accent-rgb",
[111, 181, 251],
),
};
const truthLines = addBoxes(scene, frame.truthBoxes, colors, 0.9);
const predictionLines = addBoxes(
@@ -190,10 +202,10 @@ export function L3PointPillarsScene({
const perspective = new THREE.PerspectiveCamera(52, 1, 0.1, 500);
perspective.position.set(-12, 18, 36);
const orthographic = new THREE.OrthographicCamera(-40, 40, 40, -40, 0.1, 500);
orthographic.position.set(35, 100, 0);
orthographic.position.set(bevCenterX + 5, 100, 0);
orthographic.up.set(1, 0, 0);
const camera = mode === "bev" ? orthographic : perspective;
camera.lookAt(30, 0, 0);
camera.lookAt(mode === "bev" ? bevCenterX : 30, 0, 0);
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = false;
@@ -201,7 +213,7 @@ export function L3PointPillarsScene({
controls.enablePan = true;
controls.enableZoom = true;
controls.screenSpacePanning = true;
controls.target.set(30, 0, 0);
controls.target.set(mode === "bev" ? bevCenterX : 30, 0, 0);
controls.update();
const render = () => renderer.render(scene, camera);
@@ -214,7 +226,7 @@ export function L3PointPillarsScene({
camera.aspect = width / height;
camera.updateProjectionMatrix();
} else {
const horizontal = 42;
const horizontal = bevHalfExtent;
camera.left = -horizontal;
camera.right = horizontal;
camera.top = horizontal / (width / height);
@@ -242,7 +254,7 @@ export function L3PointPillarsScene({
renderer.dispose();
renderer.domElement.remove();
};
}, [frame, mode]);
}, [bevCenterX, bevHalfExtent, frame, mode]);
return (
<div className="l3-visual-audit__scene" ref={hostRef}>
@@ -44,25 +44,17 @@ import {
advancedLaboratorySourceSession,
advancedLaboratoryWorkOptions,
isAdvancedLaboratoryWorkId,
type AdvancedLaboratoryWorkId,
} from "./AdvancedLaboratoryResult";
import {
e28LaboratoryBrief, e29LaboratoryBrief,
e30LaboratoryBrief, PUBLISHED_LABORATORY_BRIEF,
} from "./laboratoryArchiveBriefs";
import { useAdvancedLaboratoryCatalog } from "./useAdvancedLaboratoryCatalog";
import { buildLaboratoryProfiles, workOptionsForProfile } from "./laboratoryArchiveProfiles";
import type { LaboratoryProfileId, LaboratoryWorkId } from "./laboratoryArchiveProfiles";
type LaboratoryWorkspaceProps = WorkspaceRendererProps & {
SpatialView: ComponentType<WorkspaceRendererProps>;
};
type LaboratoryProfileId = "sensor-fusion" | "published-perception";
type LaboratoryWorkId =
| "e28-local-surface"
| "e29-camera-geometry"
| "e30-evidence-review"
| AdvancedLaboratoryWorkId
| `session:${string}`;
function laboratoryWorkOrdinal(value: string): number {
const match = value.match(/\bE(\d+)\b/i);
return match ? Number(match[1]) : -1;
@@ -667,7 +659,11 @@ export function LaboratoryArchiveWorkspace(props: LaboratoryWorkspaceProps) {
label: "LAB E30 · evidence review A2",
});
}
items.push(...advancedLaboratoryWorkOptions(advanced.index));
items.push(
...advancedLaboratoryWorkOptions(advanced.index).filter(
({ id }) => id !== "l3-pointpillars-visual-audit",
),
);
return items.sort(
(left, right) => laboratoryWorkOrdinal(right.label) - laboratoryWorkOrdinal(left.label),
);
@@ -677,29 +673,28 @@ export function LaboratoryArchiveWorkspace(props: LaboratoryWorkspaceProps) {
e29Result,
e30Result,
]);
const profiles = useMemo(() => {
const items: LaboratoryOption<LaboratoryProfileId>[] = [];
if (sensorWorks.length) {
items.push({
id: "sensor-fusion",
label: `${rigLabel} · камера + LiDAR · control plane`,
});
}
if (publishedWorks.length) {
items.push({
id: "published-perception",
label: `${rigLabel} · опубликованный perception pipeline`,
});
}
return items;
}, [publishedWorks.length, rigLabel, sensorWorks.length]);
const workOptions: readonly LaboratoryOption<LaboratoryWorkId>[] =
profileId === "sensor-fusion"
? sensorWorks
: publishedWorks.map((session) => ({
const publicBenchmarkWorks = useMemo(
() => advancedLaboratoryWorkOptions(advanced.index).filter(
({ id }) => id === "l3-pointpillars-visual-audit",
),
[advanced.index],
);
const profiles = useMemo(
() => buildLaboratoryProfiles({
rigLabel,
sensorAvailable: sensorWorks.length > 0,
publicBenchmarkAvailable: publicBenchmarkWorks.length > 0,
publishedAvailable: publishedWorks.length > 0,
}),
[publicBenchmarkWorks.length, publishedWorks.length, rigLabel, sensorWorks.length],
);
const publishedWorkOptions = publishedWorks.map((session) => ({
id: `session:${session.id}` as const,
label: `${session.lab?.labId ?? "LAB"} · ${laboratorySessionTitle(session)}`,
}));
const workOptions = workOptionsForProfile(
profileId, sensorWorks, publicBenchmarkWorks, publishedWorkOptions,
);
const selectedSessionId = workId.startsWith("session:")
? workId.slice("session:".length)
: null;
@@ -730,6 +725,12 @@ export function LaboratoryArchiveWorkspace(props: LaboratoryWorkspaceProps) {
setWorkId(firstWork.id);
initialWorkSelectedRef.current = true;
}
} else if (firstProfile.id === "public-benchmarks") {
const firstWork = publicBenchmarkWorks[0];
if (firstWork) {
setWorkId(firstWork.id);
initialWorkSelectedRef.current = true;
}
} else {
const first = publishedWorks[0];
if (first) {
@@ -756,6 +757,7 @@ export function LaboratoryArchiveWorkspace(props: LaboratoryWorkspaceProps) {
profileId,
profiles,
publishedWorks,
publicBenchmarkWorks,
sensorWorks,
sessions.state,
workId,
@@ -770,6 +772,11 @@ export function LaboratoryArchiveWorkspace(props: LaboratoryWorkspaceProps) {
if (first) setWorkId(first.id);
return;
}
if (next === "public-benchmarks") {
const first = publicBenchmarkWorks[0];
if (first) setWorkId(first.id);
return;
}
const first = publishedWorks[0];
if (!first) return;
const nextWork = `session:${first.id}` as const;
@@ -0,0 +1,60 @@
import type { LaboratoryOption } from "../../components/laboratory/LaboratoryPresentation";
import type { AdvancedLaboratoryWorkId } from "../../core/laboratory/advancedIndex";
export type LaboratoryProfileId =
| "sensor-fusion"
| "public-benchmarks"
| "published-perception";
export type LaboratoryWorkId =
| "e28-local-surface"
| "e29-camera-geometry"
| "e30-evidence-review"
| AdvancedLaboratoryWorkId
| `session:${string}`;
export function buildLaboratoryProfiles({
rigLabel,
sensorAvailable,
publicBenchmarkAvailable,
publishedAvailable,
}: {
rigLabel: string;
sensorAvailable: boolean;
publicBenchmarkAvailable: boolean;
publishedAvailable: boolean;
}): readonly LaboratoryOption<LaboratoryProfileId>[] {
const profiles: LaboratoryOption<LaboratoryProfileId>[] = [];
if (sensorAvailable) {
profiles.push({
id: "sensor-fusion",
label: `${rigLabel} · камера + LiDAR · control plane`,
});
}
if (publicBenchmarkAvailable) {
profiles.push({
id: "public-benchmarks",
label: "Публичные датасеты · внешний benchmark-контур",
});
}
if (publishedAvailable) {
profiles.push({
id: "published-perception",
label: `${rigLabel} · опубликованный perception pipeline`,
});
}
return profiles;
}
export function workOptionsForProfile(
profileId: LaboratoryProfileId,
sensorWorks: readonly LaboratoryOption<LaboratoryWorkId>[],
publicBenchmarkWorks: readonly LaboratoryOption<LaboratoryWorkId>[],
publishedWorks: readonly LaboratoryOption<LaboratoryWorkId>[],
): readonly LaboratoryOption<LaboratoryWorkId>[] {
return profileId === "sensor-fusion"
? sensorWorks
: profileId === "public-benchmarks"
? publicBenchmarkWorks
: publishedWorks;
}
@@ -19,6 +19,7 @@ function mergeResults(
): AdvancedLaboratoryResults {
return {
l3: next.l3 ?? current.l3,
l31: next.l31 ?? current.l31,
e31: next.e31 ?? current.e31,
e32: next.e32 ?? current.e32,
e33: next.e33 ?? current.e33,
@@ -58,6 +58,18 @@ const l3SceneUrl = new URL(
"../src/workspaces/laboratory/L3PointPillarsScene.tsx",
import.meta.url,
);
const l31ResultUrl = new URL(
"../src/workspaces/laboratory/L31PointPillarsRavnovesResult.tsx",
import.meta.url,
);
const l31VisualUrl = new URL(
"../src/workspaces/laboratory/L31PointPillarsRavnovesVisual.tsx",
import.meta.url,
);
const laboratoryProfilesUrl = new URL(
"../src/workspaces/laboratory/laboratoryArchiveProfiles.ts",
import.meta.url,
);
const e35StylesUrl = new URL(
"../src/styles/e35-degradation-recovery.css",
import.meta.url,
@@ -190,6 +202,28 @@ test("L3 visual audit binds the sealed metrics to one lazy 3D/BEV viewer", async
assert.match(advanced, /<L3PointPillarsResult/);
});
test("L3.1 keeps RAVNOVES evidence primary and KITTI in a public benchmark profile", async () => {
const [result, visual, scene, profiles, advanced] = await Promise.all([
readFile(l31ResultUrl, "utf8"),
readFile(l31VisualUrl, "utf8"),
readFile(l3SceneUrl, "utf8"),
readFile(laboratoryProfilesUrl, "utf8"),
readFile(advancedLaboratoryResultUrl, "utf8"),
]);
assert.match(result, /L3\.1 · PointPillars на RAVNOVES00/);
assert.match(result, /внешний KITTI в эту работу не входит/);
assert.match(result, /боксы являются только гипотезами/);
assert.match(visual, /fetchL31PointPillarsRavnovesFrame/);
assert.match(visual, /bevCenterX=\{0\}/);
assert.match(visual, /bevHalfExtent=\{55\}/);
assert.match(scene, /bevCenterX = 30/);
assert.match(profiles, /"public-benchmarks"/);
assert.match(profiles, /Публичные датасеты · внешний benchmark-контур/);
assert.match(advanced, /id: "l31-pointpillars-ravnoves"/);
assert.match(advanced, /<L31PointPillarsRavnovesResult/);
});
test("E33 explains the experiment, its method and its retained limits", async () => {
const [presentationSource, e33Source] = await Promise.all([
readFile(presentationSourceUrl, "utf8"),