fix(lab): restore semantic overlay in M4.7
This commit is contained in:
@@ -360,27 +360,65 @@ function parseResult(value: unknown): E47SemanticSlamResult {
|
||||
}
|
||||
|
||||
export async function fetchE47SemanticSlamResult({
|
||||
resultId: requestedResultId,
|
||||
fetcher = fetch,
|
||||
signal,
|
||||
}: {
|
||||
resultId?: string;
|
||||
fetcher?: LaboratoryFetch;
|
||||
signal?: AbortSignal;
|
||||
} = {}): Promise<E47SemanticSlamResult | null> {
|
||||
const response = await fetcher("/api/v1/laboratory/e47-semantic-slam/results?limit=1", {
|
||||
headers: { Accept: "application/json" },
|
||||
signal,
|
||||
});
|
||||
if (requestedResultId !== undefined) resultId(requestedResultId);
|
||||
let response = await fetcher(
|
||||
requestedResultId === undefined
|
||||
? "/api/v1/laboratory/e47-semantic-slam/results?limit=1"
|
||||
: `/api/v1/laboratory/e47-semantic-slam/results/${requestedResultId}`,
|
||||
{ headers: { Accept: "application/json" }, signal },
|
||||
);
|
||||
let catalogFallback = false;
|
||||
if (requestedResultId !== undefined && response.status === 404) {
|
||||
response = await fetcher("/api/v1/laboratory/e47-semantic-slam/results?limit=10", {
|
||||
headers: { Accept: "application/json" },
|
||||
signal,
|
||||
});
|
||||
catalogFallback = true;
|
||||
}
|
||||
if (!response.ok) {
|
||||
throw new E47SemanticSlamContractError(`E47 LAB недоступен: HTTP ${response.status}.`);
|
||||
}
|
||||
const payload = object(await response.json(), "E47 catalog");
|
||||
exact(
|
||||
payload.schema_version,
|
||||
"missioncore.e47-semantic-slam-catalog/v1",
|
||||
"E47 catalog schema",
|
||||
);
|
||||
const items = array(payload.items, "E47 catalog items");
|
||||
return items.length ? parseResult(items[0]) : null;
|
||||
const payload = await response.json();
|
||||
if (requestedResultId === undefined || catalogFallback) {
|
||||
const catalog = object(payload, "E47 catalog");
|
||||
exact(
|
||||
catalog.schema_version,
|
||||
"missioncore.e47-semantic-slam-catalog/v1",
|
||||
"E47 catalog schema",
|
||||
);
|
||||
const items = array(catalog.items, "E47 catalog items");
|
||||
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 E47SemanticSlamContractError(
|
||||
"E47 requested result: точный semantic-result отсутствует в каталоге.",
|
||||
);
|
||||
}
|
||||
const parsed = parseResult(selected);
|
||||
if (requestedResultId !== undefined && parsed.resultId !== requestedResultId) {
|
||||
throw new E47SemanticSlamContractError("E47 requested result: нарушена идентичность.");
|
||||
}
|
||||
return parsed;
|
||||
}
|
||||
const parsed = parseResult(payload);
|
||||
if (parsed.resultId !== requestedResultId) {
|
||||
throw new E47SemanticSlamContractError("E47 requested result: нарушена идентичность.");
|
||||
}
|
||||
return parsed;
|
||||
}
|
||||
|
||||
function parseFrame(
|
||||
|
||||
@@ -6,6 +6,10 @@ import {
|
||||
fetchM4ThreatReplayResult,
|
||||
type M4ThreatReplayResult,
|
||||
} from "./m4ReplayThreat";
|
||||
import {
|
||||
fetchE47SemanticSlamResult,
|
||||
type E47SemanticSlamResult,
|
||||
} from "./e47SemanticSlam";
|
||||
|
||||
export interface M47ReferenceGraphLabResult {
|
||||
resultId: string;
|
||||
@@ -41,6 +45,7 @@ export interface M47ReferenceGraphLabResult {
|
||||
>>;
|
||||
limitations: readonly string[];
|
||||
visual: M4ThreatReplayResult;
|
||||
semantic: E47SemanticSlamResult;
|
||||
}
|
||||
|
||||
type LaboratoryFetch = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
|
||||
@@ -154,7 +159,7 @@ export async function fetchM47ReferenceGraphLab({
|
||||
const report = evidence.rawReport;
|
||||
exact(
|
||||
report.schema_version,
|
||||
"missioncore.reference-perception-graph-lab-report/v1",
|
||||
"missioncore.reference-perception-graph-lab-report/v2",
|
||||
"M4.7 report schema",
|
||||
);
|
||||
exact(report.result_id, resultId, "M4.7 report result");
|
||||
@@ -176,6 +181,16 @@ export async function fetchM47ReferenceGraphLab({
|
||||
true,
|
||||
"M4.7 visual evidence",
|
||||
);
|
||||
exact(
|
||||
visualEvidence.camera_semantic_overlay_available,
|
||||
true,
|
||||
"M4.7 camera semantic overlay",
|
||||
);
|
||||
exact(
|
||||
visualEvidence.semantic_binding,
|
||||
"exact-sequence-and-session-time",
|
||||
"M4.7 semantic binding",
|
||||
);
|
||||
const linkedVisualResultId = text(
|
||||
visualEvidence.linked_result_id,
|
||||
"M4.7 linked visual result",
|
||||
@@ -193,6 +208,31 @@ export async function fetchM47ReferenceGraphLab({
|
||||
"M4.7 visual binding: сервер вернул другой replay result.",
|
||||
);
|
||||
}
|
||||
const semanticResultId = text(
|
||||
visualEvidence.semantic_result_id,
|
||||
"M4.7 linked semantic result",
|
||||
);
|
||||
if (!/^e47-semantic-slam-[a-f0-9]{64}$/.test(semanticResultId)) {
|
||||
throw new M47ReferenceGraphContractError(
|
||||
"M4.7 semantic binding: нарушена идентичность.",
|
||||
);
|
||||
}
|
||||
const semantic = await fetchE47SemanticSlamResult({
|
||||
resultId: semanticResultId,
|
||||
fetcher,
|
||||
signal,
|
||||
});
|
||||
if (
|
||||
!semantic
|
||||
|| semantic.resultId !== semanticResultId
|
||||
|| semantic.baseM4ResultId !== linkedVisualResultId
|
||||
|| semantic.metrics.frames.total !== 4489
|
||||
|| semantic.metrics.frames.maskAvailable !== 4489
|
||||
) {
|
||||
throw new M47ReferenceGraphContractError(
|
||||
"M4.7 semantic binding: сервер вернул несвязанный semantic-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: нарушена идентичность.");
|
||||
@@ -219,5 +259,6 @@ export async function fetchM47ReferenceGraphLab({
|
||||
queueHighWatermarks: queueWatermarks(metrics.queue_high_watermarks),
|
||||
limitations: stringArray(report.limitations, "M4.7 limitations"),
|
||||
visual,
|
||||
semantic,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ export function M47ReferenceGraphResultView({
|
||||
},
|
||||
{
|
||||
label: "Визуал",
|
||||
value: "VIDEO/CAMERA/3D/PLAN · единый recorded clock · exact M4.6 ledger binding",
|
||||
value: "VIDEO/CAMERA/3D/PLAN · единый recorded clock · exact M4.6 + E47 semantic binding",
|
||||
},
|
||||
]}
|
||||
brief={{
|
||||
@@ -72,6 +72,13 @@ export function M47ReferenceGraphResultView({
|
||||
role: "synchronized VIDEO/CAMERA/3D/PLAN evidence",
|
||||
identitySha256: result.linkedVisualResultId.split("-").at(-1) ?? null,
|
||||
},
|
||||
{
|
||||
kind: "source",
|
||||
name: result.semantic.resultId,
|
||||
version: "4489 exact camera masks",
|
||||
role: "synchronized diagnostic semantic overlay",
|
||||
identitySha256: result.semantic.resultId.split("-").at(-1) ?? null,
|
||||
},
|
||||
{
|
||||
kind: "algorithm",
|
||||
name: "canonical reference perception graph",
|
||||
@@ -90,7 +97,13 @@ export function M47ReferenceGraphResultView({
|
||||
kind="diagnostic-model"
|
||||
resizable
|
||||
>
|
||||
<M4ReplayThreatVisual resultId={result.visual.resultId} />
|
||||
<M4ReplayThreatVisual
|
||||
resultId={result.visual.resultId}
|
||||
semantic={{
|
||||
resultId: result.semantic.resultId,
|
||||
taxonomy: result.semantic.taxonomy,
|
||||
}}
|
||||
/>
|
||||
</LaboratoryEvidence>
|
||||
)}
|
||||
result={(
|
||||
|
||||
@@ -127,6 +127,21 @@ test("E47 accepts only a fully accounted diagnostic semantic/SLAM view", async (
|
||||
);
|
||||
});
|
||||
|
||||
test("E47 fetches one exact content-addressed semantic result", async () => {
|
||||
const requests = [];
|
||||
const result = await fetchE47SemanticSlamResult({
|
||||
resultId,
|
||||
fetcher: async (input) => {
|
||||
requests.push(String(input));
|
||||
return new Response(JSON.stringify(resultView()));
|
||||
},
|
||||
});
|
||||
assert.equal(result.resultId, resultId);
|
||||
assert.deepEqual(requests, [
|
||||
`/api/v1/laboratory/e47-semantic-slam/results/${resultId}`,
|
||||
]);
|
||||
});
|
||||
|
||||
test("E47 rejects result-level point accounting drift", async () => {
|
||||
await assert.rejects(
|
||||
fetchE47SemanticSlamResult({
|
||||
|
||||
@@ -9,6 +9,7 @@ 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)}`;
|
||||
const semanticResultId = `e47-semantic-slam-${"d".repeat(64)}`;
|
||||
|
||||
before(async () => {
|
||||
server = await createServer({
|
||||
@@ -81,6 +82,62 @@ function m4Result() {
|
||||
};
|
||||
}
|
||||
|
||||
function semanticResult() {
|
||||
return {
|
||||
schema_version: "missioncore.e47-semantic-slam-view/v1",
|
||||
result_id: semanticResultId,
|
||||
created_at_utc: "2026-08-06T08:13:48.601Z",
|
||||
status: "diagnostic-semantic-slam-shadow",
|
||||
profile_id: "ravnoves00-eomt-kb4-slam-shadow/v1",
|
||||
base_m4_result_id: visualResultId,
|
||||
semantic_result_id: `result-${"e".repeat(64)}`,
|
||||
geometry_result_id: `m4-geometry-replay-${"f".repeat(64)}`,
|
||||
source_pack_id: `e10-lidar-pack-${"1".repeat(64)}`,
|
||||
calibration_content_sha256: "2".repeat(64),
|
||||
provider: {
|
||||
provider_id: "eomt-cityscapes-semantic-control/v1",
|
||||
model_id: "cityscapes-semantic-eomt",
|
||||
model_revision: "3".repeat(40),
|
||||
model_weights_sha256: "4".repeat(64),
|
||||
preprocess_id: "raw-kb4-valid-fov-semantic/v1",
|
||||
},
|
||||
temporal_binding: {
|
||||
semantic_to_camera: "exact-sequence-and-session-time",
|
||||
camera_to_lidar: "accepted-e6-nearest-host-arrival-best-effort",
|
||||
clock_basis: "recorded-host-monotonic-arrival",
|
||||
maximum_lidar_camera_delta_ms: 100,
|
||||
maximum_pose_point_delta_ms: 100,
|
||||
physical_synchronization_proven: false,
|
||||
},
|
||||
taxonomy: [{
|
||||
class_id: 1,
|
||||
label: "road",
|
||||
disposition: "labeled",
|
||||
color_rgb: [128, 64, 128],
|
||||
}],
|
||||
metrics: {
|
||||
frames: { total: 4489, mask_available: 4489, source_available: 3928 },
|
||||
points: { total: 1, projected: 1, labeled: 1, ambiguous: 0, unprojected: 0, absent: 0 },
|
||||
observations: { total: 1, labeled: 1, ambiguous: 0, unprojected: 0, absent: 0 },
|
||||
runtime: { elapsed_ms: 1000, frames_per_second: 4.489 },
|
||||
},
|
||||
acceptance: {
|
||||
artifact_contract_passed: true,
|
||||
frame_accounting_passed: true,
|
||||
point_accounting_passed: true,
|
||||
observation_binding_passed: true,
|
||||
temporal_binding_passed: true,
|
||||
independent_semantic_truth_passed: false,
|
||||
provider_promoted: false,
|
||||
},
|
||||
limitations: ["diagnostic only"],
|
||||
ground_truth: false,
|
||||
semantic_authority: "diagnostic-only",
|
||||
navigation_or_safety_accepted: false,
|
||||
actuation_allowed: false,
|
||||
};
|
||||
}
|
||||
|
||||
function evidenceReport() {
|
||||
const mismatch = {
|
||||
source_binding: 0,
|
||||
@@ -92,7 +149,7 @@ function evidenceReport() {
|
||||
threat_assessments: 0,
|
||||
};
|
||||
const raw = {
|
||||
schema_version: "missioncore.reference-perception-graph-lab-report/v1",
|
||||
schema_version: "missioncore.reference-perception-graph-lab-report/v2",
|
||||
result_id: resultId,
|
||||
source: { graph_result_id: graphResultId },
|
||||
method: { graph_id: "reference-perception-graph/v2" },
|
||||
@@ -122,8 +179,11 @@ function evidenceReport() {
|
||||
},
|
||||
visual_evidence: {
|
||||
linked_result_id: visualResultId,
|
||||
semantic_result_id: semanticResultId,
|
||||
shared_recorded_clock: true,
|
||||
video_camera_3d_plan_available: true,
|
||||
camera_semantic_overlay_available: true,
|
||||
semantic_binding: "exact-sequence-and-session-time",
|
||||
},
|
||||
limitations: ["recorded replay only"],
|
||||
};
|
||||
@@ -134,13 +194,13 @@ function evidenceReport() {
|
||||
created_at_utc: "2026-08-23T18:00:16.061Z",
|
||||
access: "read-only",
|
||||
proof: {
|
||||
document_schema_version: "missioncore.reference-perception-graph-lab/v1",
|
||||
document_schema_version: "missioncore.reference-perception-graph-lab/v2",
|
||||
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,
|
||||
artifact_count: 9,
|
||||
verified_artifact_count: 9,
|
||||
},
|
||||
completeness: { identity: "recorded" },
|
||||
identity: { authority: raw.authority },
|
||||
@@ -167,14 +227,16 @@ test("M4.7 binds exact Worker graph proof to the synchronized M4.6 visual", asyn
|
||||
fetcher: async (input) => {
|
||||
const path = String(input);
|
||||
requests.push(path);
|
||||
return new Response(JSON.stringify(
|
||||
path.includes("/evidence-reports/") ? evidenceReport() : m4Result(),
|
||||
), { status: 200 });
|
||||
const payload = path.includes("/evidence-reports/")
|
||||
? evidenceReport()
|
||||
: path.includes("/e47-semantic-slam/") ? semanticResult() : m4Result();
|
||||
return new Response(JSON.stringify(payload), { status: 200 });
|
||||
},
|
||||
});
|
||||
|
||||
assert.equal(result.graphResultId, graphResultId);
|
||||
assert.equal(result.visual.resultId, visualResultId);
|
||||
assert.equal(result.semantic.resultId, semanticResultId);
|
||||
assert.equal(result.worker.id, "worker-006");
|
||||
assert.equal(result.frames.delivered, 4489);
|
||||
assert.deepEqual(Object.values(result.parityMismatchCounts), Array(7).fill(0));
|
||||
@@ -182,6 +244,7 @@ test("M4.7 binds exact Worker graph proof to the synchronized M4.6 visual", asyn
|
||||
assert.deepEqual(requests, [
|
||||
`/api/v1/laboratory/evidence-reports/m47-reference-graph-shadow/${resultId}`,
|
||||
`/api/v1/laboratory/m4-threat/results/${visualResultId}`,
|
||||
`/api/v1/laboratory/e47-semantic-slam/results/${semanticResultId}`,
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -198,6 +261,9 @@ test("M4.7 keeps exact visual binding during a rolling API deployment", async ()
|
||||
if (path.endsWith(`/${visualResultId}`)) {
|
||||
return new Response(null, { status: 404 });
|
||||
}
|
||||
if (path.includes("/e47-semantic-slam/")) {
|
||||
return new Response(JSON.stringify(semanticResult()), { status: 200 });
|
||||
}
|
||||
return new Response(JSON.stringify({
|
||||
schema_version: "missioncore.m4-threat-replay-catalog/v1",
|
||||
items: [m4Result()],
|
||||
@@ -210,5 +276,6 @@ test("M4.7 keeps exact visual binding during a rolling API deployment", async ()
|
||||
`/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",
|
||||
`/api/v1/laboratory/e47-semantic-slam/results/${semanticResultId}`,
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -5,6 +5,6 @@
|
||||
"runtime_relative_root": "m47/reference-graph-labs",
|
||||
"result_id_prefix": "m47-reference-graph-lab",
|
||||
"document_name": "manifest.json",
|
||||
"schema_version": "missioncore.reference-perception-graph-lab/v1"
|
||||
"schema_version": "missioncore.reference-perception-graph-lab/v2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,11 +14,13 @@ def main() -> int:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--graph-result-root", type=Path, required=True)
|
||||
parser.add_argument("--visual-result-root", type=Path, required=True)
|
||||
parser.add_argument("--semantic-result-root", type=Path, required=True)
|
||||
parser.add_argument("--output-root", type=Path, required=True)
|
||||
args = parser.parse_args()
|
||||
result = publish_m47_reference_graph_lab(
|
||||
graph_result_root=args.graph_result_root,
|
||||
visual_result_root=args.visual_result_root,
|
||||
semantic_result_root=args.semantic_result_root,
|
||||
output_root=args.output_root,
|
||||
)
|
||||
print(
|
||||
|
||||
@@ -12,11 +12,17 @@ from pathlib import Path
|
||||
from typing import Final
|
||||
|
||||
from k1link.perception.reference_graph_result import read_reference_graph_result
|
||||
from k1link.perception.semantic_slam_replay import (
|
||||
SEMANTIC_SLAM_MANIFEST_NAME,
|
||||
SEMANTIC_SLAM_REPORT_NAME,
|
||||
SEMANTIC_SLAM_TAXONOMY_NAME,
|
||||
read_semantic_slam_replay_result,
|
||||
)
|
||||
from k1link.perception.threat_replay import read_threat_replay_result
|
||||
|
||||
M47_REFERENCE_GRAPH_LAB_SCHEMA: Final = "missioncore.reference-perception-graph-lab/v1"
|
||||
M47_REFERENCE_GRAPH_LAB_SCHEMA: Final = "missioncore.reference-perception-graph-lab/v2"
|
||||
M47_REFERENCE_GRAPH_LAB_REPORT_SCHEMA: Final = (
|
||||
"missioncore.reference-perception-graph-lab-report/v1"
|
||||
"missioncore.reference-perception-graph-lab-report/v2"
|
||||
)
|
||||
M47_REFERENCE_GRAPH_LAB_PREFIX: Final = "m47-reference-graph-lab-"
|
||||
|
||||
@@ -37,10 +43,12 @@ def publish_m47_reference_graph_lab(
|
||||
*,
|
||||
graph_result_root: Path,
|
||||
visual_result_root: Path,
|
||||
semantic_result_root: Path,
|
||||
output_root: Path,
|
||||
) -> M47ReferenceGraphLab:
|
||||
graph = read_reference_graph_result(graph_result_root)
|
||||
visual = read_threat_replay_result(visual_result_root)
|
||||
semantic = read_semantic_slam_replay_result(semantic_result_root)
|
||||
if not graph.accepted or not visual.accepted:
|
||||
raise M47ReferenceGraphLabError("both graph and visual replay must be accepted")
|
||||
graph_report = graph.report
|
||||
@@ -49,6 +57,9 @@ def publish_m47_reference_graph_lab(
|
||||
parity = _object(graph_report.get("accepted_parity"), "graph parity")
|
||||
mismatches = _object(parity.get("mismatch_counts"), "graph parity mismatches")
|
||||
visual_identity = _object(visual.manifest.get("identity"), "visual identity")
|
||||
semantic_identity = _object(semantic.manifest.get("identity"), "semantic identity")
|
||||
semantic_frames = _object(semantic_identity.get("counts"), "semantic counts")
|
||||
semantic_frame_counts = _object(semantic_frames.get("frames"), "semantic frame counts")
|
||||
if (
|
||||
parity.get("accepted") is not True
|
||||
or parity.get("expected_frames") != 4489
|
||||
@@ -68,6 +79,13 @@ def publish_m47_reference_graph_lab(
|
||||
or parity.get("temporal_frames_sha256") != visual_identity.get("temporal_frames_sha256")
|
||||
):
|
||||
raise M47ReferenceGraphLabError("graph-to-visual parity proof changed")
|
||||
if (
|
||||
semantic_identity.get("base_m4_result_id") != visual.result_id
|
||||
or semantic_identity.get("source_session_id") != visual_identity.get("source_session_id")
|
||||
or semantic_frame_counts.get("total") != 4489
|
||||
or semantic_frame_counts.get("mask_available") != 4489
|
||||
):
|
||||
raise M47ReferenceGraphLabError("semantic-to-visual binding proof changed")
|
||||
terminal = _object(graph_report.get("terminal_outcomes"), "terminal outcomes")
|
||||
queues = _object(graph_report.get("queue_high_watermarks"), "queue high watermarks")
|
||||
execution = _object(graph_report.get("execution"), "graph execution")
|
||||
@@ -81,23 +99,30 @@ def publish_m47_reference_graph_lab(
|
||||
}
|
||||
visual_evidence = {
|
||||
"linked_result_id": visual.result_id,
|
||||
"semantic_result_id": semantic.result_id,
|
||||
"binding": "exact-threat-and-temporal-ledger-parity",
|
||||
"semantic_binding": "exact-sequence-and-session-time",
|
||||
"timeline_frames": 4489,
|
||||
"shared_recorded_clock": True,
|
||||
"video_camera_3d_plan_available": True,
|
||||
"camera_semantic_overlay_available": True,
|
||||
"regression_sequences": [138, 274, 1880, 2584],
|
||||
"independent_ground_truth": False,
|
||||
}
|
||||
identity: dict[str, object] = {
|
||||
"schema_version": M47_REFERENCE_GRAPH_LAB_SCHEMA,
|
||||
"binding_id": "m47-reference-graph-visual-binding/v1",
|
||||
"binding_id": "m47-reference-graph-visual-binding/v2",
|
||||
"source": {
|
||||
"source_id": "RAVNOVES00",
|
||||
"source_session_id": visual_identity.get("source_session_id"),
|
||||
"graph_result_id": graph.result_id,
|
||||
"visual_result_id": visual.result_id,
|
||||
"semantic_result_id": semantic.result_id,
|
||||
"temporal_frames_sha256": parity.get("temporal_frames_sha256"),
|
||||
"threat_frames_sha256": parity.get("threat_frames_sha256"),
|
||||
"semantic_frames_sha256": semantic_identity.get("semantic_frames_sha256"),
|
||||
"semantic_masks_sha256": semantic_identity.get("semantic_masks_sha256"),
|
||||
"semantic_taxonomy_sha256": semantic_identity.get("taxonomy_sha256"),
|
||||
},
|
||||
"method": {
|
||||
"graph_id": graph_manifest.get("graph_id"),
|
||||
@@ -179,6 +204,9 @@ def publish_m47_reference_graph_lab(
|
||||
"graph-runtime.json": graph.result_root / "runtime.json",
|
||||
"visual-manifest.json": visual.result_root / "manifest.json",
|
||||
"visual-report.json": visual.result_root / "report.json",
|
||||
"semantic-manifest.json": semantic.result_root / SEMANTIC_SLAM_MANIFEST_NAME,
|
||||
"semantic-report.json": semantic.result_root / SEMANTIC_SLAM_REPORT_NAME,
|
||||
"semantic-taxonomy.json": semantic.result_root / SEMANTIC_SLAM_TAXONOMY_NAME,
|
||||
}
|
||||
for name, source in sources.items():
|
||||
shutil.copyfile(source, staging / name)
|
||||
@@ -190,6 +218,9 @@ def publish_m47_reference_graph_lab(
|
||||
"graph-runtime.json": "m47-runtime",
|
||||
"visual-manifest.json": "linked-visual-manifest",
|
||||
"visual-report.json": "linked-visual-report",
|
||||
"semantic-manifest.json": "linked-semantic-manifest",
|
||||
"semantic-report.json": "linked-semantic-report",
|
||||
"semantic-taxonomy.json": "linked-semantic-taxonomy",
|
||||
}
|
||||
schemas = {
|
||||
"graph-manifest.json": graph_manifest.get("schema_version"),
|
||||
@@ -197,6 +228,11 @@ def publish_m47_reference_graph_lab(
|
||||
"graph-runtime.json": graph_runtime.get("schema_version"),
|
||||
"visual-manifest.json": visual.manifest.get("schema_version"),
|
||||
"visual-report.json": visual.report.get("schema_version"),
|
||||
"semantic-manifest.json": semantic.manifest.get("schema_version"),
|
||||
"semantic-report.json": semantic.report.get("schema_version"),
|
||||
"semantic-taxonomy.json": _read_json(
|
||||
semantic.result_root / SEMANTIC_SLAM_TAXONOMY_NAME
|
||||
).get("schema_version"),
|
||||
"report.json": M47_REFERENCE_GRAPH_LAB_REPORT_SCHEMA,
|
||||
}
|
||||
artifacts = [_artifact(staging / name, role, schemas[name]) for name, role in roles.items()]
|
||||
@@ -247,7 +283,7 @@ def read_m47_reference_graph_lab(result_root: Path) -> M47ReferenceGraphLab:
|
||||
):
|
||||
raise M47ReferenceGraphLabError("M4.7 LAB identity changed")
|
||||
artifacts = manifest.get("artifacts")
|
||||
if not isinstance(artifacts, list) or len(artifacts) != 6:
|
||||
if not isinstance(artifacts, list) or len(artifacts) != 9:
|
||||
raise M47ReferenceGraphLabError("M4.7 LAB artifact inventory changed")
|
||||
for value in artifacts:
|
||||
descriptor = _object(value, "LAB artifact")
|
||||
|
||||
@@ -137,6 +137,10 @@ def build_e47_semantic_slam_router(
|
||||
"access": "read-only-diagnostic-shadow",
|
||||
}
|
||||
|
||||
@router.get("/results/{result_id}")
|
||||
def get_result(result_id: str) -> dict[str, object]:
|
||||
return _project_result(result(result_id))
|
||||
|
||||
@router.get("/results/{result_id}/timeline/chunk")
|
||||
def get_timeline_chunk(
|
||||
result_id: str,
|
||||
|
||||
@@ -173,9 +173,7 @@ def test_catalog_projects_exact_diagnostic_only_view(
|
||||
assert item["status"] == "diagnostic-semantic-slam-shadow"
|
||||
assert item["base_m4_result_id"] == M4_RESULT_ID
|
||||
assert item["provider"]["provider_id"] == "eomt-cityscapes-semantic-control/v1"
|
||||
assert item["temporal_binding"]["semantic_to_camera"] == (
|
||||
"exact-sequence-and-session-time"
|
||||
)
|
||||
assert item["temporal_binding"]["semantic_to_camera"] == ("exact-sequence-and-session-time")
|
||||
assert item["temporal_binding"]["physical_synchronization_proven"] is False
|
||||
assert [entry["label"] for entry in item["taxonomy"]] == ["ambiguous", "road"]
|
||||
assert item["acceptance"] == {
|
||||
@@ -191,6 +189,13 @@ def test_catalog_projects_exact_diagnostic_only_view(
|
||||
assert item["navigation_or_safety_accepted"] is False
|
||||
assert item["actuation_allowed"] is False
|
||||
|
||||
get_result = _endpoint(
|
||||
"/api/v1/laboratory/e47-semantic-slam/results/{result_id}",
|
||||
root,
|
||||
)
|
||||
exact = get_result(RESULT_ID)
|
||||
assert exact == item
|
||||
|
||||
|
||||
def test_timeline_chunk_preserves_point_index_space_and_unavailable_sentinel(
|
||||
publication: tuple[Path, Path],
|
||||
|
||||
@@ -25,8 +25,10 @@ def test_m47_lab_binds_worker_graph_to_exact_visual_replay(
|
||||
) -> None:
|
||||
graph_root = tmp_path / "graph"
|
||||
visual_root = tmp_path / "visual"
|
||||
semantic_root = tmp_path / "semantic"
|
||||
graph_root.mkdir()
|
||||
visual_root.mkdir()
|
||||
semantic_root.mkdir()
|
||||
runtime = {
|
||||
"schema_version": "missioncore.reference-graph-runtime-identity/v3",
|
||||
"worker_id": "worker-006",
|
||||
@@ -99,6 +101,20 @@ def test_m47_lab_binds_worker_graph_to_exact_visual_replay(
|
||||
},
|
||||
}
|
||||
visual_report = {"schema_version": "missioncore.perception-threat-replay-report/v2"}
|
||||
semantic_identity = {
|
||||
"base_m4_result_id": "m4-threat-replay-" + "6" * 64,
|
||||
"source_session_id": "20260720T065719Z_viewer_live",
|
||||
"semantic_frames_sha256": "7" * 64,
|
||||
"semantic_masks_sha256": "8" * 64,
|
||||
"taxonomy_sha256": "9" * 64,
|
||||
"counts": {"frames": {"total": 4489, "mask_available": 4489}},
|
||||
}
|
||||
semantic_manifest = {
|
||||
"schema_version": "missioncore.e47-semantic-slam-result/v1",
|
||||
"identity": semantic_identity,
|
||||
}
|
||||
semantic_report = {"schema_version": "missioncore.e47-semantic-slam-report/v1"}
|
||||
semantic_taxonomy = {"schema_version": "missioncore.e47-semantic-taxonomy/v1"}
|
||||
for root, documents in (
|
||||
(
|
||||
graph_root,
|
||||
@@ -112,6 +128,14 @@ def test_m47_lab_binds_worker_graph_to_exact_visual_replay(
|
||||
visual_root,
|
||||
{"manifest.json": visual_manifest, "report.json": visual_report},
|
||||
),
|
||||
(
|
||||
semantic_root,
|
||||
{
|
||||
"manifest.json": semantic_manifest,
|
||||
"report.json": semantic_report,
|
||||
"taxonomy.json": semantic_taxonomy,
|
||||
},
|
||||
),
|
||||
):
|
||||
for name, document in documents.items():
|
||||
_write_json(root / name, document)
|
||||
@@ -129,6 +153,12 @@ def test_m47_lab_binds_worker_graph_to_exact_visual_replay(
|
||||
manifest=visual_manifest,
|
||||
report=visual_report,
|
||||
)
|
||||
semantic = SimpleNamespace(
|
||||
result_id="e47-semantic-slam-" + "a" * 64,
|
||||
result_root=semantic_root,
|
||||
manifest=semantic_manifest,
|
||||
report=semantic_report,
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
"k1link.laboratory.m47_reference_graph.read_reference_graph_result",
|
||||
lambda _: graph,
|
||||
@@ -137,16 +167,22 @@ def test_m47_lab_binds_worker_graph_to_exact_visual_replay(
|
||||
"k1link.laboratory.m47_reference_graph.read_threat_replay_result",
|
||||
lambda _: visual,
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
"k1link.laboratory.m47_reference_graph.read_semantic_slam_replay_result",
|
||||
lambda _: semantic,
|
||||
)
|
||||
|
||||
runtime_root = tmp_path / "runtime"
|
||||
result = publish_m47_reference_graph_lab(
|
||||
graph_result_root=graph_root,
|
||||
visual_result_root=visual_root,
|
||||
semantic_result_root=semantic_root,
|
||||
output_root=runtime_root / "m47" / "reference-graph-labs",
|
||||
)
|
||||
|
||||
assert read_m47_reference_graph_lab(result.result_root) == result
|
||||
assert result.report["visual_evidence"]["linked_result_id"] == visual.result_id
|
||||
assert result.report["visual_evidence"]["semantic_result_id"] == semantic.result_id
|
||||
assert result.report["execution"]["worker_id"] == "worker-006"
|
||||
assert result.report["metrics"]["parity_mismatch_counts"] == mismatch_counts
|
||||
repository_root = Path(__file__).resolve().parents[1]
|
||||
@@ -157,11 +193,11 @@ def test_m47_lab_binds_worker_graph_to_exact_visual_replay(
|
||||
item for item in registry.definitions if item.work_id == "m47-reference-graph-shadow"
|
||||
)
|
||||
proof = verify_laboratory_evidence_result(definition, result.result_root)
|
||||
assert proof["artifact_count"] == 6
|
||||
assert proof["artifact_count"] == 9
|
||||
projected = LaboratoryEvidenceReportService(registry, lambda: runtime_root).read(
|
||||
definition.work_id,
|
||||
result.result_id,
|
||||
)
|
||||
assert projected["raw_report"]["schema_version"] == (
|
||||
"missioncore.reference-perception-graph-lab-report/v1"
|
||||
"missioncore.reference-perception-graph-lab-report/v2"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user