fix(lab): enforce canonical replay runtime
This commit is contained in:
@@ -847,8 +847,9 @@ test("recorded VIDEO clock cannot reverse an explicit operator pause", () => {
|
||||
});
|
||||
|
||||
test("M4.6 viewer keeps media and spatial panes on one playback clock", async () => {
|
||||
const [visual, visualCss, imageScene, videoScene, pointOverlay, metricScene] = await Promise.all([
|
||||
const [visual, canonical, visualCss, imageScene, videoScene, pointOverlay, metricScene] = await Promise.all([
|
||||
readFile(new URL("../src/workspaces/laboratory/M4ReplayThreatVisual.tsx", import.meta.url), "utf8"),
|
||||
readFile(new URL("../src/components/laboratory/CanonicalRecordedLabReplay.tsx", import.meta.url), "utf8"),
|
||||
readFile(new URL("../src/styles/m4-replay-threat.css", import.meta.url), "utf8"),
|
||||
readFile(new URL("../src/components/laboratory/RecordedEvidenceImageScene.tsx", import.meta.url), "utf8"),
|
||||
readFile(new URL("../src/components/laboratory/RecordedEvidenceVideoScene.tsx", import.meta.url), "utf8"),
|
||||
@@ -858,7 +859,8 @@ test("M4.6 viewer keeps media and spatial panes on one playback clock", async ()
|
||||
assert.match(visual, /<RecordedEvidenceVideoScene/);
|
||||
assert.match(visual, /<RecordedEvidenceImageScene/);
|
||||
assert.match(visual, /<LaboratoryMetricEvidenceScene/);
|
||||
assert.match(visual, /m4-replay-threat-visual__deck/);
|
||||
assert.match(visual, /<CanonicalRecordedLabReplay/);
|
||||
assert.match(canonical, /m4-replay-threat-visual__deck/);
|
||||
assert.match(visual, /lastFrameRef/);
|
||||
assert.match(visual, /lastSpatialFrameRef/);
|
||||
assert.match(visual, /const spatialFrame = frame\?\.spatialAvailable/);
|
||||
@@ -876,19 +878,32 @@ test("M4.6 viewer keeps media and spatial panes on one playback clock", async ()
|
||||
assert.match(visual, /pointCloudOverlay=/);
|
||||
assert.match(visual, /mediaMode/);
|
||||
assert.match(visual, /spatialMode/);
|
||||
assert.match(visual, /current === next \? null : next/);
|
||||
assert.match(visual, /data-split=\{splitView \? "true" : undefined\}/);
|
||||
assert.match(visual, /<SplitPane/);
|
||||
assert.match(visual, /primarySize=\{splitView \? splitPrimarySize : mediaMode \? 100 : 0\}/);
|
||||
assert.match(visual, /resizable=\{splitView\}/);
|
||||
assert.match(visual, /separatorLabel="Изменить размер VIDEO\/CAMERA и 3D\/PLAN"/);
|
||||
assert.match(visual, /secondaryMode=\{\{/);
|
||||
assert.match(canonical, /current === next \? null : next/);
|
||||
assert.match(canonical, /data-split=\{splitView \? "true" : undefined\}/);
|
||||
assert.match(canonical, /<SplitPane/);
|
||||
assert.match(canonical, /primary=\{mediaPane\}/);
|
||||
assert.match(canonical, /secondary=\{spatialPane/);
|
||||
assert.match(canonical, /primarySize=\{splitView \? splitPrimarySize : mediaMode !== "none" \? 100 : 0\}/);
|
||||
assert.match(canonical, /resizable=\{splitView\}/);
|
||||
assert.match(canonical, /separatorLabel="Изменить размер VIDEO\/CAMERA и 3D\/PLAN"/);
|
||||
assert.match(canonical, /secondaryMode=\{\{/);
|
||||
assert.match(visual, /playback=\{playbackController\.playback\}/);
|
||||
assert.match(visual, /clock: mediaMode === "video" \? "external" : "animation"/);
|
||||
assert.match(visual, /clock: "animation"/);
|
||||
assert.match(visual, /useCanonicalRecordedLabReplayState/);
|
||||
assert.match(canonical, /current === next \? null : next/);
|
||||
assert.match(visual, /timelineFrame\.activeSequence \+ 1/);
|
||||
assert.match(visual, /segmentCount=\{timeline\.frameCount\}/);
|
||||
assert.match(visual, /onPlaybackChange=\{playbackController\.synchronize\}/);
|
||||
assert.match(visual, /onPlayingRejected=\{\(\) => playbackController\.setPlaying\(false\)\}/);
|
||||
assert.match(
|
||||
await readFile(new URL("../src/components/laboratory/useRecordedEvidencePlayback.ts", import.meta.url), "utf8"),
|
||||
/if \(clock === "animation"\) return;/,
|
||||
);
|
||||
assert.match(visual, /playbackAuthority="host"/);
|
||||
assert.match(visual, /playbackTransport="epoch-stream"/);
|
||||
assert.match(
|
||||
await readFile(new URL("../src/components/RecordedFmp4Player.tsx", import.meta.url), "utf8"),
|
||||
/if \(playbackAuthority === "host"\) return;/,
|
||||
);
|
||||
assert.match(visual, /currentSeconds: playbackController\.playback\.currentSeconds/);
|
||||
assert.match(visualCss, /m4-replay-threat-visual__deck > \.nodedc-split-pane/);
|
||||
assert.match(visualCss, /m4-replay-threat-visual__pane-toolbar\[data-pane-toolbar="media"\]/);
|
||||
@@ -951,12 +966,18 @@ test("M4.6 viewer keeps media and spatial panes on one playback clock", async ()
|
||||
});
|
||||
|
||||
test("M4.6 keeps the recorded VIDEO player mounted across media mode toggles", async () => {
|
||||
const visual = await readFile(
|
||||
new URL("../src/workspaces/laboratory/M4ReplayThreatVisual.tsx", import.meta.url),
|
||||
"utf8",
|
||||
);
|
||||
assert.match(visual, /const mediaPane = \(/);
|
||||
assert.match(visual, /hidden=\{!mediaMode\}/);
|
||||
const [visual, canonical] = await Promise.all([
|
||||
readFile(
|
||||
new URL("../src/workspaces/laboratory/M4ReplayThreatVisual.tsx", import.meta.url),
|
||||
"utf8",
|
||||
),
|
||||
readFile(
|
||||
new URL("../src/components/laboratory/CanonicalRecordedLabReplay.tsx", import.meta.url),
|
||||
"utf8",
|
||||
),
|
||||
]);
|
||||
assert.match(canonical, /const mediaPane = \(/);
|
||||
assert.match(canonical, /hidden=\{mediaMode === "none"\}/);
|
||||
assert.match(visual, /data-media="video"/);
|
||||
assert.match(visual, /hidden=\{mediaMode !== "video"\}/);
|
||||
assert.match(visual, /\{videoSource \? \(/);
|
||||
|
||||
@@ -75,10 +75,16 @@ test("semantic point alignment follows the last qualified spatial increment", as
|
||||
});
|
||||
|
||||
test("M4 keeps independent semantic controls in media and spatial panes", async () => {
|
||||
const source = await readFile(
|
||||
new URL("../src/workspaces/laboratory/M4ReplayThreatVisual.tsx", import.meta.url),
|
||||
"utf8",
|
||||
);
|
||||
const [source, canonical] = await Promise.all([
|
||||
readFile(
|
||||
new URL("../src/workspaces/laboratory/M4ReplayThreatVisual.tsx", import.meta.url),
|
||||
"utf8",
|
||||
),
|
||||
readFile(
|
||||
new URL("../src/components/laboratory/CanonicalRecordedLabReplay.tsx", import.meta.url),
|
||||
"utf8",
|
||||
),
|
||||
]);
|
||||
assert.match(source, /showMediaSemantic/);
|
||||
assert.match(source, /showSpatialSemantic/);
|
||||
assert.match(source, /activeSpatialSemantic = spatialSemantic \?\? activeSemantic/);
|
||||
@@ -89,9 +95,9 @@ test("M4 keeps independent semantic controls in media and spatial panes", async
|
||||
assert.match(source, /\|\| !showSpatialSemantic/);
|
||||
assert.match(source, /aria-label="Слои камеры и видео"/);
|
||||
assert.match(source, /aria-label="Слои 3D и плана"/);
|
||||
assert.match(source, /data-pane-mode="media"/);
|
||||
assert.match(source, /data-pane-mode="spatial"/);
|
||||
assert.match(source, /modeControlsVisible=\{!splitView\}/);
|
||||
assert.match(canonical, /data-pane-mode="media"/);
|
||||
assert.match(canonical, /data-pane-mode="spatial"/);
|
||||
assert.match(canonical, /modeControlsVisible=\{!splitView\}/);
|
||||
assert.match(source, /semanticOverlay=\{mediaMode === "video" \? semanticOverlay : undefined\}/);
|
||||
});
|
||||
|
||||
|
||||
@@ -6,7 +6,9 @@ import { createServer } from "vite";
|
||||
|
||||
let server;
|
||||
let fetchVegetationBenchmarkResult;
|
||||
let fetchCanonicalRecordedLabSpatialFrame;
|
||||
let fetchVegetationShadowResult;
|
||||
let fetchVegetationRouteTgsAnchor;
|
||||
let vegetationFullRouteMaskUrl;
|
||||
|
||||
before(async () => {
|
||||
@@ -17,7 +19,9 @@ before(async () => {
|
||||
});
|
||||
({
|
||||
fetchVegetationBenchmarkResult,
|
||||
fetchCanonicalRecordedLabSpatialFrame,
|
||||
fetchVegetationShadowResult,
|
||||
fetchVegetationRouteTgsAnchor,
|
||||
vegetationFullRouteMaskUrl,
|
||||
} = await server.ssrLoadModule(
|
||||
"/src/core/laboratory/vegetationShadow.ts",
|
||||
@@ -365,8 +369,68 @@ test("vegetation GOOSE benchmark opens through its separate archival endpoint",
|
||||
assert.equal(result.validationCases.length, 12);
|
||||
});
|
||||
|
||||
test("vegetation route TGS anchor keeps exact sealed metric shapes", async () => {
|
||||
let requestedUrl = "";
|
||||
const anchor = await fetchVegetationRouteTgsAnchor(resultId, 409, {
|
||||
fetcher: async (url) => {
|
||||
requestedUrl = String(url);
|
||||
return new Response(JSON.stringify({
|
||||
schema_version: "missioncore.lab-v1-route-tgs-anchor/v1",
|
||||
source_sequence: 409,
|
||||
slot: 1,
|
||||
current_points_xyz_m: [[1, 2, 3], [4, 5, 6]],
|
||||
costmap: {
|
||||
cell_size_m: 0.45,
|
||||
centers_xy_m: Array.from({ length: 2244 }, (_, index) => [index, -index]),
|
||||
state_codes: Array.from({ length: 2244 }, (_, index) => index % 4),
|
||||
z_bounds_m: Array.from({ length: 2244 }, () => [null, null]),
|
||||
},
|
||||
}), { status: 200, headers: { "Content-Type": "application/json" } });
|
||||
},
|
||||
});
|
||||
assert.equal(
|
||||
requestedUrl,
|
||||
`/api/v1/laboratory/vegetation-shadow/${resultId}/route-tgs-anchor/409`,
|
||||
);
|
||||
assert.equal(anchor.sourceSequence, 409);
|
||||
assert.equal(anchor.currentPointsXyzM.length, 2);
|
||||
assert.equal(anchor.costmap.centersXyM.length, 2244);
|
||||
assert.deepEqual(new Set(anchor.costmap.stateCodes), new Set([0, 1, 2, 3]));
|
||||
});
|
||||
|
||||
test("canonical recorded LAB spatial frame keeps source, SLAM and body identity on one clock", async () => {
|
||||
const generation = "e".repeat(64);
|
||||
let requestedUrl = "";
|
||||
const frame = await fetchCanonicalRecordedLabSpatialFrame("session-004", generation, 82_770_000_000, {
|
||||
fetcher: async (url) => {
|
||||
requestedUrl = String(url);
|
||||
return new Response(JSON.stringify({
|
||||
schema_version: "missioncore.canonical-recorded-lab-spatial-frame/v1",
|
||||
target_time_ns: 82_770_000_000,
|
||||
source_time_ns: 82_769_535_708,
|
||||
pose_time_ns: 82_769_535_708,
|
||||
trajectory_time_ns: 82_700_000_000,
|
||||
source_point_count: 2,
|
||||
source_points_body_xyz_m: [[1, 2, 3], [4, 5, 6]],
|
||||
local_slam_body_xyz_m: [[0, 0, 0], [1, 0, 0]],
|
||||
body_frame: {
|
||||
origin_map_xyz_m: [33, 4, 1],
|
||||
basis_map_from_body: [[1, 0, 0], [0, 1, 0], [0, 0, 1]],
|
||||
},
|
||||
}), { status: 200, headers: { "Content-Type": "application/json" } });
|
||||
},
|
||||
});
|
||||
assert.equal(
|
||||
requestedUrl,
|
||||
`/api/v1/observation-sessions/session-004/canonical-lab/spatial-frame?generation=${generation}&time_ns=82770000000`,
|
||||
);
|
||||
assert.equal(frame.sourcePointCount, 2);
|
||||
assert.equal(frame.localSlamBodyXyzM.length, 2);
|
||||
assert.deepEqual(frame.bodyFrame.originMapXyzM, [33, 4, 1]);
|
||||
});
|
||||
|
||||
test("vegetation realtime LAB and archival benchmark use separate admitted instruments", async () => {
|
||||
const [resultSource, benchmarkSource, m49Source] = await Promise.all([
|
||||
const [resultSource, benchmarkSource, m49Source, canonicalSource] = await Promise.all([
|
||||
readFile(
|
||||
new URL("../src/workspaces/laboratory/VegetationShadowResult.tsx", import.meta.url),
|
||||
"utf8",
|
||||
@@ -379,6 +443,10 @@ test("vegetation realtime LAB and archival benchmark use separate admitted instr
|
||||
new URL("../src/workspaces/laboratory/M49TgsFullShadowEvidence.tsx", import.meta.url),
|
||||
"utf8",
|
||||
),
|
||||
readFile(
|
||||
new URL("../src/components/laboratory/CanonicalRecordedLabReplay.tsx", import.meta.url),
|
||||
"utf8",
|
||||
),
|
||||
]);
|
||||
assert.doesNotMatch(resultSource, /M48MaskComparisonVisual/);
|
||||
assert.match(resultSource, /M49TgsFullShadowEvidence/);
|
||||
@@ -389,12 +457,28 @@ test("vegetation realtime LAB and archival benchmark use separate admitted instr
|
||||
assert.equal(resultSource.match(/<LaboratoryEvidence\b/g)?.length, 2);
|
||||
assert.doesNotMatch(resultSource, /RAVNOVES004TREE mixed route review/);
|
||||
assert.match(resultSource, /RAVNOVES004TREE full recorded review/);
|
||||
assert.match(resultSource, /LaboratoryRecordedClipPlayer/);
|
||||
assert.match(resultSource, /RerunViewport/);
|
||||
assert.match(resultSource, /M48EvidenceModeRail/);
|
||||
assert.match(resultSource, /CanonicalRecordedLabReplay/);
|
||||
assert.match(resultSource, /RecordedEvidenceVideoScene/);
|
||||
assert.match(resultSource, /LaboratoryMetricEvidenceScene/);
|
||||
assert.doesNotMatch(resultSource, /RerunViewport/);
|
||||
assert.match(resultSource, /fetchCanonicalRecordedLabSpatialFrame/);
|
||||
assert.match(resultSource, /useCanonicalRecordedLabReplayState/);
|
||||
assert.match(resultSource, /playbackTransport="epoch-stream"/);
|
||||
assert.match(resultSource, /causalTgsCase/);
|
||||
assert.match(resultSource, /latest causal of 10 sealed anchors/);
|
||||
assert.doesNotMatch(resultSource, /LaboratoryRecordedClipPlayer|M48EvidenceModeRail/);
|
||||
assert.doesNotMatch(resultSource, /assets\.tgs|<img/);
|
||||
assert.match(resultSource, /SOURCE POINTS/);
|
||||
assert.match(resultSource, /LOCAL SLAM/);
|
||||
assert.match(resultSource, /TGS COSTMAP/);
|
||||
assert.match(resultSource, /onClick=\{\(\) => setShowTgs\(\(visible\) => !visible\)\}/);
|
||||
assert.match(resultSource, /showClassifiedCells=\{showTgs && Boolean\(packedTgsCells\)\}/);
|
||||
assert.doesNotMatch(resultSource, /setShowTgs\(false\)/);
|
||||
assert.doesNotMatch(resultSource, /setPlaying\(false\);[\s\S]{0,160}setShowTgs/);
|
||||
assert.match(canonicalSource, /primary=\{mediaPane\}/);
|
||||
assert.match(canonicalSource, /secondary=\{spatialPane/);
|
||||
assert.match(canonicalSource, /missioncore\.canonical-recorded-lab-replay\/v1/);
|
||||
assert.match(canonicalSource, /separatorLabel="Изменить размер VIDEO\/CAMERA и 3D\/PLAN"/);
|
||||
assert.match(resultSource, /linked canonical M4\.9 TGS evidence/);
|
||||
assert.match(resultSource, /linkedTgsResultId/);
|
||||
assert.match(benchmarkSource, /M48MaskComparisonVisual/);
|
||||
|
||||
Reference in New Issue
Block a user