import assert from "node:assert/strict"; import { readFile } from "node:fs/promises"; import { after, before, test } from "node:test"; import { createServer } from "vite"; let server; let fetchM4ThreatReplayResult; let fetchM4ThreatVisual; let fetchM4ThreatTimeline; let fetchM4ThreatTimelineChunk; let selectM4ThreatTimelineFrame; let selectM4ThreatTimelineSequence; let advanceRecordedEvidencePlayback; const resultId = `m4-threat-replay-${"a".repeat(64)}`; before(async () => { server = await createServer({ appType: "custom", logLevel: "silent", server: { middlewareMode: true }, }); ({ fetchM4ThreatReplayResult, fetchM4ThreatVisual, fetchM4ThreatTimeline, fetchM4ThreatTimelineChunk, selectM4ThreatTimelineFrame, selectM4ThreatTimelineSequence, } = await server.ssrLoadModule("/src/core/laboratory/m4ReplayThreat.ts")); ({ advanceRecordedEvidencePlayback } = await server.ssrLoadModule( "/src/components/laboratory/useRecordedEvidencePlayback.ts", )); }); after(async () => { await server?.close(); }); function proposal(overrides = {}) { return { proposal_id: "proposal-1", bbox_xyxy: [100, 120, 240, 360], objectness: 0.91, semantic_hint: "person", occupied_support: false, range_m: null, threat_decision: "unknown", threat_reason_codes: ["camera-only-no-metric-geometry"], ...overrides, }; } function timelineFrame(sequence, sessionSeconds, overrides = {}) { return { schema_version: "missioncore.recorded-spatial-evidence-frame/v1", sequence, frame_id: `frame-${String(sequence).padStart(6, "0")}`, source_time_ns: Math.round(sessionSeconds * 1_000_000_000), session_seconds: sessionSeconds, source_available: true, spatial_available: true, point_cloud_body_xyz_m: [[1, 0, 0.1]], point_cloud_source_count: 1, point_cloud_sample_count: 1, point_cloud_layer: "current-increment", rolling_map_component_count: 0, metric_obstacles: [], camera_proposals: [], decision_counts: { threat: 0, "not-threat": 0, unknown: 0 }, camera_url: `/api/v1/laboratory/m4-threat/results/${resultId}/timeline/frames/${sequence}/camera`, authority: "replay-simulated", ...overrides, }; } test("M4.6 decodes accepted dual-evidence result without physical authority", async () => { const result = await fetchM4ThreatReplayResult({ fetcher: async () => new Response(JSON.stringify({ schema_version: "missioncore.m4-threat-replay-catalog/v1", items: [{ schema_version: "missioncore.m4-threat-replay-view/v1", result_id: resultId, created_at_utc: "2026-08-05T15:36:01.553Z", status: "accepted", profile_id: "m4-ravnoves00-virtual-corridor/v1", rig_profile_id: "virtual-base-footprint-1000x600/v2", corridor_profile_id: "ravnoves00-forward-corridor-8m/v2", source_result_ids: { detector: `m4-detector-replay-${"b".repeat(64)}`, geometry: `m4-geometry-replay-${"c".repeat(64)}`, temporal: `m4-temporal-replay-${"d".repeat(64)}`, }, metrics: { decisions: { threat: 8010, "not-threat": 6610, unknown: 60832 }, evidence: { "camera-only": 10158, "current-metric": 28081, "rolling-map-retained": 70989, "stale-or-held": 38025 }, fixtures: { critical: 4, critical_false_not_threat: 0, passed: 9, total: 9 }, runtime: { frames_per_second: 116.4, provider_latency_p50_ms: 4.3, provider_latency_p95_ms: 19.8, provider_latency_max_ms: 194.3, }, body_frame: { available: 3928, qualified: 3861, rejected: 67, camera_forward_alignment_deg: { p95: 8.439, maximum: 24.252 }, }, reason_counts: { "geometry-only-evidence": 21958 }, }, configuration: { virtual_body_m: [1, 0.6], nominal_sensor_height_m: 1.25, forward_corridor_m: 8, prediction_horizon_seconds: 5, body_frame: { origin: "local-surface-vertical-projection", up: "vendor-slam-map-gravity-axis", forward: "smoothed-slam-trajectory-validated-by-camera-axis", }, }, limitations: ["replay only"], accepted: true, authority: "replay-simulated", physical_collision_accepted: false, actuation_allowed: false, }], }), { status: 200 }), }); assert.equal(result.resultId, resultId); assert.equal(result.metrics.evidence.currentMetric, 28081); assert.equal(result.metrics.fixtures.criticalFalseNotThreat, 0); assert.equal(result.metrics.bodyFrame.qualified, 3861); assert.equal(result.metrics.bodyFrame.cameraForwardAlignmentDeg.p95, 8.439); assert.deepEqual(result.configuration.virtualBodyM, [1, 0.6]); assert.equal(result.configuration.bodyFrame.up, "vendor-slam-map-gravity-axis"); }); test("M4.6 binds exact CAMERA and metric 3D evidence to one replay frame", async () => { const frame = await fetchM4ThreatVisual(resultId, 1, { fetcher: async () => new Response(JSON.stringify({ schema_version: "missioncore.perception-threat-visual-frame/v1", result_id: resultId, camera_url: `/api/v1/laboratory/m4-threat/results/${resultId}/visuals/1/camera`, ordinal: 1, sequence: 20, frame_id: "frame-000020", source_time_ns: 37421857292, point_cloud_body_xyz_m: [[1, 0, 0.1], [2, 0.2, 0.3]], point_cloud_source_count: 12000, point_cloud_sample_count: 2, metric_obstacles: [{ component_id: "temporal-20-1", state: "current", motion: "moving", centroid_body_xyz_m: [2, 0.1, 0.4], cell_centers_body_xyz_m: [[2, 0.1, 0.4]], assessment: { component_id: "temporal-20-1", decision: "threat", corridor_intersection: "intersects", relative_speed_mps: 1.2, closest_approach_m: 0.4, ttc_seconds: 1.6, reason_codes: ["geometry-only-evidence"], }, }], camera_proposals: [proposal()], rig: { length_m: 1, width_m: 0.6, nominal_sensor_height_m: 1.25 }, corridor: { forward_length_m: 8, rear_margin_m: 0.5, half_width_m: 0.5, prediction_horizon_seconds: 5, }, }), { status: 200 }), }); assert.equal(frame.sequence, 20); assert.match(frame.cameraUrl, /\/visuals\/1\/camera$/); assert.equal(frame.metricObstacles[0].assessment.decision, "threat"); assert.equal(frame.cameraProposals[0].threatDecision, "unknown"); assert.equal(frame.pointCloudSampleCount, 2); }); test("M4.6 v2 keeps CURRENT INCREMENT separate from ROLLING MAP", async () => { const frame = await fetchM4ThreatVisual(resultId, 14, { fetcher: async () => new Response(JSON.stringify({ schema_version: "missioncore.perception-threat-visual-frame/v2", result_id: resultId, camera_url: `/api/v1/laboratory/m4-threat/results/${resultId}/visuals/14/camera`, ordinal: 14, sequence: 1880, frame_id: "frame-001880", source_time_ns: 223304857292, point_cloud_body_xyz_m: [[1, 0, 0.1]], point_cloud_source_count: 1652, point_cloud_sample_count: 1652, point_cloud_layer: "current-increment", rolling_map_component_count: 10, metric_obstacles: [{ component_id: "rolling-sphere-near", state: "retained", motion: "unknown", centroid_body_xyz_m: [0.76, -0.27, 0.38], cell_centers_body_xyz_m: [[0.52, -0.3, 0.08]], assessment: { component_id: "rolling-sphere-near", decision: "threat", corridor_intersection: "intersects", relative_speed_mps: null, closest_approach_m: 0.1, ttc_seconds: null, reason_codes: ["retained-corridor-intersection"], }, }], camera_proposals: [], rig: { length_m: 1, width_m: 0.6, nominal_sensor_height_m: 1.25 }, corridor: { forward_length_m: 8, rear_margin_m: 0.5, half_width_m: 0.5, prediction_horizon_seconds: 5, }, }), { status: 200 }), }); assert.equal(frame.pointCloudLayer, "current-increment"); assert.equal(frame.rollingMapComponentCount, 10); assert.equal(frame.metricObstacles[0].state, "retained"); assert.equal(frame.metricObstacles[0].assessment.decision, "threat"); }); test("M4.6 timeline keeps only a compact index and decodes bounded spatial chunks", async () => { const frameTimesNs = Array.from( { length: 4489 }, (_, index) => 35_421_857_292 + index * 100_000_000, ); const timeline = await fetchM4ThreatTimeline(resultId, { fetcher: async () => new Response(JSON.stringify({ schema_version: "missioncore.recorded-spatial-evidence-timeline/v1", result_id: resultId, recorded_source: { session_id: "20260720T065719Z_viewer_live", source_id: "RAVNOVES00", synchronization: "host-arrival-best-effort", }, image_width: 800, image_height: 600, frame_count: 4489, frame_times_ns: frameTimesNs, timeline_start_seconds: 35.421857292, timeline_end_seconds: 484.221857292, nominal_frame_interval_seconds: 0.1, nominal_rate_hz: 10, max_chunk_frames: 24, point_sample_limit: 2000, rig: { length_m: 1, width_m: 0.6, nominal_sensor_height_m: 1.25 }, corridor: { forward_length_m: 8, rear_margin_m: 0.5, half_width_m: 0.5, prediction_horizon_seconds: 5, }, authority: "replay-simulated", }), { status: 200 }), }); assert.equal(timeline.frameTimesNs.length, 4489); assert.equal(selectM4ThreatTimelineSequence(timeline.frameTimesNs, 35.50), 1); const chunk = await fetchM4ThreatTimelineChunk(resultId, 0, 2, { fetcher: async () => new Response(JSON.stringify({ schema_version: "missioncore.recorded-spatial-evidence-chunk/v1", result_id: resultId, start_sequence: 0, frame_count: 2, next_sequence: 2, frames: [ timelineFrame(0, 35.421857292), timelineFrame(1, 35.521857292, { camera_proposals: [proposal()], decision_counts: { threat: 0, "not-threat": 0, unknown: 1 }, }), ], authority: "replay-simulated", }), { status: 200 }), }); assert.equal(chunk.frames[1].cameraProposals[0].rangeM, null); assert.equal(selectM4ThreatTimelineFrame(chunk.frames, 35.50).sequence, 1); }); test("recorded evidence clock advances by selected rate and stops at the sealed end", () => { const range = { startSeconds: 10, endSeconds: 20 }; assert.deepEqual( advanceRecordedEvidencePlayback( { currentSeconds: 12, playing: true, rate: 2 }, 1.5, range, ), { currentSeconds: 15, playing: true, rate: 2 }, ); assert.deepEqual( advanceRecordedEvidencePlayback( { currentSeconds: 19.5, playing: true, rate: 1 }, 1, range, ), { currentSeconds: 20, playing: false, rate: 1 }, ); }); test("M4.6 viewer reuses shared camera, video and metric evidence renderers", async () => { const [visual, imageScene, videoScene, metricScene] = await Promise.all([ readFile(new URL("../src/workspaces/laboratory/M4ReplayThreatVisual.tsx", 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"), readFile(new URL("../src/components/laboratory/LaboratoryMetricEvidenceScene.tsx", import.meta.url), "utf8"), ]); assert.match(visual, /