fix(m4): retain compact obstacle evidence
This commit is contained in:
@@ -26,7 +26,7 @@ export function M4ReplayThreatResultView({
|
||||
<LaboratorySummary
|
||||
title="M4.6 · dual-evidence threat replay"
|
||||
description="Camera и LiDAR дают независимые доказательства, после чего один source-neutral слой оценивает пересечение виртуального коридора, ближайшее сближение и TTC. Ни один сенсор не назначен first."
|
||||
status="4489/4489 · replay-simulated · accepted"
|
||||
status="Replay contract passed · CV quality gate open"
|
||||
statusTone="warning"
|
||||
facts={[
|
||||
{
|
||||
@@ -53,7 +53,7 @@ export function M4ReplayThreatResultView({
|
||||
brief={{
|
||||
question: "Может ли единый слой обнаруживать потенциальное препятствие по двум независимым источникам, не теряя LiDAR-only объекты и не объявляя camera-only наблюдение безопасным?",
|
||||
approach: "Все 4489 кадров RAVNOVES00 повторно пропущены через неизменяемые detector, metric geometry и temporal ledgers. Текущий lio_pcl increment хранится отдельно от bounded rolling map: отсутствие повторной публикации точки не считается свободным пространством. Виртуальный base_footprint привязан к gravity-оси SLAM map и направлению сглаженной траектории, проверенному camera extrinsic.",
|
||||
principalResult: `${metrics.evidence.currentMetric.toLocaleString("ru-RU")} current metric, ${metrics.evidence.rollingMapRetained.toLocaleString("ru-RU")} rolling-map и ${metrics.evidence.cameraOnly.toLocaleString("ru-RU")} camera-only публикаций учтены. Кадр 1880 удерживает обе видимые бетонные полусферы; критические fixtures: ${metrics.fixtures.passed}/${metrics.fixtures.total}, ложных safe: ${metrics.fixtures.criticalFalseNotThreat}.`,
|
||||
principalResult: `${metrics.evidence.currentMetric.toLocaleString("ru-RU")} current metric, ${metrics.evidence.rollingMapRetained.toLocaleString("ru-RU")} rolling-map и ${metrics.evidence.cameraOnly.toLocaleString("ru-RU")} camera-only публикаций учтены. Кадры 1880 и 2584 закрепляют компактные бетонные полусферы как автоматические метрические регрессии; критические fixtures: ${metrics.fixtures.passed}/${metrics.fixtures.total}, ложных safe: ${metrics.fixtures.criticalFalseNotThreat}.`,
|
||||
limitation: "Корпус и коридор пока виртуальные, replay не является live-проходом или физическим collision test. На машине виртуальная привязка должна замениться измеренным rigid T_body_from_sensor; independent object truth остаётся следующим gate.",
|
||||
}}
|
||||
method={{
|
||||
@@ -105,8 +105,8 @@ export function M4ReplayThreatResultView({
|
||||
)}
|
||||
result={(
|
||||
<LaboratoryResultSummary
|
||||
title="Dual-evidence слой готов к следующей CV-итерации на recorded replay"
|
||||
status="Replay gate accepted · physical authority withheld"
|
||||
title="Replay-инфраструктура принята; object recall ещё проверяется"
|
||||
status="Жёлтый: pipeline целостен, независимый object-truth gate не пройден"
|
||||
statusTone="warning"
|
||||
metrics={[
|
||||
{
|
||||
@@ -131,7 +131,7 @@ export function M4ReplayThreatResultView({
|
||||
},
|
||||
]}
|
||||
conclusion={{
|
||||
proved: `На неизменяемом RAVNOVES00 каждый current, rolling-map, stale/held и camera-only объект получил ровно одну консервативную оценку. CURRENT INCREMENT и ROLLING MAP независимо включаются в viewer; кадр 1880 закреплён как регрессия двух бетонных полусфер. ${metrics.bodyFrame.qualified}/${metrics.bodyFrame.available} body frames квалифицированы без переноса handheld roll/pitch на SLAM-мир.`,
|
||||
proved: `На неизменяемом RAVNOVES00 каждый current, rolling-map, stale/held и camera-only объект получил ровно одну консервативную оценку. CURRENT INCREMENT и ROLLING MAP независимо включаются в viewer; кадры 1880 и 2584 закреплены как регрессии компактных бетонных полусфер. ${metrics.bodyFrame.qualified}/${metrics.bodyFrame.available} body frames квалифицированы без переноса handheld roll/pitch на SLAM-мир.`,
|
||||
notProved: "Не доказаны live realtime, измеренный T_body_from_sensor и геометрия физического корпуса, независимая object-level правильность, навигационная или safety-пригодность и выдача команд.",
|
||||
decision: "Сохранить dual-evidence provider как канонический replay seam и переходить к независимому object-centric gate; физическую геометрию и live/actuation authority не смешивать с дальнейшей CV-разработкой.",
|
||||
}}
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
type LaboratoryMetricSceneMode,
|
||||
} from "../../components/laboratory/LaboratoryMetricEvidenceScene";
|
||||
import { LaboratoryEvidenceViewer } from "../../components/laboratory/LaboratoryEvidenceViewer";
|
||||
import { RecordedEvidenceImageScene } from "../../components/laboratory/RecordedEvidenceImageScene";
|
||||
import {
|
||||
RecordedEvidenceVideoScene,
|
||||
type RecordedEvidenceBox,
|
||||
@@ -108,7 +109,7 @@ export function M4ReplayThreatVisual({ resultId }: { resultId: string }) {
|
||||
}, [ordinal, resultId]);
|
||||
|
||||
useEffect(() => {
|
||||
if ((mode !== "video" && mode !== "camera") || (videoOverlay && videoSource)) return;
|
||||
if (mode !== "video" || (videoOverlay && videoSource)) return;
|
||||
const controller = new AbortController();
|
||||
setVideoLoading(true);
|
||||
setVideoError(null);
|
||||
@@ -157,14 +158,6 @@ export function M4ReplayThreatVisual({ resultId }: { resultId: string }) {
|
||||
return () => controller.abort();
|
||||
}, [mode, resultId, videoOverlay, videoSource]);
|
||||
|
||||
useEffect(() => {
|
||||
if (mode !== "camera" || !frame) return;
|
||||
setVideoPlayback({
|
||||
currentSeconds: frame.sourceTimeNs / 1_000_000_000,
|
||||
playing: false,
|
||||
});
|
||||
}, [frame, mode]);
|
||||
|
||||
const activeVideoFrame = useMemo(
|
||||
() => videoOverlay
|
||||
? selectM4ThreatVideoFrame(videoOverlay.frames, videoPlayback.currentSeconds)
|
||||
@@ -317,7 +310,7 @@ export function M4ReplayThreatVisual({ resultId }: { resultId: string }) {
|
||||
) : undefined;
|
||||
|
||||
let content;
|
||||
if (mode === "video" || mode === "camera") {
|
||||
if (mode === "video") {
|
||||
content = videoLoading ? (
|
||||
<div className="l3-visual-audit__state" role="status">
|
||||
<span className="busy-indicator" aria-hidden="true" />
|
||||
@@ -335,14 +328,30 @@ export function M4ReplayThreatVisual({ resultId }: { resultId: string }) {
|
||||
imageWidth={videoOverlay.imageWidth}
|
||||
imageHeight={videoOverlay.imageHeight}
|
||||
boxes={activeBoxes}
|
||||
ariaLabel={
|
||||
mode === "camera"
|
||||
? `M4.6 exact camera sample ${ordinal}: ${activeBoxes.length} proposals`
|
||||
: `M4.6 full video frame ${activeVideoFrame?.frameIndex ?? 0}: ${activeBoxes.length} proposals`
|
||||
}
|
||||
ariaLabel={`M4.6 full video frame ${activeVideoFrame?.frameIndex ?? 0}: ${activeBoxes.length} proposals`}
|
||||
onPlaybackChange={setVideoPlayback}
|
||||
/>
|
||||
);
|
||||
} else if (mode === "camera") {
|
||||
content = sampleLoading ? (
|
||||
<div className="l3-visual-audit__state" role="status">
|
||||
<span className="busy-indicator" aria-hidden="true" />
|
||||
<span>Открываем точный CAMERA-кадр M4.6</span>
|
||||
</div>
|
||||
) : sampleError || !frame ? (
|
||||
<div className="l3-visual-audit__state" role="status">
|
||||
<Icon name="alert" size={18} />
|
||||
<span>{sampleError ?? "CAMERA-кадр M4.6 недоступен."}</span>
|
||||
</div>
|
||||
) : (
|
||||
<RecordedEvidenceImageScene
|
||||
src={frame.cameraUrl}
|
||||
imageWidth={800}
|
||||
imageHeight={600}
|
||||
boxes={activeBoxes}
|
||||
ariaLabel={`M4.6 exact camera sample ${ordinal}: ${activeBoxes.length} proposals`}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
content = sampleLoading ? (
|
||||
<div className="l3-visual-audit__state" role="status">
|
||||
@@ -376,6 +385,7 @@ export function M4ReplayThreatVisual({ resultId }: { resultId: string }) {
|
||||
<div className="l3-visual-audit m4-replay-threat-visual">
|
||||
<LaboratoryEvidenceViewer
|
||||
label="M4.6 dual-evidence replay: video, camera and metric 3D"
|
||||
className="m4-replay-threat-evidence-viewer"
|
||||
mode={mode}
|
||||
modes={[
|
||||
{ value: "video", label: "VIDEO" },
|
||||
|
||||
Reference in New Issue
Block a user