feat(lab): publish M4.7 Worker graph evidence
This commit is contained in:
@@ -37,8 +37,10 @@ import { fetchE46IGroundingDinoFullReplay } from "./e46iGroundingDinoFullReplay"
|
||||
import { fetchE46JRawFisheyeRealtime } from "./e46jRawFisheyeRealtime";
|
||||
import { fetchE47SemanticSlamResult } from "./e47SemanticSlam";
|
||||
import { fetchM4ThreatReplayResult } from "./m4ReplayThreat";
|
||||
import { fetchM47ReferenceGraphLab } from "./m47ReferenceGraph";
|
||||
|
||||
export type AdvancedLaboratoryWorkId =
|
||||
| "m47-reference-graph-shadow"
|
||||
| "m4-replay-threat"
|
||||
| "l3-pointpillars-visual-audit"
|
||||
| "l31-pointpillars-ravnoves"
|
||||
@@ -80,6 +82,7 @@ export interface AdvancedLaboratoryIndexItem {
|
||||
}
|
||||
|
||||
const WORK_IDS: readonly AdvancedLaboratoryWorkId[] = [
|
||||
"m47-reference-graph-shadow",
|
||||
"m4-replay-threat",
|
||||
"l3-pointpillars-visual-audit",
|
||||
"l31-pointpillars-ravnoves",
|
||||
@@ -116,6 +119,7 @@ const WORK_IDS: readonly AdvancedLaboratoryWorkId[] = [
|
||||
];
|
||||
|
||||
const RESULT_PREFIX: Readonly<Record<AdvancedLaboratoryWorkId, string>> = {
|
||||
"m47-reference-graph-shadow": "m47-reference-graph-lab",
|
||||
"m4-replay-threat": "m4-threat-replay",
|
||||
"l3-pointpillars-visual-audit": "l3-pointpillars-visual-audit",
|
||||
"l31-pointpillars-ravnoves": "l31-pointpillars-ravnoves",
|
||||
@@ -159,6 +163,7 @@ export function isAdvancedLaboratoryWorkId(
|
||||
|
||||
export function emptyAdvancedLaboratoryResults(): AdvancedLaboratoryResults {
|
||||
return {
|
||||
m47Graph: null,
|
||||
m4Threat: null,
|
||||
l3: null,
|
||||
l31: null,
|
||||
@@ -283,7 +288,8 @@ export function advancedLaboratoryResultAvailable(
|
||||
workId: AdvancedLaboratoryWorkId,
|
||||
results: AdvancedLaboratoryResults,
|
||||
): boolean {
|
||||
return workId === "m4-replay-threat" ? results.m4Threat !== null
|
||||
return workId === "m47-reference-graph-shadow" ? results.m47Graph !== null
|
||||
: workId === "m4-replay-threat" ? results.m4Threat !== null
|
||||
: workId === "l3-pointpillars-visual-audit" ? results.l3 !== null
|
||||
: workId === "l31-pointpillars-ravnoves" ? results.l31 !== null
|
||||
: workId === "l32-pointpillars-camera-review" ? results.l32 !== null
|
||||
@@ -323,13 +329,24 @@ export async function fetchAdvancedLaboratoryResult(
|
||||
{
|
||||
fetcher = fetch,
|
||||
signal,
|
||||
resultId,
|
||||
}: {
|
||||
fetcher?: LaboratoryFetch;
|
||||
signal?: AbortSignal;
|
||||
resultId?: string;
|
||||
} = {},
|
||||
): Promise<AdvancedLaboratoryResults> {
|
||||
const results = emptyAdvancedLaboratoryResults();
|
||||
if (workId === "m4-replay-threat") {
|
||||
if (workId === "m47-reference-graph-shadow") {
|
||||
if (!resultId) {
|
||||
throw new AdvancedLaboratoryContractError("M4.7 LAB identity не выбрана.");
|
||||
}
|
||||
results.m47Graph = await fetchM47ReferenceGraphLab({
|
||||
resultId,
|
||||
fetcher,
|
||||
signal,
|
||||
});
|
||||
} else if (workId === "m4-replay-threat") {
|
||||
results.m4Threat = await fetchM4ThreatReplayResult({ fetcher, signal });
|
||||
} else if (workId === "l3-pointpillars-visual-audit") {
|
||||
results.l3 = await fetchL3PointPillarsVisualAudit({ fetcher, signal });
|
||||
|
||||
@@ -33,8 +33,10 @@ import type { E46IGroundingDinoFullReplayResult } from "./e46iGroundingDinoFullR
|
||||
import type { E46JRawFisheyeRealtimeResult } from "./e46jRawFisheyeRealtime";
|
||||
import type { E47SemanticSlamResult } from "./e47SemanticSlam";
|
||||
import type { M4ThreatReplayResult } from "./m4ReplayThreat";
|
||||
import type { M47ReferenceGraphLabResult } from "./m47ReferenceGraph";
|
||||
|
||||
export interface AdvancedLaboratoryResults {
|
||||
m47Graph: M47ReferenceGraphLabResult | null;
|
||||
m4Threat: M4ThreatReplayResult | null;
|
||||
l3: L3PointPillarsVisualAuditResult | null;
|
||||
l31: L31PointPillarsRavnovesResult | null;
|
||||
|
||||
@@ -967,7 +967,7 @@ export async function fetchAdvancedLaboratoryResults({
|
||||
const e39 = settledCatalogValue(settled[7]);
|
||||
const e40 = settledCatalogValue(settled[8]);
|
||||
return {
|
||||
m4Threat: null,
|
||||
m47Graph: null, m4Threat: null,
|
||||
l3: null, l31: null,
|
||||
l32: null,
|
||||
l33: null,
|
||||
|
||||
@@ -0,0 +1,223 @@
|
||||
import {
|
||||
fetchLaboratoryEvidenceReport,
|
||||
type JsonValue,
|
||||
} from "./evidenceReport";
|
||||
import {
|
||||
fetchM4ThreatReplayResult,
|
||||
type M4ThreatReplayResult,
|
||||
} from "./m4ReplayThreat";
|
||||
|
||||
export interface M47ReferenceGraphLabResult {
|
||||
resultId: string;
|
||||
createdAtUtc: string;
|
||||
graphResultId: string;
|
||||
linkedVisualResultId: string;
|
||||
graphId: "reference-perception-graph/v2";
|
||||
worker: {
|
||||
id: "worker-006";
|
||||
node: string;
|
||||
artifactSha256: string;
|
||||
codeRevision: string;
|
||||
elapsedSeconds: number;
|
||||
};
|
||||
frames: {
|
||||
expected: 4489;
|
||||
admitted: 4489;
|
||||
delivered: 4489;
|
||||
};
|
||||
parityMismatchCounts: Readonly<Record<
|
||||
| "source_binding"
|
||||
| "current"
|
||||
| "rolling_retained"
|
||||
| "held"
|
||||
| "expired"
|
||||
| "camera_uncertainty"
|
||||
| "threat_assessments",
|
||||
0
|
||||
>>;
|
||||
queueHighWatermarks: Readonly<Record<
|
||||
"detector" | "geometry" | "temporal" | "rolling" | "threat",
|
||||
number
|
||||
>>;
|
||||
limitations: readonly string[];
|
||||
visual: M4ThreatReplayResult;
|
||||
}
|
||||
|
||||
type LaboratoryFetch = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
|
||||
|
||||
class M47ReferenceGraphContractError extends Error {}
|
||||
|
||||
function object(value: unknown, label: string): Record<string, unknown> {
|
||||
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
||||
throw new M47ReferenceGraphContractError(`${label}: ожидался объект.`);
|
||||
}
|
||||
return value as Record<string, unknown>;
|
||||
}
|
||||
|
||||
function text(value: unknown, label: string): string {
|
||||
if (typeof value !== "string" || !value.trim()) {
|
||||
throw new M47ReferenceGraphContractError(`${label}: ожидалась строка.`);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function exact<T extends string | number | boolean>(
|
||||
value: unknown,
|
||||
expected: T,
|
||||
label: string,
|
||||
): T {
|
||||
if (value !== expected) {
|
||||
throw new M47ReferenceGraphContractError(`${label}: нарушен контракт.`);
|
||||
}
|
||||
return expected;
|
||||
}
|
||||
|
||||
function finite(value: unknown, label: string): number {
|
||||
if (typeof value !== "number" || !Number.isFinite(value) || value < 0) {
|
||||
throw new M47ReferenceGraphContractError(`${label}: ожидалось неотрицательное число.`);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function digest(value: unknown, label: string, length: 40 | 64): string {
|
||||
const parsed = text(value, label);
|
||||
if (!new RegExp(`^[a-f0-9]{${length}}$`).test(parsed)) {
|
||||
throw new M47ReferenceGraphContractError(`${label}: нарушена digest-идентичность.`);
|
||||
}
|
||||
return parsed;
|
||||
}
|
||||
|
||||
function zeroParity(value: unknown): M47ReferenceGraphLabResult["parityMismatchCounts"] {
|
||||
const document = object(value, "M4.7 parity");
|
||||
const keys = [
|
||||
"source_binding",
|
||||
"current",
|
||||
"rolling_retained",
|
||||
"held",
|
||||
"expired",
|
||||
"camera_uncertainty",
|
||||
"threat_assessments",
|
||||
] as const;
|
||||
if (
|
||||
Object.keys(document).length !== keys.length
|
||||
|| keys.some((key) => document[key] !== 0)
|
||||
) {
|
||||
throw new M47ReferenceGraphContractError("M4.7 parity: обнаружено расхождение.");
|
||||
}
|
||||
return Object.fromEntries(keys.map((key) => [key, 0])) as unknown as (
|
||||
M47ReferenceGraphLabResult["parityMismatchCounts"]
|
||||
);
|
||||
}
|
||||
|
||||
function queueWatermarks(
|
||||
value: unknown,
|
||||
): M47ReferenceGraphLabResult["queueHighWatermarks"] {
|
||||
const document = object(value, "M4.7 queue watermarks");
|
||||
const keys = ["detector", "geometry", "temporal", "rolling", "threat"] as const;
|
||||
if (Object.keys(document).length !== keys.length) {
|
||||
throw new M47ReferenceGraphContractError("M4.7 queues: состав стадий изменился.");
|
||||
}
|
||||
return Object.fromEntries(keys.map((key) => {
|
||||
const watermark = finite(document[key], `M4.7 queue ${key}`);
|
||||
if (!Number.isInteger(watermark) || watermark > 2) {
|
||||
throw new M47ReferenceGraphContractError(`M4.7 queue ${key}: нарушена граница.`);
|
||||
}
|
||||
return [key, watermark];
|
||||
})) as unknown as M47ReferenceGraphLabResult["queueHighWatermarks"];
|
||||
}
|
||||
|
||||
function stringArray(value: JsonValue | undefined, label: string): readonly string[] {
|
||||
if (!Array.isArray(value) || value.some((item) => typeof item !== "string" || !item.trim())) {
|
||||
throw new M47ReferenceGraphContractError(`${label}: ожидался список строк.`);
|
||||
}
|
||||
return value as string[];
|
||||
}
|
||||
|
||||
export async function fetchM47ReferenceGraphLab({
|
||||
resultId,
|
||||
fetcher = fetch,
|
||||
signal,
|
||||
}: {
|
||||
resultId: string;
|
||||
fetcher?: LaboratoryFetch;
|
||||
signal?: AbortSignal;
|
||||
}): Promise<M47ReferenceGraphLabResult> {
|
||||
if (!/^m47-reference-graph-lab-[a-f0-9]{64}$/.test(resultId)) {
|
||||
throw new M47ReferenceGraphContractError("M4.7 result id: нарушена идентичность.");
|
||||
}
|
||||
const evidence = await fetchLaboratoryEvidenceReport({
|
||||
workId: "m47-reference-graph-shadow",
|
||||
resultId,
|
||||
fetcher,
|
||||
signal,
|
||||
});
|
||||
const report = evidence.rawReport;
|
||||
exact(
|
||||
report.schema_version,
|
||||
"missioncore.reference-perception-graph-lab-report/v1",
|
||||
"M4.7 report schema",
|
||||
);
|
||||
exact(report.result_id, resultId, "M4.7 report result");
|
||||
const source = object(report.source, "M4.7 source");
|
||||
const method = object(report.method, "M4.7 method");
|
||||
const execution = object(report.execution, "M4.7 execution");
|
||||
const metrics = object(report.metrics, "M4.7 metrics");
|
||||
const frames = object(metrics.frames, "M4.7 frames");
|
||||
const acceptance = object(report.acceptance, "M4.7 acceptance");
|
||||
const authority = object(report.authority, "M4.7 authority");
|
||||
const visualEvidence = object(report.visual_evidence, "M4.7 visual evidence");
|
||||
exact(acceptance.accepted, true, "M4.7 acceptance");
|
||||
exact(authority.commands_enabled, false, "M4.7 commands");
|
||||
exact(authority.actuation_allowed, false, "M4.7 actuation");
|
||||
exact(authority.navigation_or_safety_accepted, false, "M4.7 safety authority");
|
||||
exact(visualEvidence.shared_recorded_clock, true, "M4.7 recorded clock");
|
||||
exact(
|
||||
visualEvidence.video_camera_3d_plan_available,
|
||||
true,
|
||||
"M4.7 visual evidence",
|
||||
);
|
||||
const linkedVisualResultId = text(
|
||||
visualEvidence.linked_result_id,
|
||||
"M4.7 linked visual result",
|
||||
);
|
||||
if (!/^m4-threat-replay-[a-f0-9]{64}$/.test(linkedVisualResultId)) {
|
||||
throw new M47ReferenceGraphContractError("M4.7 visual binding: нарушена идентичность.");
|
||||
}
|
||||
const visual = await fetchM4ThreatReplayResult({
|
||||
resultId: linkedVisualResultId,
|
||||
fetcher,
|
||||
signal,
|
||||
});
|
||||
if (!visual || visual.resultId !== linkedVisualResultId) {
|
||||
throw new M47ReferenceGraphContractError(
|
||||
"M4.7 visual binding: сервер вернул другой replay result.",
|
||||
);
|
||||
}
|
||||
const graphResultId = text(source.graph_result_id, "M4.7 graph result");
|
||||
if (!/^m47-reference-graph-[a-f0-9]{64}$/.test(graphResultId)) {
|
||||
throw new M47ReferenceGraphContractError("M4.7 graph result: нарушена идентичность.");
|
||||
}
|
||||
return {
|
||||
resultId,
|
||||
createdAtUtc: text(evidence.createdAtUtc, "M4.7 created at"),
|
||||
graphResultId,
|
||||
linkedVisualResultId,
|
||||
graphId: exact(method.graph_id, "reference-perception-graph/v2", "M4.7 graph id"),
|
||||
worker: {
|
||||
id: exact(execution.worker_id, "worker-006", "M4.7 worker"),
|
||||
node: text(execution.worker_node, "M4.7 worker node"),
|
||||
artifactSha256: digest(execution.artifact_sha256, "M4.7 artifact", 64),
|
||||
codeRevision: digest(execution.code_revision, "M4.7 revision", 40),
|
||||
elapsedSeconds: finite(execution.elapsed_seconds, "M4.7 elapsed"),
|
||||
},
|
||||
frames: {
|
||||
expected: exact(frames.expected, 4489, "M4.7 expected frames"),
|
||||
admitted: exact(frames.admitted, 4489, "M4.7 admitted frames"),
|
||||
delivered: exact(frames.delivered, 4489, "M4.7 delivered frames"),
|
||||
},
|
||||
parityMismatchCounts: zeroParity(metrics.parity_mismatch_counts),
|
||||
queueHighWatermarks: queueWatermarks(metrics.queue_high_watermarks),
|
||||
limitations: stringArray(report.limitations, "M4.7 limitations"),
|
||||
visual,
|
||||
};
|
||||
}
|
||||
@@ -315,22 +315,59 @@ function parseMetricVisual(value: unknown): M4ThreatMetricVisual {
|
||||
}
|
||||
|
||||
export async function fetchM4ThreatReplayResult({
|
||||
resultId: requestedResultId,
|
||||
fetcher = fetch,
|
||||
signal,
|
||||
}: {
|
||||
resultId?: string;
|
||||
fetcher?: LaboratoryFetch;
|
||||
signal?: AbortSignal;
|
||||
} = {}): Promise<M4ThreatReplayResult | null> {
|
||||
const response = await fetcher("/api/v1/laboratory/m4-threat/results?limit=1", {
|
||||
headers: { Accept: "application/json" },
|
||||
signal,
|
||||
});
|
||||
if (
|
||||
requestedResultId !== undefined
|
||||
&& !/^m4-threat-replay-[a-f0-9]{64}$/.test(requestedResultId)
|
||||
) {
|
||||
throw new M4ThreatContractError("M4.6 requested result id: нарушена идентичность.");
|
||||
}
|
||||
let response = await fetcher(
|
||||
requestedResultId === undefined
|
||||
? "/api/v1/laboratory/m4-threat/results?limit=1"
|
||||
: `/api/v1/laboratory/m4-threat/results/${requestedResultId}`,
|
||||
{ headers: { Accept: "application/json" }, signal },
|
||||
);
|
||||
// Rolling deployments may briefly pair the new UI with the previous read-only
|
||||
// API. Preserve exact-result binding by selecting the requested result from
|
||||
// the catalog instead of silently falling back to whatever happens to be latest.
|
||||
let catalogFallback = false;
|
||||
if (requestedResultId !== undefined && response.status === 404) {
|
||||
response = await fetcher("/api/v1/laboratory/m4-threat/results?limit=10", {
|
||||
headers: { Accept: "application/json" },
|
||||
signal,
|
||||
});
|
||||
catalogFallback = true;
|
||||
}
|
||||
if (!response.ok) throw new M4ThreatContractError(`M4.6 LAB недоступен: HTTP ${response.status}.`);
|
||||
const catalog = object(await response.json(), "M4.6 catalog");
|
||||
exact(catalog.schema_version, "missioncore.m4-threat-replay-catalog/v1", "M4.6 catalog schema");
|
||||
const items = array(catalog.items, "M4.6 results");
|
||||
if (!items.length) return null;
|
||||
const item = object(items[0], "M4.6 result");
|
||||
const payload = await response.json();
|
||||
let item: Record<string, unknown>;
|
||||
if (requestedResultId === undefined || catalogFallback) {
|
||||
const catalog = object(payload, "M4.6 catalog");
|
||||
exact(catalog.schema_version, "missioncore.m4-threat-replay-catalog/v1", "M4.6 catalog schema");
|
||||
const items = array(catalog.items, "M4.6 results");
|
||||
if (!items.length) return null;
|
||||
const selected = requestedResultId === undefined
|
||||
? items[0]
|
||||
: items.find((candidate) => (
|
||||
typeof candidate === "object"
|
||||
&& candidate !== null
|
||||
&& (candidate as Record<string, unknown>).result_id === requestedResultId
|
||||
));
|
||||
if (selected === undefined) {
|
||||
throw new M4ThreatContractError("M4.6 requested result: точный результат отсутствует в каталоге.");
|
||||
}
|
||||
item = object(selected, "M4.6 result");
|
||||
} else {
|
||||
item = object(payload, "M4.6 result");
|
||||
}
|
||||
exact(item.schema_version, "missioncore.m4-threat-replay-view/v1", "M4.6 view schema");
|
||||
exact(item.accepted, true, "M4.6 acceptance");
|
||||
exact(item.authority, "replay-simulated", "M4.6 authority");
|
||||
@@ -349,8 +386,12 @@ export async function fetchM4ThreatReplayResult({
|
||||
const configuration = object(item.configuration, "M4.6 configuration");
|
||||
const configuredBodyFrame = object(configuration.body_frame, "M4.6 configured body frame");
|
||||
const sourceResultIds = object(item.source_result_ids, "M4.6 sources");
|
||||
const parsedResultId = resultId(item.result_id);
|
||||
if (requestedResultId !== undefined) {
|
||||
exact(parsedResultId, requestedResultId, "M4.6 requested result");
|
||||
}
|
||||
return {
|
||||
resultId: resultId(item.result_id),
|
||||
resultId: parsedResultId,
|
||||
createdAtUtc: text(item.created_at_utc, "M4.6 created"),
|
||||
profileId: text(item.profile_id, "M4.6 profile"),
|
||||
rigProfileId: text(item.rig_profile_id, "M4.6 rig"),
|
||||
|
||||
@@ -41,6 +41,7 @@ import { E46IGroundingDinoFullReplayResultView } from "./E46IGroundingDinoFullRe
|
||||
import { E46JRawFisheyeRealtimeResultView } from "./E46JRawFisheyeRealtimeResult";
|
||||
import { E47SemanticSlamResultView } from "./E47SemanticSlamResult";
|
||||
import { M4ReplayThreatResultView } from "./M4ReplayThreatResult";
|
||||
import { M47ReferenceGraphResultView } from "./M47ReferenceGraphResult";
|
||||
|
||||
export { isAdvancedLaboratoryWorkId };
|
||||
export type { AdvancedLaboratoryWorkId };
|
||||
@@ -83,6 +84,9 @@ export function AdvancedLaboratoryResult({
|
||||
failedSessionId: string | null;
|
||||
replayError: string | null;
|
||||
}) {
|
||||
if (workId === "m47-reference-graph-shadow" && results.m47Graph) {
|
||||
return <M47ReferenceGraphResultView rigLabel={rigLabel} result={results.m47Graph} />;
|
||||
}
|
||||
if (workId === "m4-replay-threat" && results.m4Threat) {
|
||||
return <M4ReplayThreatResultView rigLabel={rigLabel} result={results.m4Threat} />;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
import {
|
||||
LaboratoryEvidence,
|
||||
LaboratoryResultSummary,
|
||||
LaboratorySummary,
|
||||
LaboratoryWorkTemplate,
|
||||
} from "../../components/laboratory/LaboratoryPresentation";
|
||||
import type { M47ReferenceGraphLabResult } from "../../core/laboratory/m47ReferenceGraph";
|
||||
import { formatNumber } from "../../presentation";
|
||||
import { M4ReplayThreatVisual } from "./M4ReplayThreatVisual";
|
||||
|
||||
export function M47ReferenceGraphResultView({
|
||||
rigLabel,
|
||||
result,
|
||||
}: {
|
||||
rigLabel: string;
|
||||
result: M47ReferenceGraphLabResult;
|
||||
}) {
|
||||
const parityDimensions = Object.keys(result.parityMismatchCounts).length;
|
||||
const maximumQueue = Math.max(...Object.values(result.queueHighWatermarks));
|
||||
return (
|
||||
<LaboratoryWorkTemplate
|
||||
summary={(
|
||||
<LaboratorySummary
|
||||
title="M4.7 · canonical reference graph shadow"
|
||||
description="Полный source→detector→geometry→temporal/motion→rolling→threat граф выполнен на Worker 006 и побайтно сопоставлен с принятыми M4.5R/M4.6 ledgers. Ни один live-контур и ни одна команда не участвовали."
|
||||
status="4489/4489 · lossless graph parity passed"
|
||||
statusTone="success"
|
||||
facts={[
|
||||
{
|
||||
label: "Конфигурация",
|
||||
value: `${rigLabel} · RIGHT camera + LiDAR · recorded replay`,
|
||||
},
|
||||
{
|
||||
label: "Исполнение",
|
||||
value: `${result.worker.id} / ${result.worker.node} · ${formatNumber(result.worker.elapsedSeconds, 1)} с`,
|
||||
},
|
||||
{
|
||||
label: "Artifact",
|
||||
value: `${result.worker.artifactSha256.slice(0, 12)}… · commit ${result.worker.codeRevision.slice(0, 8)}`,
|
||||
},
|
||||
{
|
||||
label: "Graph accounting",
|
||||
value: `${result.frames.admitted}/${result.frames.expected} admitted · ${result.frames.delivered} delivered`,
|
||||
},
|
||||
{
|
||||
label: "Визуал",
|
||||
value: "VIDEO/CAMERA/3D/PLAN · единый recorded clock · exact M4.6 ledger binding",
|
||||
},
|
||||
]}
|
||||
brief={{
|
||||
question: "Сохраняет ли собранный канонический perception graph уже принятые результаты каждого кадра без потерь, перестановочных артефактов и скрытого backpressure?",
|
||||
approach: "Worker 006 выполнил все 4489 кадров в lossless replay через изолированный Triton и временный graph container. Результат связан с точным artifact SHA, commit, container identity и двумя принятыми parity-ledgers. Визуальный слой использует тот же threat/temporal payload, поэтому его можно проверять на общем таймлайне.",
|
||||
principalResult: `${parityDimensions}/${parityDimensions} parity dimensions имеют ноль расхождений; максимальная заполненность каждой bounded queue — ${maximumQueue}. Все ${result.frames.delivered} кадров завершились delivered.`,
|
||||
limitation: "Это принятие сборки графа на recorded replay. Оно не доказывает независимую object-level точность, физический live, навигационную безопасность или готовность выдавать команды моторам.",
|
||||
}}
|
||||
method={{
|
||||
completeness: "complete",
|
||||
executionClass: "hybrid",
|
||||
pipelineId: result.graphId,
|
||||
components: [
|
||||
{
|
||||
kind: "source",
|
||||
name: result.graphResultId,
|
||||
version: "lossless-replay",
|
||||
role: "immutable 4489-frame canonical graph output",
|
||||
identitySha256: result.graphResultId.split("-").at(-1) ?? null,
|
||||
},
|
||||
{
|
||||
kind: "source",
|
||||
name: result.linkedVisualResultId,
|
||||
version: "exact ledger parity",
|
||||
role: "synchronized VIDEO/CAMERA/3D/PLAN evidence",
|
||||
identitySha256: result.linkedVisualResultId.split("-").at(-1) ?? null,
|
||||
},
|
||||
{
|
||||
kind: "algorithm",
|
||||
name: "canonical reference perception graph",
|
||||
version: result.graphId,
|
||||
role: "source-neutral perception assembly without command authority",
|
||||
identitySha256: result.worker.artifactSha256,
|
||||
},
|
||||
],
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
evidence={(
|
||||
<LaboratoryEvidence
|
||||
eyebrow="M4.7 VISUAL EVIDENCE · VIDEO / CAMERA / 3D / PLAN"
|
||||
title="Синхронная проверка accepted graph payload на общем recorded timeline"
|
||||
kind="diagnostic-model"
|
||||
resizable
|
||||
>
|
||||
<M4ReplayThreatVisual resultId={result.visual.resultId} />
|
||||
</LaboratoryEvidence>
|
||||
)}
|
||||
result={(
|
||||
<LaboratoryResultSummary
|
||||
title="Каноническая сборка графа принята; открыт object-centric gate"
|
||||
status="Зелёный: graph assembly parity · жёлтый: independent object truth ещё отсутствует"
|
||||
statusTone="warning"
|
||||
metrics={[
|
||||
{
|
||||
label: "Replay frames",
|
||||
value: `${result.frames.delivered}/${result.frames.expected}`,
|
||||
hint: `${formatNumber(result.worker.elapsedSeconds, 1)} с на Worker 006`,
|
||||
},
|
||||
{
|
||||
label: "Parity",
|
||||
value: `${parityDimensions}/${parityDimensions} · 0 mismatch`,
|
||||
hint: "source/current/rolling/held/expired/camera/threat",
|
||||
},
|
||||
{
|
||||
label: "Queue high-water",
|
||||
value: String(maximumQueue),
|
||||
hint: "bounded on every graph stage",
|
||||
},
|
||||
{
|
||||
label: "Authority",
|
||||
value: "OFF",
|
||||
hint: "commands=false · actuation=false",
|
||||
},
|
||||
]}
|
||||
conclusion={{
|
||||
proved: "Канонический граф полностью обработал immutable RAVNOVES00 и сохранил уже принятые temporal/threat решения для каждого кадра. Runtime provenance от Worker 006 до LAB результата замкнут хэшами.",
|
||||
notProved: "Не доказаны независимая полнота/точность детекции объектов, live realtime на машине, измеренная геометрия корпуса, collision safety, планирование движения и управление моторами.",
|
||||
decision: "Считать M4.7 graph assembly завершённым и переходить к следующей лаборатории: независимому object-centric detection gate с визуальным разбором miss/duplicate/geometry ошибок.",
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -63,6 +63,13 @@ interface KnownWorkDefinition {
|
||||
const rig = (rigLabel: string): string => rigLabel.trim() || "Сенсорный риг";
|
||||
|
||||
const KNOWN_WORKS: Readonly<Record<Exclude<LaboratoryWorkId, `session:${string}`>, KnownWorkDefinition>> = {
|
||||
"m47-reference-graph-shadow": {
|
||||
profileId: "rig-dual-evidence-virtual-corridor-v1",
|
||||
profileName: (rigLabel) => `${rig(rigLabel)} RIGHT · Camera + LiDAR dual evidence`,
|
||||
experimentId: "m47-reference-perception-graph-shadow",
|
||||
experimentName: "RAVNOVES00 canonical reference graph",
|
||||
variantName: "M4.7 · Worker 006 · lossless graph parity",
|
||||
},
|
||||
"m4-replay-threat": {
|
||||
profileId: "rig-dual-evidence-virtual-corridor-v1",
|
||||
profileName: (rigLabel) => `${rig(rigLabel)} RIGHT · Camera + LiDAR dual evidence`,
|
||||
|
||||
@@ -18,6 +18,7 @@ function mergeResults(
|
||||
next: AdvancedLaboratoryResults,
|
||||
): AdvancedLaboratoryResults {
|
||||
return {
|
||||
m47Graph: next.m47Graph ?? current.m47Graph,
|
||||
m4Threat: next.m4Threat ?? current.m4Threat,
|
||||
l3: next.l3 ?? current.l3,
|
||||
l31: next.l31 ?? current.l31,
|
||||
@@ -109,12 +110,15 @@ export function useAdvancedLaboratoryCatalog({
|
||||
!isAdvancedLaboratoryWorkId(selectedWorkId)
|
||||
|| advancedLaboratoryResultAvailable(selectedWorkId, results)
|
||||
) return;
|
||||
const indexedResultId = index.find((item) => item.workId === selectedWorkId)?.resultId;
|
||||
if (selectedWorkId === "m47-reference-graph-shadow" && !indexedResultId) return;
|
||||
const controller = new AbortController();
|
||||
setLoadingWorkId(selectedWorkId);
|
||||
setFailedWorkId(null);
|
||||
setResultError(null);
|
||||
void fetchAdvancedLaboratoryResult(selectedWorkId, {
|
||||
signal: controller.signal,
|
||||
resultId: indexedResultId,
|
||||
}).then(async (next) => {
|
||||
if (controller.signal.aborted) return;
|
||||
setResults((current) => mergeResults(current, next));
|
||||
@@ -128,7 +132,7 @@ export function useAdvancedLaboratoryCatalog({
|
||||
if (!controller.signal.aborted) setLoadingWorkId(null);
|
||||
});
|
||||
return () => controller.abort();
|
||||
}, [results, selectedWorkId]);
|
||||
}, [index, results, selectedWorkId]);
|
||||
|
||||
return {
|
||||
index,
|
||||
|
||||
@@ -0,0 +1,214 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { after, before, test } from "node:test";
|
||||
|
||||
import { createServer } from "vite";
|
||||
|
||||
let server;
|
||||
let fetchM47ReferenceGraphLab;
|
||||
|
||||
const resultId = `m47-reference-graph-lab-${"a".repeat(64)}`;
|
||||
const graphResultId = `m47-reference-graph-${"b".repeat(64)}`;
|
||||
const visualResultId = `m4-threat-replay-${"c".repeat(64)}`;
|
||||
|
||||
before(async () => {
|
||||
server = await createServer({
|
||||
appType: "custom",
|
||||
logLevel: "silent",
|
||||
server: { middlewareMode: true },
|
||||
});
|
||||
({ fetchM47ReferenceGraphLab } = await server.ssrLoadModule(
|
||||
"/src/core/laboratory/m47ReferenceGraph.ts",
|
||||
));
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await server?.close();
|
||||
});
|
||||
|
||||
function m4Result() {
|
||||
return {
|
||||
schema_version: "missioncore.m4-threat-replay-view/v1",
|
||||
result_id: visualResultId,
|
||||
created_at_utc: "2026-08-05T15:36:01.553Z",
|
||||
status: "accepted",
|
||||
profile_id: "m4-ravnoves00-virtual-corridor/v3",
|
||||
rig_profile_id: "virtual-base-footprint-1000x600/v3",
|
||||
corridor_profile_id: "ravnoves00-forward-corridor-8m/v3",
|
||||
source_result_ids: {
|
||||
detector: `m4-detector-replay-${"d".repeat(64)}`,
|
||||
geometry: `m4-geometry-replay-${"e".repeat(64)}`,
|
||||
temporal: `m4-temporal-replay-${"f".repeat(64)}`,
|
||||
},
|
||||
metrics: {
|
||||
decisions: { threat: 7606, "not-threat": 10769, unknown: 128878 },
|
||||
evidence: {
|
||||
"camera-only": 10158,
|
||||
"current-metric": 28081,
|
||||
"rolling-map-retained": 70989,
|
||||
"stale-or-held": 38025,
|
||||
},
|
||||
fixtures: { critical: 5, critical_false_not_threat: 0, passed: 10, total: 10 },
|
||||
runtime: {
|
||||
frames_per_second: 175.0,
|
||||
provider_latency_p50_ms: 2.5,
|
||||
provider_latency_p95_ms: 7.2,
|
||||
provider_latency_max_ms: 26.6,
|
||||
},
|
||||
body_frame: {
|
||||
available: 3928,
|
||||
qualified: 3861,
|
||||
rejected: 67,
|
||||
camera_forward_alignment_deg: { p95: 8.439, maximum: 24.252 },
|
||||
},
|
||||
reason_counts: { "geometry-only-evidence": 87550 },
|
||||
},
|
||||
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,
|
||||
};
|
||||
}
|
||||
|
||||
function evidenceReport() {
|
||||
const mismatch = {
|
||||
source_binding: 0,
|
||||
current: 0,
|
||||
rolling_retained: 0,
|
||||
held: 0,
|
||||
expired: 0,
|
||||
camera_uncertainty: 0,
|
||||
threat_assessments: 0,
|
||||
};
|
||||
const raw = {
|
||||
schema_version: "missioncore.reference-perception-graph-lab-report/v1",
|
||||
result_id: resultId,
|
||||
source: { graph_result_id: graphResultId },
|
||||
method: { graph_id: "reference-perception-graph/v2" },
|
||||
execution: {
|
||||
worker_id: "worker-006",
|
||||
worker_node: "DESKTOP-OPJ8J04",
|
||||
artifact_sha256: "1".repeat(64),
|
||||
code_revision: "2".repeat(40),
|
||||
elapsed_seconds: 198.126,
|
||||
},
|
||||
metrics: {
|
||||
frames: { expected: 4489, admitted: 4489, delivered: 4489 },
|
||||
parity_mismatch_counts: mismatch,
|
||||
queue_high_watermarks: {
|
||||
detector: 2,
|
||||
geometry: 2,
|
||||
temporal: 2,
|
||||
rolling: 2,
|
||||
threat: 2,
|
||||
},
|
||||
},
|
||||
acceptance: { accepted: true },
|
||||
authority: {
|
||||
commands_enabled: false,
|
||||
actuation_allowed: false,
|
||||
navigation_or_safety_accepted: false,
|
||||
},
|
||||
visual_evidence: {
|
||||
linked_result_id: visualResultId,
|
||||
shared_recorded_clock: true,
|
||||
video_camera_3d_plan_available: true,
|
||||
},
|
||||
limitations: ["recorded replay only"],
|
||||
};
|
||||
return {
|
||||
schema_version: "missioncore.laboratory-evidence-report/v1",
|
||||
work_id: "m47-reference-graph-shadow",
|
||||
result_id: resultId,
|
||||
created_at_utc: "2026-08-23T18:00:16.061Z",
|
||||
access: "read-only",
|
||||
proof: {
|
||||
document_schema_version: "missioncore.reference-perception-graph-lab/v1",
|
||||
document_sha256: "3".repeat(64),
|
||||
identity_sha256: "a".repeat(64),
|
||||
report_schema_version: raw.schema_version,
|
||||
report_sha256: "4".repeat(64),
|
||||
artifact_count: 6,
|
||||
verified_artifact_count: 6,
|
||||
},
|
||||
completeness: { identity: "recorded" },
|
||||
identity: { authority: raw.authority },
|
||||
source: raw.source,
|
||||
configuration: null,
|
||||
method: raw.method,
|
||||
execution: raw.execution,
|
||||
resources: null,
|
||||
metrics: raw.metrics,
|
||||
gates: raw.acceptance,
|
||||
decision: null,
|
||||
limitations: raw.limitations,
|
||||
authority: raw.authority,
|
||||
artifacts: [],
|
||||
visual_evidence: {},
|
||||
raw_report: raw,
|
||||
};
|
||||
}
|
||||
|
||||
test("M4.7 binds exact Worker graph proof to the synchronized M4.6 visual", async () => {
|
||||
const requests = [];
|
||||
const result = await fetchM47ReferenceGraphLab({
|
||||
resultId,
|
||||
fetcher: async (input) => {
|
||||
const path = String(input);
|
||||
requests.push(path);
|
||||
return new Response(JSON.stringify(
|
||||
path.includes("/evidence-reports/") ? evidenceReport() : m4Result(),
|
||||
), { status: 200 });
|
||||
},
|
||||
});
|
||||
|
||||
assert.equal(result.graphResultId, graphResultId);
|
||||
assert.equal(result.visual.resultId, visualResultId);
|
||||
assert.equal(result.worker.id, "worker-006");
|
||||
assert.equal(result.frames.delivered, 4489);
|
||||
assert.deepEqual(Object.values(result.parityMismatchCounts), Array(7).fill(0));
|
||||
assert.equal(Math.max(...Object.values(result.queueHighWatermarks)), 2);
|
||||
assert.deepEqual(requests, [
|
||||
`/api/v1/laboratory/evidence-reports/m47-reference-graph-shadow/${resultId}`,
|
||||
`/api/v1/laboratory/m4-threat/results/${visualResultId}`,
|
||||
]);
|
||||
});
|
||||
|
||||
test("M4.7 keeps exact visual binding during a rolling API deployment", async () => {
|
||||
const requests = [];
|
||||
const result = await fetchM47ReferenceGraphLab({
|
||||
resultId,
|
||||
fetcher: async (input) => {
|
||||
const path = String(input);
|
||||
requests.push(path);
|
||||
if (path.includes("/evidence-reports/")) {
|
||||
return new Response(JSON.stringify(evidenceReport()), { status: 200 });
|
||||
}
|
||||
if (path.endsWith(`/${visualResultId}`)) {
|
||||
return new Response(null, { status: 404 });
|
||||
}
|
||||
return new Response(JSON.stringify({
|
||||
schema_version: "missioncore.m4-threat-replay-catalog/v1",
|
||||
items: [m4Result()],
|
||||
}), { status: 200 });
|
||||
},
|
||||
});
|
||||
|
||||
assert.equal(result.visual.resultId, visualResultId);
|
||||
assert.deepEqual(requests, [
|
||||
`/api/v1/laboratory/evidence-reports/m47-reference-graph-shadow/${resultId}`,
|
||||
`/api/v1/laboratory/m4-threat/results/${visualResultId}`,
|
||||
"/api/v1/laboratory/m4-threat/results?limit=10",
|
||||
]);
|
||||
});
|
||||
Reference in New Issue
Block a user