feat(lab): stabilize autonomous TGS playback
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { createHash } from "node:crypto";
|
||||
import { readFile } from "node:fs/promises";
|
||||
import { after, before, test } from "node:test";
|
||||
|
||||
@@ -9,6 +10,8 @@ let fetchM4ThreatReplayResult;
|
||||
let fetchM4ThreatVisual;
|
||||
let fetchM4ThreatTimeline;
|
||||
let fetchM4ThreatTimelineChunk;
|
||||
let fetchM4ThreatPlaybackManifest;
|
||||
let fetchM4ThreatPlaybackPointChunk;
|
||||
let fetchM4ThreatCameraPointOverlay;
|
||||
let hydrateM4ThreatTimelineFrame;
|
||||
let selectM4ThreatTimelineFrame;
|
||||
@@ -33,6 +36,8 @@ before(async () => {
|
||||
fetchM4ThreatVisual,
|
||||
fetchM4ThreatTimeline,
|
||||
fetchM4ThreatTimelineChunk,
|
||||
fetchM4ThreatPlaybackManifest,
|
||||
fetchM4ThreatPlaybackPointChunk,
|
||||
fetchM4ThreatCameraPointOverlay,
|
||||
hydrateM4ThreatTimelineFrame,
|
||||
selectM4ThreatTimelineFrame,
|
||||
@@ -373,6 +378,76 @@ test("M4.6 hydrates a lightweight timeline frame from one retained binary point
|
||||
assert.equal(typeof hydrateM4ThreatTimelineFrame, "function");
|
||||
});
|
||||
|
||||
test("M4.6 source cloud opens from one verified bounded chunk instead of the 105 MiB track", async () => {
|
||||
const pointOffsets = [0, ...Array(4489).fill(2)];
|
||||
const points = new Float32Array([11, 20, 30.25, 12, 19.5, 30]);
|
||||
const pointBytes = points.buffer;
|
||||
const pointSha256 = createHash("sha256").update(Buffer.from(pointBytes)).digest("hex");
|
||||
const endpointRoot = "/api/v1/laboratory/m4-threat/results";
|
||||
const chunks = Array.from({ length: 188 }, (_, index) => {
|
||||
const start = index * 24;
|
||||
const count = Math.min(24, 4489 - start);
|
||||
const pointStart = pointOffsets[start];
|
||||
const pointStop = pointOffsets[start + count];
|
||||
const pointCount = pointStop - pointStart;
|
||||
return {
|
||||
index,
|
||||
start,
|
||||
count,
|
||||
point_start: pointStart,
|
||||
point_count: pointCount,
|
||||
url: `${endpointRoot}/${resultId}/timeline/playback/chunks/${index}`,
|
||||
media_type: "application/octet-stream",
|
||||
dtype: "<f4",
|
||||
shape: [pointCount, 3],
|
||||
bytes: pointCount * 3 * 4,
|
||||
sha256: index === 0 ? pointSha256 : "0".repeat(64),
|
||||
};
|
||||
});
|
||||
const manifestPayload = {
|
||||
schema_version: "missioncore.recorded-spatial-playback/v1",
|
||||
result_id: resultId,
|
||||
frame_count: 4489,
|
||||
point_count: 2,
|
||||
point_offsets: pointOffsets,
|
||||
chunk_frame_count: 24,
|
||||
resident_chunk_count_max: 4,
|
||||
forward_prefetch_chunk_count: 1,
|
||||
chunks,
|
||||
track: {
|
||||
id: "points-map-f32",
|
||||
url: `${endpointRoot}/${resultId}/timeline/playback/tracks/points-map-f32`,
|
||||
media_type: "application/octet-stream",
|
||||
dtype: "<f4",
|
||||
shape: [2, 3],
|
||||
bytes: pointBytes.byteLength,
|
||||
sha256: pointSha256,
|
||||
},
|
||||
coordinate_frame: "map",
|
||||
access: "read-only-sealed-binary-playback",
|
||||
};
|
||||
const requested = [];
|
||||
const fetcher = async (input) => {
|
||||
const url = String(input);
|
||||
requested.push(url);
|
||||
if (url.endsWith("/timeline/playback")) return Response.json(manifestPayload);
|
||||
if (url.endsWith("/timeline/playback/chunks/0")) return new Response(pointBytes.slice(0));
|
||||
return new Response(null, { status: 404 });
|
||||
};
|
||||
const manifest = await fetchM4ThreatPlaybackManifest(resultId, { fetcher });
|
||||
const chunk = await fetchM4ThreatPlaybackPointChunk(manifest, 0, { fetcher });
|
||||
|
||||
assert.deepEqual(requested, [
|
||||
`${endpointRoot}/${resultId}/timeline/playback`,
|
||||
`${endpointRoot}/${resultId}/timeline/playback/chunks/0`,
|
||||
]);
|
||||
assert.equal(chunk.pointCount, 2);
|
||||
assert.equal(chunk.pointStart, 0);
|
||||
assert.equal(chunk.sequenceCount, 24);
|
||||
assert.equal(chunk.pointsMapXyzM.byteLength, 24);
|
||||
assert.equal(requested.some((url) => url.endsWith("points-map-f32")), false);
|
||||
});
|
||||
|
||||
test("M4.8S timeline binds factory-KB4 camera points through its exact endpoint", async () => {
|
||||
const replayResultId = `m48s-fixed-class-detector-lab-${"b".repeat(64)}`;
|
||||
const endpointRoot = "/api/v1/laboratory/m48s/fixed-class-detector";
|
||||
@@ -825,10 +900,15 @@ test("M4.6 viewer keeps media and spatial panes on one playback clock", async ()
|
||||
assert.match(visualCss, /width: 33\.333333%/);
|
||||
assert.match(visualCss, /flex-flow: column nowrap/);
|
||||
assert.match(visualCss, /m4-replay-threat-visual__overlay > div/);
|
||||
assert.match(visualCss, /grid-template-columns: minmax\(0, max-content\)/);
|
||||
assert.match(visualCss, /width: max-content/);
|
||||
assert.match(visualCss, /grid-template-columns: minmax\(0, 1fr\)/);
|
||||
assert.match(visualCss, /width: min\(17\.5rem/);
|
||||
assert.match(visualCss, /grid-auto-rows: 3\.8rem/);
|
||||
assert.match(visualCss, /--m4-replay-threat-overlay-pane-width/);
|
||||
assert.match(visualCss, /white-space: nowrap/);
|
||||
assert.match(visualCss, /-webkit-line-clamp: 2/);
|
||||
assert.match(visual, /classifiedCellCount/);
|
||||
assert.match(visual, /lastAvailableClassifiedSpatialFrame/);
|
||||
assert.match(visual, /current UNOBSERVED/);
|
||||
assert.match(visualCss, /laboratory-metric-evidence-scene__legend/);
|
||||
assert.match(visualCss, /bottom: auto/);
|
||||
assert.match(videoScene, /<RecordedFmp4Player/);
|
||||
@@ -842,16 +922,18 @@ test("M4.6 viewer keeps media and spatial panes on one playback clock", async ()
|
||||
assert.match(visual, /showLocalSurface/);
|
||||
assert.match(
|
||||
visual,
|
||||
/pointCloudBodyXyzM=\{displayedClassifiedSpatialFrame && replaceClassifiedPointCloud[\s\S]*\? classifiedPointsBody[\s\S]*: activeSpatialFrame\?\.pointCloudBodyXyzM \?\? \[\]\}/,
|
||||
/pointCloudBodyXyzM=\{displayedClassifiedSpatialFrame && replaceClassifiedPointCloud[\s\S]*\? classifiedPointsBody[\s\S]*: classifiedContextSpatialFrame\?\.pointCloudBodyXyzM \?\? \[\]\}/,
|
||||
);
|
||||
assert.match(
|
||||
visual,
|
||||
/const classifiedSpatialFrame = classifiedSpatialLayer\?\.frame\?\.sourceSequence === timelineFrame\.activeSequence[\s\S]*const displayedClassifiedSpatialFrame = classifiedSpatialFrame[\s\S]*lastClassifiedSpatialFrameRef/,
|
||||
/const classifiedSpatialFrame = classifiedSpatialLayer\?\.frame\?\.sourceSequence === timelineFrame\.activeSequence[\s\S]*lastClassifiedSpatialFrameRef[\s\S]*const displayedClassifiedSpatialFrame = classifiedSpatialFrame\s*&&\s*classifiedSpatialFrame\.sampleAvailable !== false/,
|
||||
);
|
||||
assert.doesNotMatch(visual, /classifiedSpatialFrame\?\.sampleAvailable !== false/);
|
||||
assert.match(visual, /timelineFrame\.availableFrames\.find/);
|
||||
assert.match(visual, /localSurfaceBodyXyzM=\{localSurface\.pointsBodyXyzM\}/);
|
||||
assert.match(visual, /showLocalSurface=\{showLocalSurface\}/);
|
||||
assert.match(visual, /\{semantic \? \([\s\S]*>\s*SEMANTICS\s*<\/Button>/);
|
||||
assert.match(visual, /все 2 244 TGS-ячейки явно UNOBSERVED/);
|
||||
assert.match(visual, /current safety — все \{classifiedCellCount\.toLocaleString\("ru-RU"\)\} TGS-ячейки UNOBSERVED/);
|
||||
assert.match(
|
||||
visual,
|
||||
/mapGravityLocalSensorToBodyGround[\s\S]*rotated\[2\] \+ nominalSensorHeightM/,
|
||||
|
||||
Reference in New Issue
Block a user