feat(lab): seal full RAVNOVES004TREE semantic review

This commit is contained in:
DCCONSTRUCTIONS
2026-08-29 13:37:57 +03:00
parent 24b65926fe
commit 9dec37a8a9
12 changed files with 1494 additions and 30 deletions
@@ -106,6 +106,39 @@ export interface VegetationMixedRouteReview {
cases: readonly VegetationMixedRouteCase[];
}
export interface VegetationFullRouteLayer {
name: string;
resultId: string;
frameCount: 6830;
taxonomy: readonly VegetationVideoSemanticClass[];
inferenceFps: number;
latencyP95Ms: number;
peakReservedVramBytes: number;
}
export interface VegetationFullRouteReview {
sourceId: "RAVNOVES004TREE";
sessionId: "20260828T130511Z_viewer_live";
sourceJobId: "recorded-camera-eb2783c5480d56bda07c8af0";
sourceJobInputSha256: string;
sourceStreamSha256: string;
recordedMediaSourceId: "recorded.camera.6a3945242828a038";
recordedMediaGenerationSha256: string;
frameCount: 6830;
width: 800;
height: 600;
timelineStartSeconds: number;
timelineEndSeconds: number;
frameSourceTimesNs: readonly number[];
decodeRepair: {
repairedFrameCount: 1;
sequence: 6092;
method: "duplicate-previous-decoded-frame";
};
city: VegetationFullRouteLayer;
vegetation: VegetationFullRouteLayer;
}
export interface VegetationShadowResult {
resultId: string;
createdAtUtc: string;
@@ -116,6 +149,7 @@ export interface VegetationShadowResult {
validationCases: readonly VegetationVisualCase[];
routeVideo: VegetationRouteVideo | null;
routeReview: VegetationMixedRouteReview | null;
routeFullReview: VegetationFullRouteReview | null;
limitations: readonly string[];
visualShadowReady: true;
missionPolicyReadyForConfiguration: true;
@@ -545,6 +579,246 @@ function mixedRouteReviewValue(
};
}
function fullRouteTaxonomyValue(
value: unknown,
label: string,
schema: string,
classCount: number,
): readonly VegetationVideoSemanticClass[] {
const taxonomy = objectValue(value, `${label}.taxonomy`);
exact(taxonomy.schema_version, schema, `${label}.taxonomy.schema`);
const classes = arrayValue(taxonomy.classes, `${label}.taxonomy.classes`).map(
(raw, expectedId): VegetationVideoSemanticClass => {
const item = objectValue(raw, `${label}.taxonomy[${expectedId}]`);
const classId = integerValue(item.class_id, `${label}.class_id[${expectedId}]`);
if (classId !== expectedId) {
throw new VegetationShadowContractError(`${label}: taxonomy order changed.`);
}
const color = arrayValue(item.color_rgb, `${label}.color[${expectedId}]`)
.map((channel, index) => integerValue(channel, `${label}.color[${expectedId}][${index}]`));
if (color.length !== 3 || color.some((channel) => channel > 255)) {
throw new VegetationShadowContractError(`${label}: taxonomy color invalid.`);
}
const disposition = item.disposition;
if (
disposition !== "labeled"
&& disposition !== "ambiguous"
&& disposition !== "prediction"
&& disposition !== "undefined"
) {
throw new VegetationShadowContractError(`${label}: taxonomy disposition changed.`);
}
return {
classId,
label: textValue(item.label, `${label}.label[${expectedId}]`),
colorRgb: color as unknown as readonly [number, number, number],
disposition,
materialClass: item.material_class === null || item.material_class === undefined
? null
: textValue(item.material_class, `${label}.material[${expectedId}]`),
evidenceState: item.evidence_state === null || item.evidence_state === undefined
? null
: textValue(item.evidence_state, `${label}.evidence[${expectedId}]`),
};
},
);
if (classes.length !== classCount) {
throw new VegetationShadowContractError(`${label}: taxonomy size changed.`);
}
return classes;
}
function fullRouteLayerValue(
value: unknown,
layer: "city" | "vegetation",
): VegetationFullRouteLayer {
const label = `vegetation.route_full_review.layers.${layer}`;
const row = objectValue(value, label);
const resultId = textValue(row.result_id, `${label}.result_id`);
const identity = layer === "city"
? /^result-[a-f0-9]{64}$/
: /^lab-v1-ravnoves-video-ddrnet-[a-f0-9]{64}$/;
if (!identity.test(resultId)) {
throw new VegetationShadowContractError(`${label}: identity invalid.`);
}
exact(row.frame_count, 6830, `${label}.frame_count`);
const archive = objectValue(row.mask_archive, `${label}.mask_archive`);
exact(
archive.path,
layer === "city" ? "video/eomt-semantic-masks.zip" : "video/ddrnet-semantic-masks.zip",
`${label}.mask_archive.path`,
);
const digest = textValue(archive.sha256, `${label}.mask_archive.sha256`);
if (!SHA256.test(digest)) {
throw new VegetationShadowContractError(`${label}: archive digest invalid.`);
}
integerValue(archive.byte_length, `${label}.mask_archive.byte_length`);
return {
name: textValue(row.name, `${label}.name`),
resultId,
frameCount: 6830,
taxonomy: fullRouteTaxonomyValue(
row.taxonomy,
label,
layer === "city"
? "missioncore.recorded-eomt-taxonomy/v1"
: "missioncore.lab-v1-vegetation-taxonomy/v1",
layer === "city" ? 16 : 64,
),
inferenceFps: numberValue(row.inference_fps, `${label}.inference_fps`),
latencyP95Ms: numberValue(row.latency_p95_ms, `${label}.latency_p95_ms`),
peakReservedVramBytes: integerValue(
row.peak_reserved_vram_bytes,
`${label}.peak_reserved_vram_bytes`,
),
};
}
function fullRouteReviewValue(value: unknown): VegetationFullRouteReview | null {
if (value === null || value === undefined) return null;
const row = objectValue(value, "vegetation.route_full_review");
exact(row.source_id, "RAVNOVES004TREE", "vegetation.route_full_review.source_id");
exact(
row.session_id,
"20260828T130511Z_viewer_live",
"vegetation.route_full_review.session_id",
);
exact(
row.source_job_id,
"recorded-camera-eb2783c5480d56bda07c8af0",
"vegetation.route_full_review.source_job_id",
);
exact(row.frame_count, 6830, "vegetation.route_full_review.frame_count");
exact(row.width, 800, "vegetation.route_full_review.width");
exact(row.height, 600, "vegetation.route_full_review.height");
exact(row.ground_truth, false, "vegetation.route_full_review.ground_truth");
const sourceJobInputSha256 = textValue(
row.source_job_input_sha256,
"vegetation.route_full_review.source_job_input_sha256",
);
const sourceStreamSha256 = textValue(
row.source_stream_sha256,
"vegetation.route_full_review.source_stream_sha256",
);
exact(
sourceJobInputSha256,
"eb2783c5480d56bda07c8af008dff5344d19dc550ef70fe2075d6f098f7cc715",
"vegetation.route_full_review.source_job_input_sha256",
);
exact(
sourceStreamSha256,
"e5eb017e2cc0f546736eda5235ca157b501913093cb64af5e548e335417e1bac",
"vegetation.route_full_review.source_stream_sha256",
);
exact(
row.recorded_media_source_id,
"recorded.camera.6a3945242828a038",
"vegetation.route_full_review.recorded_media_source_id",
);
const recordedMediaGenerationSha256 = textValue(
row.recorded_media_generation_sha256,
"vegetation.route_full_review.recorded_media_generation_sha256",
);
exact(
recordedMediaGenerationSha256,
"b073ea1e7babf1c77a664e1a5b95e3702d0e05b0e34c1e85a7c67a6f8b392ded",
"vegetation.route_full_review.recorded_media_generation_sha256",
);
if (
!SHA256.test(sourceJobInputSha256)
|| !SHA256.test(sourceStreamSha256)
|| !SHA256.test(recordedMediaGenerationSha256)
) {
throw new VegetationShadowContractError("vegetation.route_full_review: source digest invalid.");
}
const timelineStartSeconds = numberValue(
row.timeline_start_seconds,
"vegetation.route_full_review.timeline_start_seconds",
);
const timelineEndSeconds = numberValue(
row.timeline_end_seconds,
"vegetation.route_full_review.timeline_end_seconds",
);
if (timelineEndSeconds <= timelineStartSeconds) {
throw new VegetationShadowContractError("vegetation.route_full_review: timeline invalid.");
}
const frameSourceTimesNs = arrayValue(
row.frame_source_times_ns,
"vegetation.route_full_review.frame_source_times_ns",
).map((raw, index) => {
const time = integerValue(raw, `vegetation.route_full_review.frame_source_times_ns[${index}]`);
if (!Number.isSafeInteger(time)) {
throw new VegetationShadowContractError("vegetation.route_full_review: unsafe frame time.");
}
return time;
});
if (
frameSourceTimesNs.length !== 6830
|| frameSourceTimesNs.some((time, index) => index > 0 && time <= frameSourceTimesNs[index - 1]!)
) {
throw new VegetationShadowContractError("vegetation.route_full_review: frame timeline changed.");
}
const decodeRepair = objectValue(
row.decode_repair,
"vegetation.route_full_review.decode_repair",
);
exact(decodeRepair.repaired_frame_count, 1, "vegetation.route_full_review.decode_repair.count");
exact(decodeRepair.sequence, 6092, "vegetation.route_full_review.decode_repair.sequence");
exact(
decodeRepair.method,
"duplicate-previous-decoded-frame",
"vegetation.route_full_review.decode_repair.method",
);
const repairProofs = objectValue(
decodeRepair.proofs,
"vegetation.route_full_review.decode_repair.proofs",
);
for (const [key, expectedPath] of Object.entries({
eomt: "proofs/decode_repair.json",
ddrnet: "proofs/ddrnet_decode_repair.json",
})) {
const proof = objectValue(
repairProofs[key],
`vegetation.route_full_review.decode_repair.proofs.${key}`,
);
exact(
proof.path,
expectedPath,
`vegetation.route_full_review.decode_repair.proofs.${key}.path`,
);
const digest = textValue(
proof.sha256,
`vegetation.route_full_review.decode_repair.proofs.${key}.sha256`,
);
if (!SHA256.test(digest)) {
throw new VegetationShadowContractError("vegetation.route_full_review: repair proof invalid.");
}
}
const layers = objectValue(row.layers, "vegetation.route_full_review.layers");
return {
sourceId: "RAVNOVES004TREE",
sessionId: "20260828T130511Z_viewer_live",
sourceJobId: "recorded-camera-eb2783c5480d56bda07c8af0",
sourceJobInputSha256,
sourceStreamSha256,
recordedMediaSourceId: "recorded.camera.6a3945242828a038",
recordedMediaGenerationSha256,
frameCount: 6830,
width: 800,
height: 600,
timelineStartSeconds,
timelineEndSeconds,
frameSourceTimesNs,
decodeRepair: {
repairedFrameCount: 1,
sequence: 6092,
method: "duplicate-previous-decoded-frame",
},
city: fullRouteLayerValue(layers.city, "city"),
vegetation: fullRouteLayerValue(layers.vegetation, "vegetation"),
};
}
function parseResult(
value: unknown,
resultId: string,
@@ -589,9 +863,10 @@ function parseResult(
const validationCases = arrayValue(catalogs.goose, "vegetation.catalogs.goose")
.map((item) => visualCaseValue(item, resultId, "goose", endpointRoot));
const routeReview = mixedRouteReviewValue(payload.route_review, resultId, endpointRoot);
const routeFullReview = fullRouteReviewValue(payload.route_full_review);
if (
routeCases.length !== 0
|| (routeReview ? validationCases.length !== 0 : validationCases.length !== 12)
|| (routeReview || routeFullReview ? validationCases.length !== 0 : validationCases.length !== 12)
) {
throw new VegetationShadowContractError("vegetation.catalogs: ожидалось 12 truth-backed GOOSE случаев без route viewer.");
}
@@ -605,6 +880,7 @@ function parseResult(
validationCases,
routeVideo: routeVideoValue(payload.route_video),
routeReview,
routeFullReview,
limitations: arrayValue(payload.limitations, "vegetation.limitations")
.map((item, index) => textValue(item, `vegetation.limitations[${index}]`)),
visualShadowReady: true,
@@ -625,6 +901,23 @@ export function vegetationVideoMaskUrl(resultId: string, sequence: number): stri
return `/api/v1/laboratory/vegetation-shadow/${encodeURIComponent(resultId)}/masks/${sequence}`;
}
export function vegetationFullRouteMaskUrl(
resultId: string,
layer: "city" | "vegetation",
sequence: number,
): string {
if (
!RESULT_ID.test(resultId)
|| (layer !== "city" && layer !== "vegetation")
|| !Number.isInteger(sequence)
|| sequence < 0
|| sequence >= 6830
) {
throw new VegetationShadowContractError("Vegetation full-route mask identity недопустима.");
}
return `/api/v1/laboratory/vegetation-shadow/${encodeURIComponent(resultId)}/route-masks/${layer}/${sequence}`;
}
export async function fetchVegetationShadowResult(
resultId: string,
{
@@ -1,7 +1,8 @@
import { useEffect, useState } from "react";
import { useEffect, useMemo, useState } from "react";
import { Icon, IconButton, StatusBadge } from "@nodedc/ui-react";
import { LaboratoryEvidenceViewer } from "../../components/laboratory/LaboratoryEvidenceViewer";
import { LaboratoryRecordedClipPlayer } from "../../components/laboratory/LaboratoryRecordedClipPlayer";
import {
LaboratoryEvidence,
LaboratoryResultSummary,
@@ -9,10 +10,21 @@ import {
LaboratoryWorkTemplate,
} from "../../components/laboratory/LaboratoryPresentation";
import {
RecordedEvidenceSemanticMaskOverlay,
type RecordedEvidenceSemanticClass,
type RecordedEvidenceSemanticPaletteEntry,
} from "../../components/laboratory/RecordedEvidenceSemanticMaskOverlay";
import {
vegetationFullRouteMaskUrl,
vegetationVideoMaskUrl,
type VegetationFullRouteLayer,
type VegetationFullRouteReview,
type VegetationMixedRouteReview,
type VegetationShadowResult,
} from "../../core/laboratory/vegetationShadow";
import { recordedObservationSources } from "../../core/observation/recordedObservationSources";
import { resolveObservationSessionReplay } from "../../core/observation/useObservationSessions";
import type { ObservationSourceDescriptor } from "../../core/runtime/contracts";
import {
fetchM49TgsFullShadowResult,
type M49TgsFullShadowResult,
@@ -31,6 +43,217 @@ const MIXED_ROUTE_MODES = [
{ value: "tgs", label: "TGS" },
] as const;
const FULL_ROUTE_MODES = [
{ value: "source", label: "SOURCE" },
{ value: "city", label: "ГОРОД · EoMT" },
{ value: "vegetation", label: "ПРИРОДА · DDRNet" },
] as const;
function semanticPresentation(layer: VegetationFullRouteLayer): {
classes: readonly RecordedEvidenceSemanticClass[];
palette: readonly RecordedEvidenceSemanticPaletteEntry[];
} {
return {
classes: layer.taxonomy.map((item) => ({ id: item.classId, label: item.label })),
palette: layer.taxonomy.map((item) => ({
classId: item.classId,
color: item.classId === 0
? { kind: "transparent" as const }
: { kind: "diagnostic" as const, rgb: item.colorRgb },
})),
};
}
function FullRouteReviewEvidence({
resultId,
review,
}: {
resultId: string;
review: VegetationFullRouteReview;
}) {
const [sequence, setSequence] = useState(1);
const [playing, setPlaying] = useState(false);
const [playbackRate, setPlaybackRate] = useState(1);
const [mode, setMode] = useState<typeof FULL_ROUTE_MODES[number]["value"]>("vegetation");
const [expanded, setExpanded] = useState(false);
const [videoSource, setVideoSource] = useState<ObservationSourceDescriptor | null>(null);
const [videoError, setVideoError] = useState<string | null>(null);
const frames = useMemo(
() => review.frameSourceTimesNs.map((sourceTimeNs, index) => ({
sequence: index + 1,
sourceTimeNs,
})),
[review.frameSourceTimesNs],
);
const layer = mode === "source" ? null : review[mode];
const semantic = useMemo(() => layer ? semanticPresentation(layer) : null, [layer]);
const maskSequence = sequence - 1;
const prefetchSrcs = useMemo(() => layer
? Array.from({ length: 8 }, (_, offset) => maskSequence + offset + 1)
.filter((candidate) => candidate < review.frameCount)
.map((candidate) => vegetationFullRouteMaskUrl(resultId, mode as "city" | "vegetation", candidate))
: [], [layer, maskSequence, mode, resultId, review.frameCount]);
useEffect(() => {
const controller = new AbortController();
setVideoSource(null);
setVideoError(null);
void resolveObservationSessionReplay(review.sessionId, { signal: controller.signal })
.then((launch) => {
const source = recordedObservationSources(launch).find((candidate) => (
candidate.id === review.recordedMediaSourceId
&& candidate.modality === "video"
&& candidate.semanticChannelId === "camera.video.recorded"
&& candidate.delivery?.kind === "recorded-fmp4-manifest"
&& candidate.delivery.manifestGenerationSha256 === review.recordedMediaGenerationSha256
&& candidate.delivery.timelineStartSeconds === review.timelineStartSeconds
&& candidate.delivery.timelineEndSeconds >= review.timelineEndSeconds
));
if (!source) {
throw new Error("RIGHT-видео не совпало с sealed RAVNOVES004TREE timeline.");
}
if (!controller.signal.aborted) setVideoSource(source);
})
.catch((caught: unknown) => {
if (!controller.signal.aborted) {
setVideoError(caught instanceof Error ? caught.message : "Записанное видео недоступно.");
}
});
return () => controller.abort();
}, [
review.recordedMediaGenerationSha256,
review.recordedMediaSourceId,
review.sessionId,
review.timelineEndSeconds,
review.timelineStartSeconds,
]);
return (
<LaboratoryEvidenceViewer
label="RAVNOVES004TREE full recorded review"
className="m48-atlas-visual"
mode={mode}
modes={FULL_ROUTE_MODES}
expanded={expanded}
onModeChange={setMode}
onExpandedChange={setExpanded}
chromeLayout="stacked"
>
{videoSource ? (
<LaboratoryRecordedClipPlayer
source={videoSource}
segmentCount={review.frameCount}
frames={frames}
sequence={sequence}
playing={playing}
playbackRate={playbackRate}
cameraPresentation="primary"
continuousPlayback
sourceCount={1}
onSequenceChange={setSequence}
onPlayingChange={setPlaying}
onPlaybackRateChange={setPlaybackRate}
cameraOverlay={(
<>
<div className="m48-clip-player__pane-label" data-pane="camera">
{mode === "source" ? "SOURCE" : `${mode === "city" ? "EoMT CITY" : "DDRNet NATURE"} · КАДР ${sequence}/${review.frameCount}`}
</div>
{layer && semantic ? (
<RecordedEvidenceSemanticMaskOverlay
src={vegetationFullRouteMaskUrl(resultId, mode as "city" | "vegetation", maskSequence)}
prefetchSrcs={prefetchSrcs}
imageWidth={review.width}
imageHeight={review.height}
classes={semantic.classes}
palette={semantic.palette}
opacity={0.76}
ariaLabel={`${layer.name} semantic prediction`}
/>
) : null}
</>
)}
/>
) : (
<div className="m4-replay-threat-visual__pane-status" role={videoError ? "alert" : "status"}>
{videoError ?? "Открываем автономный recorded source…"}
</div>
)}
</LaboratoryEvidenceViewer>
);
}
function FullRouteReviewResult({
rigLabel,
resultId,
review,
}: {
rigLabel: string;
resultId: string;
review: VegetationFullRouteReview;
}) {
return (
<LaboratoryWorkTemplate
summary={(
<LaboratorySummary
title="LAB V1 · RAVNOVES004TREE · полный маршрут"
description="Существующий M4.7-шаблон воспроизводит всю запись и переключает два независимых sealed semantic-слоя: городской EoMT и природный DDRNet. Worker для открытия результата не нужен."
status="FULL RECORDED REVIEW · truth отсутствует · commands OFF"
statusTone="warning"
facts={[
{ label: "Источник", value: `${review.sourceId} · ${review.frameCount}/${review.frameCount} frames` },
{ label: "Город", value: `${review.city.name} · ${decimal(review.city.inferenceFps, 2)} fps` },
{ label: "Природа", value: `${review.vegetation.name} · ${decimal(review.vegetation.inferenceFps, 2)} fps` },
{ label: "Authority", value: `${rigLabel} · VISUAL REVIEW ONLY · commands OFF` },
]}
brief={{
question: "Как оба semantic-кандидата ведут себя на полном переходе от сельской среды к городской?",
approach: "Все 6830 позиции одной recorded timeline последовательно прогнаны на Worker 006 и сохранены двумя независимыми архивами масок. В M4.7 переключается только видимый слой.",
principalResult: "Полная временная шкала доступна локально в SOURCE / EoMT CITY / DDRNet NATURE без обращения к Worker.",
limitation: "Ручной truth отсутствует. Один повреждённый H.264-пакет на позиции 6092 представлен предыдущим декодированным кадром и явно зафиксирован в proof. Полный TGS и кюветы этим прогоном не проверялись.",
}}
method={{
completeness: "complete",
executionClass: "ai-inference",
pipelineId: "ravnoves004tree-full-eomt-ddrnet-recorded-review/v1",
components: [
{ kind: "model", name: review.city.name, version: "sealed Worker 006 run", role: "urban semantic review", identitySha256: null },
{ kind: "model", name: review.vegetation.name, version: "GOOSE DDRNet-39", role: "vegetation semantic review", identitySha256: null },
],
}}
/>
)}
evidence={(
<LaboratoryEvidence
eyebrow="M4.7 TEMPLATE · RAVNOVES004TREE FULL VIDEO"
title="SOURCE / EoMT CITY / DDRNet NATURE · 6830/6830 · TRUTH отсутствует"
kind="diagnostic-model"
resizable
>
<FullRouteReviewEvidence resultId={resultId} review={review} />
</LaboratoryEvidence>
)}
result={(
<LaboratoryResultSummary
title="Полный двухслойный visual review собран; управление не авторизовано"
status="Recorded evidence ready · navigation/actuation OFF"
statusTone="warning"
metrics={[
{ label: "Route masks", value: "6830/6830 × 2", hint: "sealed local archives · Worker не требуется" },
{ label: "EoMT p95", value: `${decimal(review.city.latencyP95Ms, 2)} ms`, hint: "последовательный изолированный прогон" },
{ label: "DDRNet p95", value: `${decimal(review.vegetation.latencyP95Ms, 2)} ms`, hint: "последовательный изолированный прогон" },
{ label: "Decode repair", value: "1/6830", hint: "sequence 6092 · previous frame · sealed proof" },
]}
conclusion={{
proved: "Городской EoMT и природный DDRNet воспроизводимо обработали полную запись и доступны в одном существующем M4.7 viewer.",
notProved: "Не доказаны truth accuracy, одновременный realtime-load, полный TGS, отрицательные препятствия и безопасное управление ровером.",
decision: "Использовать результат только как визуальную диагностику. Navigation/actuation оставить OFF; следующий gate — оценка временной стабильности и независимый person/vehicle STOP.",
}}
/>
)}
/>
);
}
function MixedRouteReviewEvidence({ review }: { review: VegetationMixedRouteReview }) {
const [index, setIndex] = useState(0);
const [mode, setMode] = useState<typeof MIXED_ROUTE_MODES[number]["value"]>("vegetation");
@@ -224,6 +447,15 @@ export function VegetationShadowResultView({
rigLabel: string;
result: VegetationShadowResult;
}) {
if (result.routeFullReview) {
return (
<FullRouteReviewResult
rigLabel={rigLabel}
resultId={result.resultId}
review={result.routeFullReview}
/>
);
}
if (result.routeReview) {
return <MixedRouteReviewResult rigLabel={rigLabel} review={result.routeReview} />;
}