feat(perception): integrate vegetation policy review

This commit is contained in:
DCCONSTRUCTIONS
2026-08-28 11:22:00 +03:00
parent 30080c51aa
commit c4c2392c79
17 changed files with 2388 additions and 105 deletions
@@ -55,7 +55,9 @@ export interface VegetationVideoSemanticClass {
classId: number;
label: string;
colorRgb: readonly [number, number, number];
disposition: "prediction" | "undefined";
disposition: "labeled" | "ambiguous" | "prediction" | "undefined";
materialClass: string | null;
evidenceState: string | null;
}
export interface VegetationRouteVideo {
@@ -67,8 +69,12 @@ export interface VegetationRouteVideo {
height: 600;
centerCropXyxy: readonly [100, 0, 700, 600];
outsideCropState: "undefined";
viewKind: "fine-semantic-prediction" | "coarse-material-policy-review";
linkedTgsResultId: string | null;
taxonomy: readonly VegetationVideoSemanticClass[];
aggregatePredictionPixels: readonly number[];
policyPresets: Readonly<Record<string, Readonly<Record<string, string>>>> | null;
fusionMode: "synchronised-multilayer-review" | null;
}
export interface VegetationShadowResult {
@@ -257,6 +263,9 @@ function routeVideoValue(value: unknown): VegetationRouteVideo | null {
"vegetation.route_video.m47_reference_graph_result_id",
);
const baseM4ResultId = textValue(row.base_m4_result_id, "vegetation.route_video.base_m4_result_id");
const viewKind = row.view_kind === undefined
? "fine-semantic-prediction"
: textValue(row.view_kind, "vegetation.route_video.view_kind");
if (
!/^lab-v1-ravnoves-video-ddrnet-[a-f0-9]{64}$/.test(workerResultId)
|| !/^m47-reference-graph-lab-[a-f0-9]{64}$/.test(m47ReferenceGraphResultId)
@@ -264,6 +273,15 @@ function routeVideoValue(value: unknown): VegetationRouteVideo | null {
) {
throw new VegetationShadowContractError("vegetation.route_video: identity invalid.");
}
if (viewKind !== "fine-semantic-prediction" && viewKind !== "coarse-material-policy-review") {
throw new VegetationShadowContractError("vegetation.route_video: view kind invalid.");
}
const linkedTgsResultId = viewKind === "coarse-material-policy-review"
? textValue(row.linked_tgs_result_id, "vegetation.route_video.linked_tgs_result_id")
: null;
if (linkedTgsResultId && !/^m49-tgs-full-shadow-[a-f0-9]{64}$/.test(linkedTgsResultId)) {
throw new VegetationShadowContractError("vegetation.route_video: TGS identity invalid.");
}
exact(row.frame_count, 4489, "vegetation.route_video.frame_count");
exact(row.width, 800, "vegetation.route_video.width");
exact(row.height, 600, "vegetation.route_video.height");
@@ -279,11 +297,9 @@ function routeVideoValue(value: unknown): VegetationRouteVideo | null {
throw new VegetationShadowContractError("vegetation.route_video: crop contract changed.");
}
const taxonomy = objectValue(row.taxonomy, "vegetation.route_video.taxonomy");
exact(
taxonomy.schema_version,
"missioncore.lab-v1-vegetation-taxonomy/v1",
"vegetation.route_video.taxonomy.schema",
);
exact(taxonomy.schema_version, viewKind === "coarse-material-policy-review"
? "missioncore.lab-v1-terrain-policy-taxonomy/v1"
: "missioncore.lab-v1-vegetation-taxonomy/v1", "vegetation.route_video.taxonomy.schema");
const classes = arrayValue(taxonomy.classes, "vegetation.route_video.taxonomy.classes")
.map((value, expectedId): VegetationVideoSemanticClass => {
const item = objectValue(value, `vegetation.route_video.taxonomy[${expectedId}]`);
@@ -296,36 +312,78 @@ function routeVideoValue(value: unknown): VegetationRouteVideo | null {
if (color.length !== 3 || color.some((channel) => channel > 255)) {
throw new VegetationShadowContractError("vegetation.route_video: taxonomy color invalid.");
}
const disposition: VegetationVideoSemanticClass["disposition"] = expectedId === 0
? "undefined"
: "prediction";
if (item.disposition !== disposition) {
const disposition = item.disposition;
if (
disposition !== "labeled"
&& disposition !== "ambiguous"
&& disposition !== "prediction"
&& disposition !== "undefined"
) {
throw new VegetationShadowContractError("vegetation.route_video: taxonomy disposition changed.");
}
if (
viewKind === "fine-semantic-prediction"
&& disposition !== (expectedId === 0 ? "undefined" : "prediction")
) {
throw new VegetationShadowContractError("vegetation.route_video: fine taxonomy disposition changed.");
}
const materialClass = item.material_class === null || item.material_class === undefined
? null
: textValue(item.material_class, `vegetation.route_video.material[${expectedId}]`);
const evidenceState = item.evidence_state === null || item.evidence_state === undefined
? null
: textValue(item.evidence_state, `vegetation.route_video.evidence[${expectedId}]`);
return {
classId,
label: textValue(item.label, `vegetation.route_video.label[${expectedId}]`),
colorRgb: color as unknown as readonly [number, number, number],
disposition,
materialClass,
evidenceState,
};
});
if (classes.length !== 64) {
throw new VegetationShadowContractError("vegetation.route_video: taxonomy must contain 64 classes.");
const expectedClassCount = viewKind === "coarse-material-policy-review" ? 9 : 64;
if (classes.length !== expectedClassCount) {
throw new VegetationShadowContractError("vegetation.route_video: taxonomy size changed.");
}
const aggregatePredictionPixels = arrayValue(
row.aggregate_prediction_pixels,
"vegetation.route_video.aggregate_prediction_pixels",
).map((value, index) => integerValue(value, `vegetation.route_video.pixels[${index}]`));
if (aggregatePredictionPixels.length !== 64) {
if (aggregatePredictionPixels.length !== expectedClassCount) {
throw new VegetationShadowContractError("vegetation.route_video: class accounting changed.");
}
const maskArchive = objectValue(row.mask_archive, "vegetation.route_video.mask_archive");
exact(maskArchive.path, "video/ddrnet-semantic-masks.zip", "vegetation.route_video.mask_archive.path");
exact(maskArchive.path, viewKind === "coarse-material-policy-review"
? "video/coarse-material-policy-masks.zip"
: "video/ddrnet-semantic-masks.zip", "vegetation.route_video.mask_archive.path");
const archiveSha256 = textValue(maskArchive.sha256, "vegetation.route_video.mask_archive.sha256");
if (!SHA256.test(archiveSha256)) {
throw new VegetationShadowContractError("vegetation.route_video: archive digest invalid.");
}
integerValue(maskArchive.byte_length, "vegetation.route_video.mask_archive.byte_length");
let policyPresets: VegetationRouteVideo["policyPresets"] = null;
let fusionMode: VegetationRouteVideo["fusionMode"] = null;
if (viewKind === "coarse-material-policy-review") {
const policy = objectValue(row.policy, "vegetation.route_video.policy");
const presets = objectValue(policy.presets, "vegetation.route_video.policy.presets");
policyPresets = Object.fromEntries(Object.entries(presets).map(([presetId, rawRules]) => {
const rules = objectValue(rawRules, `vegetation.route_video.policy.${presetId}`);
return [presetId, Object.fromEntries(Object.entries(rules).map(([material, action]) => [
material,
textValue(action, `vegetation.route_video.policy.${presetId}.${material}`),
]))];
}));
const fusion = objectValue(row.fusion, "vegetation.route_video.fusion");
exact(fusion.pixel_raster_fusion, false, "vegetation.route_video.fusion.pixel_raster_fusion");
exact(fusion.camera_semantic_temporal_filter, "none", "vegetation.route_video.fusion.camera_filter");
exact(
fusion.mode,
"synchronised-multilayer-review",
"vegetation.route_video.fusion.mode",
);
fusionMode = "synchronised-multilayer-review";
}
return {
workerResultId,
m47ReferenceGraphResultId,
@@ -335,8 +393,12 @@ function routeVideoValue(value: unknown): VegetationRouteVideo | null {
height: 600,
centerCropXyxy: [100, 0, 700, 600],
outsideCropState: "undefined",
viewKind,
linkedTgsResultId,
taxonomy: classes,
aggregatePredictionPixels,
policyPresets,
fusionMode,
};
}
@@ -22,6 +22,7 @@ import {
import {
M4ReplayThreatVisual,
type M4ReplayClassifiedSpatialFrame,
type M4ReplayThreatSemanticLayer,
} from "./M4ReplayThreatVisual";
const CLASSES: readonly RecordedEvidenceSemanticClass[] = [
@@ -42,7 +43,15 @@ function message(error: unknown): string {
: "Полный TGS spatial frame недоступен.";
}
export function M49TgsFullShadowEvidence({ result }: { result: M49TgsFullShadowResult }) {
export function M49TgsFullShadowEvidence({
result,
semanticOverride,
evidenceLabel = "M49 · full TGS shadow",
}: {
result: M49TgsFullShadowResult;
semanticOverride?: M4ReplayThreatSemanticLayer;
evidenceLabel?: string;
}) {
const [activeSequence, setActiveSequence] = useState<number | null>(null);
const [semantic, setSemantic] = useState<E47SemanticSlamResult | null>(null);
const [semanticError, setSemanticError] = useState<string | null>(null);
@@ -62,6 +71,7 @@ export function M49TgsFullShadowEvidence({ result }: { result: M49TgsFullShadowR
const controller = new AbortController();
setSemantic(null);
setSemanticError(null);
if (semanticOverride) return () => controller.abort();
void fetchE47SemanticSlamResult({
resultId: result.source.linkedSemanticResultId,
signal: controller.signal,
@@ -77,7 +87,7 @@ export function M49TgsFullShadowEvidence({ result }: { result: M49TgsFullShadowR
if (!controller.signal.aborted) setSemanticError(message(caught));
});
return () => controller.abort();
}, [result.source.linkedSemanticResultId, result.source.linkedVisualResultId]);
}, [result.source.linkedSemanticResultId, result.source.linkedVisualResultId, semanticOverride]);
useEffect(() => {
const controller = new AbortController();
@@ -196,13 +206,13 @@ export function M49TgsFullShadowEvidence({ result }: { result: M49TgsFullShadowR
<>
<M4ReplayThreatVisual
resultId={result.source.linkedVisualResultId}
semantic={semantic ? {
semantic={semanticOverride ?? (semantic ? {
resultId: semantic.resultId,
taxonomy: semantic.taxonomy,
} : undefined}
} : undefined)}
showReviewAnchorBoxes={false}
reviewLabel="4 489 source-paced TGS frames"
evidenceLabel="M49 · full TGS shadow"
evidenceLabel={evidenceLabel}
initialSpatialMode="3d"
onActiveSequenceChange={handleSequenceChange}
classifiedSpatialLayer={{
@@ -217,7 +227,7 @@ export function M49TgsFullShadowEvidence({ result }: { result: M49TgsFullShadowR
replacePointCloud: false,
}}
/>
{semanticError ? (
{!semanticOverride && semanticError ? (
<div className="m4-replay-threat-visual__pane-status" role="alert">
Semantic overlay недоступен: {semanticError}
</div>
@@ -378,12 +378,12 @@ export function M4ReplayThreatVisual({
);
}, [frame, metadata.timeline, showReferenceMediaLayers, showStaticObstacles]);
const activeBoxes = useMemo(
() => classifiedSpatialLayer || !showReferenceMediaLayers ? [] : [
() => !showReferenceMediaLayers ? [] : [
...boxes(frame?.cameraProposals ?? []),
...staticObstacleBoxes,
...reviewAnchorBoxes,
],
[classifiedSpatialLayer, frame, reviewAnchorBoxes, showReferenceMediaLayers, staticObstacleBoxes],
[frame, reviewAnchorBoxes, showReferenceMediaLayers, staticObstacleBoxes],
);
const semanticClasses = useMemo<readonly RecordedEvidenceSemanticClass[]>(
() => semantic?.taxonomy.map((item) => ({
@@ -1,3 +1,5 @@
import { useEffect, useState } from "react";
import {
LaboratoryEvidence,
LaboratoryResultSummary,
@@ -8,11 +10,16 @@ import {
vegetationVideoMaskUrl,
type VegetationShadowResult,
} from "../../core/laboratory/vegetationShadow";
import {
fetchM49TgsFullShadowResult,
type M49TgsFullShadowResult,
} from "../../core/laboratory/m49TgsFullShadow";
import {
M48MaskComparisonVisual,
type M48MaskComparisonCase,
} from "./M48FailureAtlasVisual";
import { M4ReplayThreatVisual } from "./M4ReplayThreatVisual";
import { M49TgsFullShadowEvidence } from "./M49TgsFullShadowEvidence";
function decimal(value: number, digits = 1): string {
return value.toLocaleString("ru-RU", { maximumFractionDigits: digits });
@@ -49,6 +56,75 @@ function comparisonCases(result: VegetationShadowResult): readonly M48MaskCompar
});
}
function VegetationRouteEvidence({ result }: { result: VegetationShadowResult }) {
const route = result.routeVideo!;
const [tgs, setTgs] = useState<M49TgsFullShadowResult | null>(null);
const [tgsError, setTgsError] = useState<string | null>(null);
useEffect(() => {
const controller = new AbortController();
setTgs(null);
setTgsError(null);
if (!route.linkedTgsResultId) return () => controller.abort();
void fetchM49TgsFullShadowResult(route.linkedTgsResultId, {
signal: controller.signal,
}).then((next) => {
if (controller.signal.aborted) return;
if (next.source.linkedVisualResultId !== route.baseM4ResultId) {
throw new Error("TGS и camera timeline имеют разные source identities.");
}
setTgs(next);
}).catch((caught: unknown) => {
if (!controller.signal.aborted) {
setTgsError(caught instanceof Error ? caught.message : "Sealed TGS недоступен.");
}
});
return () => controller.abort();
}, [route.baseM4ResultId, route.linkedTgsResultId]);
const semantic = {
resultId: route.workerResultId,
spatialResultId: null,
taxonomy: route.taxonomy,
maskUrl: (sequence: number) => vegetationVideoMaskUrl(result.resultId, sequence),
label: route.viewKind === "coarse-material-policy-review"
? "Coarse material evidence · recorded video"
: "DDRNet vegetation prediction · recorded video",
maskAriaLabel: route.viewKind === "coarse-material-policy-review"
? "Coarse material policy evidence"
: "DDRNet vegetation prediction",
} as const;
if (route.linkedTgsResultId && tgs) {
return (
<M49TgsFullShadowEvidence
result={tgs}
semanticOverride={semantic}
evidenceLabel="LAB V1 · MATERIAL + YOLOX + TGS"
/>
);
}
if (route.linkedTgsResultId && !tgsError) {
return <div className="m4-replay-threat-visual__pane-status" role="status">Открываем sealed TGS и coarse material timeline</div>;
}
return (
<>
<M4ReplayThreatVisual
resultId={route.baseM4ResultId}
evidenceLabel="LAB V1 · DDRNet"
showReferenceMediaLayers={route.viewKind === "coarse-material-policy-review"}
showSpatialOverlaySummary={false}
semantic={semantic}
/>
{tgsError ? (
<div className="m4-replay-threat-visual__pane-status" role="alert">
TGS слой недоступен: {tgsError}
</div>
) : null}
</>
);
}
export function VegetationShadowResultView({
rigLabel,
result,
@@ -68,10 +144,14 @@ export function VegetationShadowResultView({
<LaboratorySummary
title="LAB V1 · готовые модели растительности"
description={result.routeVideo
? "M4.8 сохраняет truth-backed сравнение моделей, а штатный M4.7 viewer показывает фактический DDRNet prediction на всей записи RAVNOVES00. Все 4489 масок запечатаны локально и открываются без Worker 006."
? result.routeVideo.viewKind === "coarse-material-policy-review"
? "M4.8 сохраняет truth-backed сравнение моделей, а штатный M4.7 синхронно показывает coarse material evidence, frozen YOLOX vetoes и causal TGS на всей записи RAVNOVES00. Все слои запечатаны локально и открываются без Worker 006."
: "M4.8 сохраняет truth-backed сравнение моделей, а штатный M4.7 viewer показывает фактический DDRNet prediction на всей записи RAVNOVES00. Все 4489 масок запечатаны локально и открываются без Worker 006."
: "Штатный M4.8-инструмент сравнивает две готовые fine-64 модели на полном GOOSE validation split и на 12 truth-backed hard cases, выбранных только по наличию нужной растительности. Sealed evidence открывается локально без Worker 006."}
status={result.routeVideo
? "DDRNet full-video prediction ready · route truth отсутствует"
? result.routeVideo.viewKind === "coarse-material-policy-review"
? "MULTILAYER POLICY REVIEW · commands OFF · route truth отсутствует"
: "DDRNet full-video prediction ready · route truth отсутствует"
: "Truth-backed model comparison · route transfer не принят"}
statusTone="warning"
facts={[
@@ -80,15 +160,17 @@ export function VegetationShadowResultView({
{ label: "Кейсы", value: "трава · куст · ствол · крона · изгородь · лес · посевы" },
...(result.routeVideo ? [{
label: "Видео",
value: "RAVNOVES00 · 4489/4489 DDRNet masks · exact recorded sequence",
value: result.routeVideo.viewKind === "coarse-material-policy-review"
? "RAVNOVES00 · 4489/4489 coarse masks + YOLOX + TGS · exact sequence"
: "RAVNOVES00 · 4489/4489 DDRNet masks · exact recorded sequence",
}] : []),
{ label: "Authority", value: `${rigLabel} · MODEL QUALIFICATION ONLY · commands OFF` },
]}
brief={{
question: "Какие готовые веса лучше различают проезжаемую траву, кусты и стволы на размеченных off-road кадрах?",
approach: "Обе модели последовательно прогнаны в одном изолированном CUDA-runtime на 962 кадрах. 12 визуальных кейсов выбраны детерминированно по truth-поддержке восьми растительных классов; один M4.8 viewer показывает source, truth, prediction и material-error для выбранной модели.",
principalResult: `${selected.loadedModelName} лидирует по vegetation IoU: ${decimal(selected.vegetationMeanIouPercent, 2)}% против ${decimal(alternative.vegetationMeanIouPercent, 2)}%. ${result.routeVideo ? "Его фактическая temporal stability теперь видна на всех 4489 кадрах штатного recorded viewer." : "Ошибки по каждому типу проверяются в одном штатном инструменте."}`,
limitation: "GOOSE — внешний размеченный домен; RAVNOVES00 — наш fisheye, но без ручной truth-разметки. Full-video слой показывает prediction, а не доказывает правильность. Папоротник отдельным классом отсутствует.",
principalResult: `${selected.loadedModelName} лидирует по vegetation IoU: ${decimal(selected.vegetationMeanIouPercent, 2)}% против ${decimal(alternative.vegetationMeanIouPercent, 2)}%. ${result.routeVideo?.viewKind === "coarse-material-policy-review" ? "Fine-64 prediction сведён к mission-neutral материалам; YOLOX и TGS сохраняют независимое veto." : result.routeVideo ? "Его фактическая temporal stability теперь видна на всех 4489 кадрах штатного recorded viewer." : "Ошибки по каждому типу проверяются в одном штатном инструменте."}`,
limitation: "GOOSE — внешний размеченный домен; RAVNOVES00 — наш fisheye, но без ручной truth-разметки. Материалы — prediction, а не доказательство проходимости. TGS не проецируется в пиксели без отдельной принятой калибровки.",
}}
method={{
completeness: "complete",
@@ -120,32 +202,25 @@ export function VegetationShadowResultView({
{result.routeVideo ? (
<LaboratoryEvidence
eyebrow="M4.7 · RAVNOVES00 FULL VIDEO"
title="DDRNet PREDICTION · 4489/4489 кадров · TRUTH для этой записи отсутствует"
title={result.routeVideo.viewKind === "coarse-material-policy-review"
? "COARSE MATERIAL + YOLOX VETO + CAUSAL TGS · 4489/4489 · TRUTH отсутствует"
: "DDRNet PREDICTION · 4489/4489 кадров · TRUTH для этой записи отсутствует"}
kind="diagnostic-model"
resizable
>
<M4ReplayThreatVisual
resultId={result.routeVideo.baseM4ResultId}
evidenceLabel="LAB V1 · DDRNet"
showReferenceMediaLayers={false}
showSpatialOverlaySummary={false}
semantic={{
resultId: result.routeVideo.workerResultId,
spatialResultId: null,
taxonomy: result.routeVideo.taxonomy,
maskUrl: (sequence) => vegetationVideoMaskUrl(result.resultId, sequence),
label: "DDRNet vegetation prediction · recorded video",
maskAriaLabel: "DDRNet vegetation prediction",
}}
/>
<VegetationRouteEvidence result={result} />
</LaboratoryEvidence>
) : null}
</>
)}
result={(
<LaboratoryResultSummary
title="DDRNet — стартовые веса; перенос на ровер ещё не доказан"
status={`${selected.loadedModelName} выбран только как vegetation candidate`}
title={result.routeVideo?.viewKind === "coarse-material-policy-review"
? "Слои собраны для визуального policy review; управление не авторизовано"
: "DDRNet — стартовые веса; перенос на ровер ещё не доказан"}
status={result.routeVideo?.viewKind === "coarse-material-policy-review"
? "Materials are advisory · YOLOX/TGS veto cannot be cleared"
: `${selected.loadedModelName} выбран только как vegetation candidate`}
statusTone="warning"
metrics={[
{
@@ -186,13 +261,17 @@ export function VegetationShadowResultView({
...(result.routeVideo ? [{
label: "Route video",
value: "4489/4489 masks",
hint: "DDRNet prediction · exact sequence · Worker-independent playback",
hint: result.routeVideo.viewKind === "coarse-material-policy-review"
? "9 coarse states · YOLOX + causal TGS · Worker-independent playback"
: "DDRNet prediction · exact sequence · Worker-independent playback",
}] : []),
]}
conclusion={{
proved: "Обе официальные fine-64 модели воспроизводимо запускаются на Worker 006; DDRNet лучше по aggregate vegetation IoU. Truth-backed hard cases прямо показывают траву, кусты и стволы, а не случайные автомобили и здания.",
notProved: "Не доказаны accuracy на нашем fisheye-домене, папоротник как отдельный материал, collision safety и physical-live поведение ровера. Видео позволяет увидеть temporal stability, но без truth не превращает её в метрику качества.",
decision: "Смотреть полный prediction на видео и собирать конкретные temporal/domain failure cases. DDRNet остаётся diagnostic candidate; LiDAR/TGS fail-closed геометрию не ослаблять.",
decision: result.routeVideo?.viewKind === "coarse-material-policy-review"
? "На одном M4.7 проверить ложные LOW GRASS/HIGH GRASS кандидаты против YOLOX и TGS. До truth-кейсов и integrated load этот слой не подключать к planner/actuation."
: "Смотреть полный prediction на видео и собирать конкретные temporal/domain failure cases. DDRNet остаётся diagnostic candidate; LiDAR/TGS fail-closed геометрию не ослаблять.",
}}
/>
)}
@@ -108,7 +108,9 @@ test("M4.9T5 viewer prefers autonomous chunks and keeps a sealed legacy fallback
assert.doesNotMatch(source, /centersXyM\.map\(/);
assert.match(source, /fetchE47SemanticSlamResult/);
assert.match(source, /next\.baseM4ResultId !== result\.source\.linkedVisualResultId/);
assert.match(source, /semantic=\{semantic \? \{/);
assert.match(source, /semantic=\{semanticOverride \?\? \(semantic \? \{/);
assert.match(source, /semanticOverride/);
assert.doesNotMatch(visual, /classifiedSpatialLayer \|\| !showReferenceMediaLayers \? \[\]/);
assert.match(
visual,
/classifiedSpatialFrame\s*&&\s*classifiedSpatialFrame\.sampleAvailable !== false/,
@@ -104,45 +104,89 @@ function routeVideo() {
};
}
function coarseRouteVideo() {
return {
...routeVideo(),
view_kind: "coarse-material-policy-review",
linked_tgs_result_id: `m49-tgs-full-shadow-${"2".repeat(64)}`,
taxonomy: {
schema_version: "missioncore.lab-v1-terrain-policy-taxonomy/v1",
classes: Array.from({ length: 9 }, (_, classId) => ({
class_id: classId,
label: `policy-${classId}`,
color_rgb: [classId, classId, classId],
disposition: classId === 0 ? "ambiguous" : "prediction",
material_class: classId === 0 ? null : "grass",
evidence_state: classId === 0 ? "UNOBSERVED" : "SUPPORTED_GROUND",
})),
},
aggregate_prediction_pixels: Array(9).fill(0),
mask_archive: {
path: "video/coarse-material-policy-masks.zip",
sha256: "8".repeat(64),
byte_length: 2048,
},
policy: {
presets: {
urban: { grass: "NO_GO" },
rural: { grass: "HIGH_COST" },
offroad: { grass: "HIGH_COST" },
},
},
fusion: {
mode: "synchronised-multilayer-review",
pixel_raster_fusion: false,
camera_semantic_temporal_filter: "none",
},
};
}
function labPayload(route = routeVideo()) {
return {
schema_version: "missioncore.lab-v1-vegetation-shadow/v1",
result_id: resultId,
created_at_utc: "2026-08-27T20:00:00Z",
status: "visual-shadow-ready-policy-not-authorized",
ground_truth: false,
identity: { selected_candidate: "ddrnet" },
metrics: {
candidates: {
ddrnet: candidate("ddrnet", 0.64),
ppliteseg: candidate("ppliteseg", 0.61),
},
},
decision: {
selected_candidate: "ddrnet",
visual_shadow_ready: true,
mission_policy_ready_for_configuration: true,
navigation_accepted: false,
production_accepted: false,
},
limitations: ["shadow only"],
authority: {
commands_enabled: false,
navigation_or_safety_accepted: false,
actuation_accepted: false,
camera_semantics_can_clear_rigid_geometry: false,
},
catalogs: {
goose: Array.from({ length: 12 }, (_, index) => visualCase("goose", index)),
ravnoves: [],
},
route_video: route,
access: "read-only",
};
}
test("vegetation LAB keeps autonomous assets and fail-closed authority", async () => {
let requestedUrl = "";
const result = await fetchVegetationShadowResult(resultId, {
fetcher: async (url) => {
requestedUrl = String(url);
return new Response(JSON.stringify({
schema_version: "missioncore.lab-v1-vegetation-shadow/v1",
result_id: resultId,
created_at_utc: "2026-08-27T20:00:00Z",
status: "visual-shadow-ready-policy-not-authorized",
ground_truth: false,
identity: { selected_candidate: "ddrnet" },
metrics: {
candidates: {
ddrnet: candidate("ddrnet", 0.64),
ppliteseg: candidate("ppliteseg", 0.61),
},
},
decision: {
selected_candidate: "ddrnet",
visual_shadow_ready: true,
mission_policy_ready_for_configuration: true,
navigation_accepted: false,
production_accepted: false,
},
limitations: ["shadow only"],
authority: {
commands_enabled: false,
navigation_or_safety_accepted: false,
actuation_accepted: false,
camera_semantics_can_clear_rigid_geometry: false,
},
catalogs: {
goose: Array.from({ length: 12 }, (_, index) => visualCase("goose", index)),
ravnoves: [],
},
route_video: routeVideo(),
access: "read-only",
}), { status: 200, headers: { "Content-Type": "application/json" } });
return new Response(JSON.stringify(labPayload()), {
status: 200,
headers: { "Content-Type": "application/json" },
});
},
});
assert.equal(
@@ -154,6 +198,8 @@ test("vegetation LAB keeps autonomous assets and fail-closed authority", async (
assert.equal(result.routeCases.length, 0);
assert.equal(result.validationCases.length, 12);
assert.equal(result.routeVideo.frameCount, 4489);
assert.equal(result.routeVideo.viewKind, "fine-semantic-prediction");
assert.equal(result.routeVideo.linkedTgsResultId, null);
assert.equal(result.routeVideo.taxonomy[0].disposition, "undefined");
assert.equal(result.validationCases[0].focus.className, "high_grass");
assert.match(result.validationCases[0].assets.ddrnet_error, /\/assets\/visual\/goose\//);
@@ -165,6 +211,21 @@ test("vegetation LAB keeps autonomous assets and fail-closed authority", async (
});
});
test("vegetation LAB parses coarse material policy and sealed TGS binding", async () => {
const result = await fetchVegetationShadowResult(resultId, {
fetcher: async () => new Response(JSON.stringify(labPayload(coarseRouteVideo())), {
status: 200,
headers: { "Content-Type": "application/json" },
}),
});
assert.equal(result.routeVideo.viewKind, "coarse-material-policy-review");
assert.match(result.routeVideo.linkedTgsResultId, /^m49-tgs-full-shadow-/);
assert.equal(result.routeVideo.taxonomy.length, 9);
assert.equal(result.routeVideo.taxonomy[0].evidenceState, "UNOBSERVED");
assert.equal(result.routeVideo.policyPresets.urban.grass, "NO_GO");
assert.equal(result.routeVideo.fusionMode, "synchronised-multilayer-review");
});
test("vegetation LAB reuses the admitted M4.8 and M4.7 instruments", async () => {
const resultSource = await readFile(
new URL("../src/workspaces/laboratory/VegetationShadowResult.tsx", import.meta.url),
@@ -172,8 +233,10 @@ test("vegetation LAB reuses the admitted M4.8 and M4.7 instruments", async () =>
);
assert.match(resultSource, /M48MaskComparisonVisual/);
assert.match(resultSource, /M4ReplayThreatVisual/);
assert.match(resultSource, /M49TgsFullShadowEvidence/);
assert.match(resultSource, /semanticOverride/);
assert.equal(resultSource.match(/<LaboratoryEvidence\b/g)?.length, 2);
assert.match(resultSource, /showReferenceMediaLayers=\{false\}/);
assert.match(resultSource, /linkedTgsResultId/);
assert.doesNotMatch(resultSource, /VegetationRouteVisual|urban\/rural\/off-road presets/);
await assert.rejects(
access(new URL("../src/workspaces/laboratory/VegetationShadowVisual.tsx", import.meta.url)),