refactor(lab): canonicalize recorded spatial replay

This commit is contained in:
DCCONSTRUCTIONS
2026-08-29 23:38:17 +03:00
parent bd2892140f
commit 74da6437e9
12 changed files with 919 additions and 293 deletions
@@ -23,6 +23,7 @@ import {
type LaboratoryMetricPackedCellEvidence,
} from "../../components/laboratory/LaboratoryMetricEvidenceScene";
import { RecordedEvidenceVideoScene } from "../../components/laboratory/RecordedEvidenceVideoScene";
import { useCanonicalRecordedLabSpatialFrame } from "../../components/laboratory/useCanonicalRecordedLabSpatialFrame";
import { useRecordedEvidencePlayback } from "../../components/laboratory/useRecordedEvidencePlayback";
import {
LaboratoryEvidence,
@@ -35,12 +36,14 @@ import {
type RecordedEvidenceSemanticPaletteEntry,
} from "../../components/laboratory/RecordedEvidenceSemanticMaskOverlay";
import {
fetchCanonicalRecordedLabSpatialFrame,
canonicalRecordedLabPackedTgsCells,
canonicalRecordedLabTgsIsCurrent,
} from "../../core/laboratory/canonicalRecordedLab";
import {
fetchVegetationShadowResult,
fetchVegetationRouteTgsAnchor,
vegetationFullRouteMaskUrl,
vegetationVideoMaskUrl,
type CanonicalRecordedLabSpatialFrame,
type VegetationFullRouteLayer,
type VegetationFullRouteReview,
type VegetationMixedRouteCase,
@@ -105,9 +108,7 @@ function causalTgsCase(
&& (!latest || candidate.sourceSequence > latest.sourceSequence)
? candidate
: latest
), null) ?? cases.reduce((first, candidate) => (
candidate.sourceSequence < first.sourceSequence ? candidate : first
));
), null);
}
function nearestFullRouteFrameIndex(
@@ -130,92 +131,6 @@ function nearestFullRouteFrameIndex(
: low;
}
function useCanonicalRavSpatialFrame(
review: VegetationFullRouteReview,
replayLaunch: ObservationSessionReplayLaunch | null,
targetTimeNs: number,
) {
const [frame, setFrame] = useState<CanonicalRecordedLabSpatialFrame | null>(null);
const [error, setError] = useState<string | null>(null);
const desiredRef = useRef<number | null>(null);
const runningRef = useRef(false);
const mountedRef = useRef(true);
const cacheRef = useRef(new Map<number, CanonicalRecordedLabSpatialFrame>());
const pumpRef = useRef<() => void>(() => undefined);
pumpRef.current = () => {
if (runningRef.current || desiredRef.current === null || !replayLaunch) return;
runningRef.current = true;
let settledTimeNs: number | null = null;
void (async () => {
while (mountedRef.current && desiredRef.current !== null) {
const requestedTimeNs = desiredRef.current;
const cached = cacheRef.current.get(requestedTimeNs);
try {
const next = cached ?? await fetchCanonicalRecordedLabSpatialFrame(
review.sessionId,
replayLaunch.sha256,
requestedTimeNs,
);
if (!cached) {
cacheRef.current.set(requestedTimeNs, next);
while (cacheRef.current.size > 12) {
const oldest = cacheRef.current.keys().next().value as number | undefined;
if (oldest === undefined) break;
cacheRef.current.delete(oldest);
}
}
if (!mountedRef.current) break;
setFrame(next);
setError(null);
} catch (caught: unknown) {
if (!mountedRef.current) break;
setError(caught instanceof Error ? caught.message : "Spatial-слои RAV004 недоступны.");
}
settledTimeNs = requestedTimeNs;
if (desiredRef.current === requestedTimeNs) break;
}
})().finally(() => {
runningRef.current = false;
if (
mountedRef.current
&& desiredRef.current !== null
&& desiredRef.current !== settledTimeNs
) {
pumpRef.current();
}
});
};
useEffect(() => {
mountedRef.current = true;
return () => {
mountedRef.current = false;
desiredRef.current = null;
};
}, []);
useEffect(() => {
cacheRef.current.clear();
setFrame(null);
setError(null);
}, [replayLaunch?.sha256, review.sessionId]);
useEffect(() => {
if (!replayLaunch) return;
desiredRef.current = targetTimeNs;
const cached = cacheRef.current.get(targetTimeNs);
if (cached) {
setFrame(cached);
setError(null);
return;
}
pumpRef.current();
}, [replayLaunch, targetTimeNs]);
return { frame, error, loading: Boolean(replayLaunch) && !frame && !error };
}
function FullRouteReviewEvidence({
resultId,
review,
@@ -266,7 +181,11 @@ function FullRouteReviewEvidence({
const spatialRequestTimeNs = review.frameSourceTimesNs[spatialRequestIndex]
?? review.frameSourceTimesNs[sequenceIndex]
?? Math.round(playbackController.playback.currentSeconds * 1_000_000_000);
const spatialEvidence = useCanonicalRavSpatialFrame(review, replayLaunch, spatialRequestTimeNs);
const spatialEvidence = useCanonicalRecordedLabSpatialFrame({
sessionId: review.sessionId,
generationSha256: replayLaunch?.sha256 ?? null,
targetTimeNs: spatialRequestTimeNs,
});
const layer = review[semanticLayer];
const semantic = useMemo(() => semanticPresentation(layer), [layer]);
const prefetchSrcs = useMemo(() => showCameraSemantic
@@ -343,11 +262,17 @@ function FullRouteReviewEvidence({
? review.frameSourceTimesNs[selectedTgsCase.sourceSequence - 1]
?? Math.round(selectedTgsCase.sessionSeconds * 1_000_000_000)
: spatialRequestTimeNs;
const tgsReferenceEvidence = useCanonicalRavSpatialFrame(
review,
replayLaunch,
selectedTgsTimeNs,
const currentFrameTimeNs = review.frameSourceTimesNs[sequenceIndex]
?? Math.round(playbackController.playback.currentSeconds * 1_000_000_000);
const tgsWithinEvidenceWindow = Boolean(
selectedTgsCase
&& canonicalRecordedLabTgsIsCurrent(currentFrameTimeNs, selectedTgsTimeNs),
);
const tgsReferenceEvidence = useCanonicalRecordedLabSpatialFrame({
sessionId: review.sessionId,
generationSha256: replayLaunch?.sha256 ?? null,
targetTimeNs: selectedTgsTimeNs,
});
useEffect(() => {
if (!showTgs || !selectedTgsCase) {
@@ -376,53 +301,24 @@ function FullRouteReviewEvidence({
}, [review.linkedRouteReviewResultId, selectedTgsCase?.sourceSequence, showTgs]);
const packedTgsCells = useMemo<LaboratoryMetricPackedCellEvidence | undefined>(() => {
if (!tgsAnchor) return undefined;
if (!tgsAnchor || !tgsWithinEvidenceWindow) return undefined;
const currentBody = spatialEvidence.frame?.bodyFrame;
const anchorBody = tgsReferenceEvidence.frame?.bodyFrame;
const transformPoint = (point: readonly [number, number, number]) => {
if (!currentBody || !anchorBody) return point;
const map = [0, 1, 2].map((row) => (
anchorBody.originMapXyzM[row]!
+ anchorBody.basisMapFromBody[row]!.reduce(
(sum, coefficient, column) => sum + coefficient * point[column]!,
0,
)
));
const delta = map.map((value, index) => value - currentBody.originMapXyzM[index]!);
return [0, 1, 2].map((column) => (
currentBody.basisMapFromBody.reduce(
(sum, row, rowIndex) => sum + row[column]! * delta[rowIndex]!,
0,
)
)) as [number, number, number];
};
const centers: number[] = [];
const zBounds: number[] = [];
tgsAnchor.costmap.centersXyM.forEach(([x, y], index) => {
const bounds = tgsAnchor.costmap.zBoundsM[index] ?? [null, null];
const center = transformPoint([x, y, 0]);
centers.push(center[0], center[1]);
if (bounds[0] === null || bounds[1] === null) {
zBounds.push(Number.NaN, Number.NaN);
} else {
const bottom = transformPoint([x, y, bounds[0]]);
const top = transformPoint([x, y, bounds[1]]);
zBounds.push(Math.min(bottom[2], top[2]), Math.max(bottom[2], top[2]));
}
});
return {
centersBodyXyM: Float32Array.from(centers),
zBoundsM: Float32Array.from(zBounds),
stateCodes: Uint8Array.from(tgsAnchor.costmap.stateCodes),
};
}, [spatialEvidence.frame?.bodyFrame, tgsAnchor, tgsReferenceEvidence.frame?.bodyFrame]);
if (!currentBody || !anchorBody) return undefined;
return canonicalRecordedLabPackedTgsCells(tgsAnchor.costmap, anchorBody, currentBody);
}, [
spatialEvidence.frame?.bodyFrame,
tgsAnchor,
tgsReferenceEvidence.frame?.bodyFrame,
tgsWithinEvidenceWindow,
]);
const semanticOverlay = showCameraSemantic ? {
src: vegetationFullRouteMaskUrl(resultId, semanticLayer, sequenceIndex),
prefetchSrcs,
classes: semantic.classes,
palette: semantic.palette,
opacity: 0.76,
opacity: 0.46,
ariaLabel: `${layer.name} semantic prediction frame ${sequence}`,
} : undefined;
@@ -464,7 +360,11 @@ function FullRouteReviewEvidence({
? spatialEvidence.frame.localSlamBodyXyzM
: []}
obstacles={[]}
rig={{ lengthM: 1, widthM: 0.8, nominalSensorHeightM: 0.4 }}
rig={{
lengthM: 1,
widthM: 0.8,
nominalSensorHeightM: spatialEvidence.frame.sensorHeight.meters,
}}
corridor={{ forwardLengthM: 12, rearMarginM: 1, halfWidthM: 0.4 }}
occupiedVoxelSizeM={tgsAnchor?.costmap.cellSizeM ?? 0.45}
mode={spatialMode}
@@ -487,7 +387,9 @@ function FullRouteReviewEvidence({
<div className="m4-replay-threat-visual__pane-status" role="status">
{tgsAnchorError ?? linkedReviewError ?? (tgsAnchorLoading
? `Открываем sealed TGS anchor ${selectedTgsCase.sourceSequence}; source/SLAM и общий clock продолжаются.`
: `TGS anchor ${selectedTgsCase.sourceSequence} из 10; source/SLAM и общий clock продолжаются.`)}
: tgsWithinEvidenceWindow
? `TGS anchor ${selectedTgsCase.sourceSequence} из 10; source/SLAM и общий clock продолжаются.`
: `TGS anchor ${selectedTgsCase.sourceSequence} старше доказанного окна 1 с; слой скрыт, playback продолжается.`)}
</div>
) : null}
</>
@@ -597,12 +499,12 @@ function FullRouteReviewEvidence({
</div>
<div>
<span>Spatial evidence</span>
<strong>{showTgs && selectedTgsCase
<strong>{showTgs && selectedTgsCase && tgsWithinEvidenceWindow
? `TGS anchor ${selectedTgsCase.sourceSequence} · ${selectedTgsCase.tgs.occupiedCells} occupied`
: "source RRD · points + SLAM"}</strong>
: "source RRD · points + bounded Local SLAM"}</strong>
<small>{showTgs
? "latest causal of 10 sealed anchors · continuous playback retained"
: "causal 1 s view · grayscale intensity · recorded source identity"}</small>
? "TGS visible only inside sealed 1 s evidence window · playback retained"
: "5 s bounded Local SLAM · ground-rebased recorded source"}</small>
</div>
</div>
);
@@ -673,7 +575,7 @@ function FullRouteReviewResult({
summary={(
<LaboratorySummary
title="LAB V1 · RAVNOVES004TREE · полный маршрут"
description="Общий recorded-LAB шаблон воспроизводит запись с травой и оврагами: RIGHT camera, исходное облако, SLAM trajectory, два независимых semantic-слоя и десять реально просчитанных TGS-якорей."
description="Общий recorded-LAB шаблон воспроизводит запись с травой и оврагами: RIGHT camera, исходное облако, ограниченный Local SLAM, два независимых semantic-слоя и десять реально просчитанных TGS-якорей."
status="FULL RECORDED REVIEW · truth отсутствует · commands OFF"
statusTone="warning"
facts={[
@@ -686,7 +588,7 @@ function FullRouteReviewResult({
]}
brief={{
question: "Что реально видно на полном RAV004-прогоне с высокой травой, оврагами и переходом к городу?",
approach: "Одна recorded timeline открывается общим LAB viewer. Camera и RRD синхронизированы; EoMT/DDRNet переключаются на камере, source points и SLAM trajectory — в 3D, TGS — только на десяти запечатанных якорях.",
approach: "Одна recorded timeline открывается общим LAB viewer. Camera и RRD синхронизированы; EoMT/DDRNet переключаются на камере, source points и 5-секундный Local SLAM — в 3D, TGS — только в доказанном окне десяти запечатанных якорей.",
principalResult: "RAV004 больше не подменяется RAV00: доступна полная исходная запись и её реальные пространственные слои.",
limitation: "Ручной truth, continuous TGS и point-aligned 3D semantics отсутствуют. Один повреждённый H.264-пакет на позиции 6092 заменён предыдущим декодированным кадром и отражён в proof.",
}}
@@ -695,7 +597,7 @@ function FullRouteReviewResult({
executionClass: "ai-inference",
pipelineId: "ravnoves004tree-full-eomt-ddrnet-recorded-review/v1",
components: [
{ kind: "algorithm", name: "Recorded source points + SLAM trajectory", version: "sealed RRD", role: "spatial source evidence", identitySha256: null },
{ kind: "algorithm", name: "Recorded source points + bounded Local SLAM", version: "source-paced-ground-v2", role: "spatial source evidence", identitySha256: null },
{ 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 },
{ kind: "algorithm", name: "Causal TGS", version: "10 linked route anchors", role: "bounded geometric evidence", identitySha256: null },
@@ -725,7 +627,7 @@ function FullRouteReviewResult({
{ label: "Spatial evidence", value: "RRD + 10 TGS anchors", hint: "continuous TGS и 3D semantics отсутствуют" },
]}
conclusion={{
proved: "Полный RAV004 открывается в каноническом recorded viewer с camera, source points, SLAM trajectory, EoMT, DDRNet и связанными TGS-якорями.",
proved: "Полный RAV004 открывается в каноническом recorded viewer с camera, source points, bounded Local SLAM, EoMT, DDRNet и связанными TGS-якорями.",
notProved: "Не доказаны truth accuracy, временная стабильность DDRNet, continuous negative-obstacle detection и безопасное управление ровером.",
decision: "Использовать как visual audit. Следующий gate — truth-набор овраг/трава/дерево/яма и motion-aware temporal evaluation при целевых ≥10 FPS; navigation/actuation оставить OFF.",
}}