feat(lab): stabilize autonomous TGS playback

This commit is contained in:
DCCONSTRUCTIONS
2026-08-27 20:34:20 +03:00
parent c8593207d3
commit 95a1ef5057
26 changed files with 3326 additions and 253 deletions
@@ -691,3 +691,18 @@ test("metric evidence keeps one WebGL renderer while frame labels advance", () =
/querySelector\("canvas"\)[\s\S]*?setAttribute\("aria-label", label\)[\s\S]*?\}, \[label\]\);/,
);
});
test("metric evidence renders on demand while preserving damped camera interaction", () => {
const source = readFileSync(
new URL("../src/components/laboratory/LaboratoryMetricEvidenceScene.tsx", import.meta.url),
"utf8",
);
assert.match(source, /const requestRenderRef = useRef/);
assert.match(source, /controls\.addEventListener\("change", requestRender\)/);
assert.match(source, /requestRenderRef\.current\(\)/);
assert.doesNotMatch(
source,
/const render = \(\) => \{\s*animationFrame = window\.requestAnimationFrame\(render\)/,
);
});
@@ -0,0 +1,234 @@
import assert from "node:assert/strict";
import { createHash } from "node:crypto";
import { after, before, test } from "node:test";
import { createServer } from "vite";
let server;
let M49PhysicalSafetyPlaybackBuffer;
let fetchM49PhysicalSafetyPlaybackIdForSource;
const resultId = `m49-physical-safety-playback-${"a".repeat(64)}`;
const endpoint = `/api/v1/laboratory/m49/physical-safety-playback/${resultId}`;
const frameCount = 160;
const cellCount = 4;
before(async () => {
server = await createServer({
appType: "custom",
logLevel: "silent",
server: { middlewareMode: true },
});
({
M49PhysicalSafetyPlaybackBuffer,
fetchM49PhysicalSafetyPlaybackIdForSource,
} = await server.ssrLoadModule(
"/src/core/laboratory/m49PhysicalSafetyPlayback.ts",
));
});
after(async () => {
await server?.close();
});
function sha256(buffer) {
return createHash("sha256").update(Buffer.from(buffer)).digest("hex");
}
function chunk(index) {
const start = index * 32;
const count = Math.min(32, frameCount - start);
const stateBytes = count * cellCount;
const zBytes = count * cellCount * 2 * 4;
const headerBytes = 28;
const padding = (4 - ((headerBytes + stateBytes) % 4)) % 4;
const buffer = new ArrayBuffer(headerBytes + stateBytes + padding + zBytes);
const bytes = new Uint8Array(buffer);
bytes.set(new TextEncoder().encode("MCPSCH01"));
const view = new DataView(buffer);
view.setUint32(8, start, true);
view.setUint32(12, count, true);
view.setUint32(16, cellCount, true);
view.setUint32(20, stateBytes, true);
view.setUint32(24, zBytes, true);
const states = new Uint8Array(buffer, headerBytes, stateBytes);
states.fill(1);
const z = new Float32Array(buffer, headerBytes + stateBytes + padding, count * cellCount * 2);
for (let local = 0; local < count; local += 1) {
const sequence = start + local;
for (let cell = 0; cell < cellCount; cell += 1) {
z[(local * cellCount + cell) * 2] = 0;
z[(local * cellCount + cell) * 2 + 1] = 0.12;
}
if (sequence === 17) {
states.fill(0, local * cellCount, (local + 1) * cellCount);
z.fill(Number.NaN, local * cellCount * 2, (local + 1) * cellCount * 2);
}
}
return buffer;
}
function fixture() {
const centers = new Float32Array([0, 0, 0.15, 0, 0.3, 0, 0.45, 0]).buffer;
const frames = new TextEncoder().encode(Array.from({ length: frameCount }, (_, sequence) => (
JSON.stringify({
source_frame_index: sequence,
session_seconds: sequence / 10,
sample_available: sequence !== 17,
eligible_point_count: sequence === 17 ? 0 : cellCount,
})
)).join("\n") + "\n").buffer;
const chunks = Array.from({ length: Math.ceil(frameCount / 32) }, (_, index) => chunk(index));
const manifest = {
schema_version: "missioncore.m49-physical-safety-playback/v1",
result_id: resultId,
created_at_utc: "2026-08-27T12:00:00Z",
access: "read-only-sealed-local",
identity: { source_result_id: `m49-tgs-full-shadow-${"b".repeat(64)}` },
execution: {
execution_class: "local-sequential-offline",
worker_role: "realtime-only",
worker_runtime_dependency: false,
worker_requests_required: 0,
},
authority: {
commands_enabled: false,
navigation_or_safety_accepted: false,
actuation_accepted: false,
},
playback: {
coordinate_frame: "map-gravity-local",
source_pace_hz: 10,
frame_count: frameCount,
cell_count: cellCount,
cell_size_m: 0.15,
radius_m: 12,
state_codes: {
UNOBSERVED: 0,
GROUND_SUPPORT: 1,
NONGROUND_OCCUPIED: 2,
UNKNOWN_REJECTED: 3,
},
chunk_frame_count: 32,
startup_prebuffer_chunk_count: 2,
resident_chunk_count_max: 3,
forward_prefetch_chunk_count: 1,
centers: {
url: `${endpoint}/tracks/centers`,
media_type: "application/octet-stream",
byte_length: centers.byteLength,
sha256: sha256(centers),
dtype: "<f4",
shape: [cellCount, 2],
},
frames: {
url: `${endpoint}/tracks/frames`,
media_type: "application/x-ndjson",
byte_length: frames.byteLength,
sha256: sha256(frames),
dtype: "ndjson",
shape: [frameCount],
},
chunks: chunks.map((buffer, index) => ({
index,
start: index * 32,
count: Math.min(32, frameCount - index * 32),
url: `${endpoint}/chunks/${index}`,
media_type: "application/octet-stream",
byte_length: buffer.byteLength,
sha256: sha256(buffer),
header_bytes: 28,
format: "mcpsch01-states-u8-aligned-z-bounds-f32le",
})),
},
};
const responses = new Map([
[`${endpoint}/tracks/centers`, centers],
[`${endpoint}/tracks/frames`, frames],
...chunks.map((buffer, index) => [`${endpoint}/chunks/${index}`, buffer]),
]);
return { manifest, responses };
}
test("physical-safety playback opens and seeks with bounded local chunks only", async () => {
const { manifest, responses } = fixture();
const requested = [];
const progress = [];
const fetcher = async (input) => {
const url = String(input);
requested.push(url);
if (url === `${endpoint.replace(`/${resultId}`, "")}/results?limit=2&source_result_id=${manifest.identity.source_result_id}`) {
return Response.json({
schema_version: "missioncore.m49-physical-safety-playback-catalog/v1",
worker_runtime_dependency: false,
access: "read-only-sealed-local",
items: [{
result_id: resultId,
source_result_id: manifest.identity.source_result_id,
worker_runtime_dependency: false,
navigation_or_safety_accepted: false,
}],
});
}
if (url === `${endpoint}/manifest`) {
return Response.json(manifest);
}
const payload = responses.get(url);
return payload
? new Response(payload, { headers: { "Content-Type": "application/octet-stream" } })
: new Response(null, { status: 404 });
};
const resolvedResultId = await fetchM49PhysicalSafetyPlaybackIdForSource(
manifest.identity.source_result_id,
{ fetcher },
);
assert.equal(resolvedResultId, resultId);
const playback = await M49PhysicalSafetyPlaybackBuffer.open(resolvedResultId, {
fetcher,
onProgress: (value) => progress.push(value),
});
assert.deepEqual(playback.residentChunkIndexes, [0, 1]);
assert.equal(progress.at(-1).phase, "ready");
assert.equal(requested.some((url) => url.includes("worker")), false);
const startupRequestCount = requested.length;
await playback.prepare(0);
await playback.prepare(0);
assert.equal(requested.length, startupRequestCount);
const missing = await playback.frame(17);
assert.equal(missing.metadata.sampleAvailable, false);
assert.deepEqual(new Set(missing.states), new Set([0]));
assert.equal([...missing.zBoundsM].every((value) => Number.isNaN(value)), true);
await playback.prepare(100);
assert.equal(playback.residentChunkIndexes.length <= 3, true);
assert.equal(playback.residentChunkIndexes.includes(3), true);
assert.equal(playback.residentChunkIndexes.includes(4), true);
const selected = await playback.frame(100);
assert.deepEqual([...selected.states], [1, 1, 1, 1]);
const maximumResidentBytes = manifest.playback.centers.byte_length
+ manifest.playback.frames.byte_length
+ 3 * Math.max(...manifest.playback.chunks.map((value) => value.byte_length));
assert.equal(playback.residentByteLength <= maximumResidentBytes, true);
await playback.prepare(0);
assert.equal(playback.residentChunkIndexes.length <= 3, true);
assert.equal(playback.residentChunkIndexes.includes(0), true);
assert.equal(playback.residentChunkIndexes.includes(1), true);
assert.equal(
requested.every((url) => url.startsWith("/api/v1/laboratory/m49/physical-safety-playback")),
true,
);
});
test("physical-safety playback rejects a manifest that points at Worker", async () => {
const { manifest } = fixture();
manifest.playback.centers.url = "http://worker-006/centers";
await assert.rejects(
M49PhysicalSafetyPlaybackBuffer.open(resultId, {
fetcher: async () => Response.json(manifest),
}),
/sealed local API/,
);
});
@@ -74,24 +74,53 @@ test("M4.9T5 chunk keeps every missing-LiDAR cell explicitly UNOBSERVED", async
assert.deepEqual(new Set(chunk.frames[0].costmap.states), new Set([0]));
});
test("M4.9T5 viewer preloads one immutable binary playback pack", async () => {
const [source, contract] = await Promise.all([
test("M4.9T5 viewer prefers autonomous chunks and keeps a sealed legacy fallback", async () => {
const [source, visual, scene, contract] = await Promise.all([
readFile(
new URL("../src/workspaces/laboratory/M49TgsFullShadowEvidence.tsx", import.meta.url),
"utf8",
),
readFile(
new URL("../src/workspaces/laboratory/M4ReplayThreatVisual.tsx", import.meta.url),
"utf8",
),
readFile(
new URL("../src/components/laboratory/LaboratoryMetricEvidenceScene.tsx", import.meta.url),
"utf8",
),
readFile(
new URL("../src/core/laboratory/m49TgsFullShadow.ts", import.meta.url),
"utf8",
),
]);
assert.match(source, /fetchM49PhysicalSafetyPlaybackIdForSource/);
assert.match(source, /M49PhysicalSafetyPlaybackBuffer\.open/);
assert.match(source, /physicalPlayback\.frameIfResident/);
assert.match(source, /physicalPlayback\.prepare/);
assert.match(source, /fetchM49TgsFullShadowPlaybackPack/);
assert.match(source, /playbackProgress/);
assert.doesNotMatch(source, /fetchM49TgsFullShadowSpatialChunk/);
assert.match(source, /sampleAvailable: spatial\.sampleAvailable/);
assert.match(source, /sampleAvailable: frame\.sampleAvailable/);
assert.match(source, /packedCellsMapGravityLocal/);
assert.match(source, /playbackPack\.states\.subarray/);
assert.match(source, /playbackPack\.zBoundsM\.subarray/);
assert.doesNotMatch(source, /Array\.from\(\s*playbackPack\.states/);
assert.doesNotMatch(source, /centersXyM\.map\(/);
assert.match(source, /fetchE47SemanticSlamResult/);
assert.match(source, /next\.baseM4ResultId !== result\.source\.linkedVisualResultId/);
assert.match(source, /semantic=\{semantic \? \{/);
assert.match(
visual,
/classifiedSpatialFrame\s*&&\s*classifiedSpatialFrame\.sampleAvailable !== false/,
);
assert.doesNotMatch(visual, /classifiedSpatialFrame\?\.sampleAvailable !== false/);
assert.match(visual, /timelineFrame\.availableFrames\.find/);
assert.match(visual, /<LaboratoryMetricEvidenceScene/);
assert.doesNotMatch(
visual,
/\{\(!classifiedSpatialLayer \? spatialFrame : displayedClassifiedSpatialFrame\) \? \(/,
);
assert.match(scene, /useEffect\(\(\) => resetView\(\), \[mode, resetView\]\)/);
assert.match(contract, /linked_semantic_result_id/);
assert.match(contract, /missioncore\.m49-tgs-full-shadow-playback\/v1/);
});
@@ -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/,
@@ -173,6 +173,9 @@ test("recorded player keeps full-archive range fallback and uses bounded generat
assert.match(source, /pumpRecordedSegmentWindow/);
assert.match(source, /waitForRecordedVideoTarget/);
assert.match(source, /removeRecordedMediaRange/);
assert.match(source, /hasPresentedFrame/);
assert.match(source, /retainForwardFrame/);
assert.match(source, /candidateTarget\.sequence >= previousTarget\.sequence/);
assert.equal(recordedMediaDecodeStartSequence([1, 1491, 1501], 1500), 1491);
assert.deepEqual(
@@ -57,7 +57,10 @@ test("metric evidence keeps missing semantic assignments as context and exposes
assert.match(source, /recordedEvidenceSemanticCssColor/);
assert.match(source, /DynamicDrawUsage/);
assert.match(source, /classifiedMeshesRef/);
assert.match(source, /classifiedPackedCells/);
assert.match(source, /updatePointPositions/);
assert.match(source, /renderer\.info\.render\.calls/);
assert.match(source, /data-decision="performance"/);
});
test("semantic point alignment follows the last qualified spatial increment", async () => {