feat(lab): publish M4.7 Worker graph evidence

This commit is contained in:
DCCONSTRUCTIONS
2026-08-23 22:00:46 +03:00
parent 64860be4ae
commit 34ed8a0f5f
20 changed files with 1363 additions and 16 deletions
@@ -0,0 +1,355 @@
"""Publish an immutable visual LAB binding for the accepted M4.7 graph shadow."""
from __future__ import annotations
import hashlib
import json
import os
import shutil
import uuid
from dataclasses import dataclass
from pathlib import Path
from typing import Final
from k1link.perception.reference_graph_result import read_reference_graph_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_REPORT_SCHEMA: Final = (
"missioncore.reference-perception-graph-lab-report/v1"
)
M47_REFERENCE_GRAPH_LAB_PREFIX: Final = "m47-reference-graph-lab-"
class M47ReferenceGraphLabError(RuntimeError):
"""The M4.7 graph and visual replay cannot be bound without exact proof."""
@dataclass(frozen=True, slots=True)
class M47ReferenceGraphLab:
result_id: str
result_root: Path
manifest: dict[str, object]
report: dict[str, object]
def publish_m47_reference_graph_lab(
*,
graph_result_root: Path,
visual_result_root: Path,
output_root: Path,
) -> M47ReferenceGraphLab:
graph = read_reference_graph_result(graph_result_root)
visual = read_threat_replay_result(visual_result_root)
if not graph.accepted or not visual.accepted:
raise M47ReferenceGraphLabError("both graph and visual replay must be accepted")
graph_report = graph.report
graph_manifest = graph.manifest
graph_runtime = _object(graph_manifest.get("runtime"), "graph runtime")
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")
if (
parity.get("accepted") is not True
or parity.get("expected_frames") != 4489
or parity.get("compared_frames") != 4489
or set(mismatches)
!= {
"source_binding",
"current",
"rolling_retained",
"held",
"expired",
"camera_uncertainty",
"threat_assessments",
}
or any(value != 0 for value in mismatches.values())
or parity.get("threat_frames_sha256") != visual_identity.get("frames_sha256")
or parity.get("temporal_frames_sha256") != visual_identity.get("temporal_frames_sha256")
):
raise M47ReferenceGraphLabError("graph-to-visual parity 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")
authority = {
"physical_live": False,
"commands_enabled": False,
"actuation_allowed": False,
"navigation_or_safety_accepted": False,
"ground_truth": False,
"mode": "replay-simulated",
}
visual_evidence = {
"linked_result_id": visual.result_id,
"binding": "exact-threat-and-temporal-ledger-parity",
"timeline_frames": 4489,
"shared_recorded_clock": True,
"video_camera_3d_plan_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",
"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,
"temporal_frames_sha256": parity.get("temporal_frames_sha256"),
"threat_frames_sha256": parity.get("threat_frames_sha256"),
},
"method": {
"graph_id": graph_manifest.get("graph_id"),
"run_mode": graph_manifest.get("run_mode"),
"source_profile_id": graph_manifest.get("source_profile_id"),
"canonical_payload_sha256": graph_manifest.get("canonical_payload_sha256"),
"parity_schema_version": parity.get("schema_version"),
},
"execution": graph_runtime,
"acceptance": {
"accepted": True,
"expected_frames": 4489,
"admitted_frames": graph_report.get("admitted_frames"),
"delivered_frames": terminal.get("delivered"),
"parity_mismatch_counts": mismatches,
},
"visual_evidence": visual_evidence,
"authority": authority,
}
identity_sha256 = _canonical_sha256(identity)
result_id = f"{M47_REFERENCE_GRAPH_LAB_PREFIX}{identity_sha256}"
elapsed_seconds = execution.get("elapsed_seconds")
report: dict[str, object] = {
"schema_version": M47_REFERENCE_GRAPH_LAB_REPORT_SCHEMA,
"result_id": result_id,
"source": identity["source"],
"method": identity["method"],
"execution": {
**graph_runtime,
"elapsed_seconds": elapsed_seconds,
},
"metrics": {
"frames": {
"expected": 4489,
"admitted": graph_report.get("admitted_frames"),
"delivered": terminal.get("delivered"),
"failed": terminal.get("failed", 0),
"stale": terminal.get("stale", 0),
"superseded": terminal.get("superseded", 0),
"rejected": terminal.get("rejected", 0),
"unavailable": terminal.get("unavailable", 0),
},
"queue_high_watermarks": queues,
"parity_mismatch_counts": mismatches,
"canonical_payload_sha256": graph_manifest.get("canonical_payload_sha256"),
},
"acceptance": {
"accepted": True,
"gates": graph_report.get("gates"),
"parity": parity,
},
"decision": {
"state": "accepted-reference-graph-replay",
"next_gate": "independent-object-centric-detection-quality",
"summary": (
"Canonical source→detector→geometry→temporal/motion→rolling→threat "
"graph preserves the accepted M4.5R/M4.6 payload for every frame."
),
},
"limitations": [
"This result proves recorded lossless replay parity, not physical live operation.",
"The linked M4.6 visual replay is engineering evidence, not independent object truth.",
"No navigation, safety, command or actuation authority is granted.",
"Independent object-centric detection quality remains the next acceptance gate.",
],
"authority": authority,
"visual_evidence": visual_evidence,
}
output = output_root.expanduser().resolve()
output.mkdir(mode=0o700, parents=True, exist_ok=True)
if output.is_symlink() or not output.is_dir():
raise M47ReferenceGraphLabError("LAB output root must be a real directory")
staging = output / f".m47-reference-graph-lab.{uuid.uuid4().hex}.tmp"
staging.mkdir(mode=0o700, exist_ok=False)
try:
sources = {
"graph-manifest.json": graph.result_root / "manifest.json",
"graph-report.json": graph.result_root / "report.json",
"graph-runtime.json": graph.result_root / "runtime.json",
"visual-manifest.json": visual.result_root / "manifest.json",
"visual-report.json": visual.result_root / "report.json",
}
for name, source in sources.items():
shutil.copyfile(source, staging / name)
_write_json(staging / "report.json", report)
roles = {
"report.json": "m47-lab-report",
"graph-manifest.json": "m47-graph-manifest",
"graph-report.json": "m47-graph-report",
"graph-runtime.json": "m47-runtime",
"visual-manifest.json": "linked-visual-manifest",
"visual-report.json": "linked-visual-report",
}
schemas = {
"graph-manifest.json": graph_manifest.get("schema_version"),
"graph-report.json": graph_report.get("schema_version"),
"graph-runtime.json": graph_runtime.get("schema_version"),
"visual-manifest.json": visual.manifest.get("schema_version"),
"visual-report.json": visual.report.get("schema_version"),
"report.json": M47_REFERENCE_GRAPH_LAB_REPORT_SCHEMA,
}
artifacts = [_artifact(staging / name, role, schemas[name]) for name, role in roles.items()]
manifest: dict[str, object] = {
"schema_version": M47_REFERENCE_GRAPH_LAB_SCHEMA,
"result_id": result_id,
"identity_sha256": identity_sha256,
"identity": identity,
"created_at_utc": graph_runtime.get("started_at_utc"),
"accepted": True,
"ground_truth": False,
"authority": authority,
"artifacts": artifacts,
}
_write_json(staging / "manifest.json", manifest)
target = output / result_id
_publish(staging, target)
except Exception:
shutil.rmtree(staging, ignore_errors=True)
raise
return read_m47_reference_graph_lab(target)
def read_m47_reference_graph_lab(result_root: Path) -> M47ReferenceGraphLab:
candidate = result_root.expanduser().absolute()
if candidate.is_symlink():
raise M47ReferenceGraphLabError("M4.7 LAB result root is invalid")
resolved = candidate.resolve(strict=True)
if (
resolved.is_symlink()
or not resolved.is_dir()
or not resolved.name.startswith(M47_REFERENCE_GRAPH_LAB_PREFIX)
):
raise M47ReferenceGraphLabError("M4.7 LAB result root is invalid")
manifest = _read_json(resolved / "manifest.json")
if (
manifest.get("schema_version") != M47_REFERENCE_GRAPH_LAB_SCHEMA
or manifest.get("result_id") != resolved.name
or manifest.get("accepted") is not True
or manifest.get("ground_truth") is not False
):
raise M47ReferenceGraphLabError("M4.7 LAB manifest changed")
identity = _object(manifest.get("identity"), "LAB identity")
identity_sha256 = _canonical_sha256(identity)
if (
manifest.get("identity_sha256") != identity_sha256
or resolved.name != f"{M47_REFERENCE_GRAPH_LAB_PREFIX}{identity_sha256}"
):
raise M47ReferenceGraphLabError("M4.7 LAB identity changed")
artifacts = manifest.get("artifacts")
if not isinstance(artifacts, list) or len(artifacts) != 6:
raise M47ReferenceGraphLabError("M4.7 LAB artifact inventory changed")
for value in artifacts:
descriptor = _object(value, "LAB artifact")
path_value = descriptor.get("path")
if not isinstance(path_value, str) or "/" in path_value or "\\" in path_value:
raise M47ReferenceGraphLabError("M4.7 LAB artifact path changed")
path = resolved / path_value
if (
path.is_symlink()
or not path.is_file()
or path.stat().st_size != descriptor.get("byte_length")
or _file_sha256(path) != descriptor.get("sha256")
):
raise M47ReferenceGraphLabError("M4.7 LAB artifact proof changed")
report = _read_json(resolved / "report.json")
if (
report.get("schema_version") != M47_REFERENCE_GRAPH_LAB_REPORT_SCHEMA
or report.get("result_id") != resolved.name
or _object(report.get("acceptance"), "LAB acceptance").get("accepted") is not True
or report.get("authority") != identity.get("authority")
):
raise M47ReferenceGraphLabError("M4.7 LAB report changed")
return M47ReferenceGraphLab(
result_id=resolved.name,
result_root=resolved,
manifest=manifest,
report=report,
)
def _artifact(path: Path, role: str, schema: object) -> dict[str, object]:
return {
"role": role,
"path": path.name,
"byte_length": path.stat().st_size,
"sha256": _file_sha256(path),
"schema_version": schema,
"media_type": "application/json",
}
def _publish(staging: Path, target: Path) -> None:
if target.exists():
existing = {path.name: _file_sha256(path) for path in target.iterdir() if path.is_file()}
proposed = {path.name: _file_sha256(path) for path in staging.iterdir() if path.is_file()}
if existing != proposed:
raise M47ReferenceGraphLabError("immutable M4.7 LAB identity collision")
shutil.rmtree(staging)
return
os.replace(staging, target)
def _object(value: object, label: str) -> dict[str, object]:
if not isinstance(value, dict) or any(not isinstance(key, str) for key in value):
raise M47ReferenceGraphLabError(f"{label} must be an object")
return value
def _write_json(path: Path, document: dict[str, object]) -> None:
with path.open("wb") as stream:
stream.write(_canonical_json(document) + b"\n")
stream.flush()
os.fsync(stream.fileno())
def _read_json(path: Path) -> dict[str, object]:
if path.is_symlink() or not path.is_file() or path.stat().st_size > 1024 * 1024:
raise M47ReferenceGraphLabError("M4.7 LAB JSON artifact is invalid")
try:
return _object(json.loads(path.read_text("utf-8")), "M4.7 LAB JSON artifact")
except (OSError, UnicodeDecodeError, json.JSONDecodeError) as error:
raise M47ReferenceGraphLabError("M4.7 LAB JSON artifact is unreadable") from error
def _canonical_json(value: object) -> bytes:
return json.dumps(
value,
ensure_ascii=False,
sort_keys=True,
separators=(",", ":"),
allow_nan=False,
).encode("utf-8")
def _canonical_sha256(value: object) -> str:
return hashlib.sha256(_canonical_json(value)).hexdigest()
def _file_sha256(path: Path) -> str:
digest = hashlib.sha256()
with path.open("rb") as stream:
for chunk in iter(lambda: stream.read(1024 * 1024), b""):
digest.update(chunk)
return digest.hexdigest()
__all__ = [
"M47_REFERENCE_GRAPH_LAB_PREFIX",
"M47_REFERENCE_GRAPH_LAB_REPORT_SCHEMA",
"M47_REFERENCE_GRAPH_LAB_SCHEMA",
"M47ReferenceGraphLab",
"M47ReferenceGraphLabError",
"publish_m47_reference_graph_lab",
"read_m47_reference_graph_lab",
]
@@ -153,6 +153,103 @@ def seal_reference_graph_result(
)
def read_reference_graph_result(result_root: Path) -> SealedReferenceGraphResult:
candidate = result_root.expanduser().absolute()
if candidate.is_symlink():
raise ReferenceGraphResultError("reference graph result root is invalid")
resolved = candidate.resolve(strict=True)
if (
resolved.is_symlink()
or not resolved.is_dir()
or not resolved.name.startswith(REFERENCE_GRAPH_RESULT_PREFIX)
):
raise ReferenceGraphResultError("reference graph result root is invalid")
manifest = _read_json(resolved / "manifest.json")
expected_manifest_keys = {
"schema_version",
"result_id",
"identity_sha256",
"graph_id",
"source_profile_id",
"run_mode",
"canonical_payload_sha256",
"runtime",
"files",
"accepted",
}
if set(manifest) != expected_manifest_keys:
raise ReferenceGraphResultError("reference graph manifest fields changed")
if manifest.get("schema_version") != REFERENCE_GRAPH_MANIFEST_SCHEMA:
raise ReferenceGraphResultError("reference graph manifest schema changed")
if not isinstance(manifest.get("accepted"), bool):
raise ReferenceGraphResultError("reference graph acceptance type changed")
identity = {
key: manifest[key]
for key in (
"graph_id",
"source_profile_id",
"run_mode",
"canonical_payload_sha256",
"runtime",
"files",
)
}
identity_sha256 = hashlib.sha256(_canonical_json(identity)).hexdigest()
if (
manifest.get("result_id") != resolved.name
or manifest.get("identity_sha256") != identity_sha256
or resolved.name != f"{REFERENCE_GRAPH_RESULT_PREFIX}{identity_sha256}"
):
raise ReferenceGraphResultError("reference graph identity changed")
runtime = ReferenceGraphRuntimeIdentity.from_dict(manifest.get("runtime"))
files = manifest.get("files")
if not isinstance(files, dict) or set(files) != {
"frames.jsonl",
"outcomes.jsonl",
"report.json",
"runtime.json",
}:
raise ReferenceGraphResultError("reference graph artifact inventory changed")
for name, descriptor_value in files.items():
if not isinstance(descriptor_value, dict) or set(descriptor_value) != {
"sha256",
"bytes",
}:
raise ReferenceGraphResultError("reference graph artifact proof changed")
path = _safe_result_file(resolved, name)
if descriptor_value.get("bytes") != path.stat().st_size or descriptor_value.get(
"sha256"
) != _sha256_file(path):
raise ReferenceGraphResultError("reference graph artifact proof does not match")
runtime_document = _read_json(resolved / "runtime.json")
if runtime_document != runtime.to_dict():
raise ReferenceGraphResultError("reference graph runtime artifact changed")
report = _read_json(resolved / "report.json")
if (
report.get("schema_version") != REFERENCE_GRAPH_REPORT_SCHEMA
or report.get("graph_id") != manifest.get("graph_id")
or report.get("canonical_payload_sha256") != manifest.get("canonical_payload_sha256")
or not isinstance(report.get("execution"), dict)
or report["execution"].get("runtime_identity") != runtime_document
or report.get("accepted") is not manifest.get("accepted")
):
raise ReferenceGraphResultError("reference graph report changed")
gates = report.get("gates")
if (
not isinstance(gates, dict)
or not gates
or manifest.get("accepted") is not all(value is True for value in gates.values())
):
raise ReferenceGraphResultError("reference graph acceptance proof changed")
return SealedReferenceGraphResult(
result_id=resolved.name,
result_root=resolved,
accepted=bool(manifest["accepted"]),
report=report,
manifest=manifest,
)
def _write_json_lines(path: Path, rows: tuple[dict[str, object], ...]) -> None:
with path.open("wb") as handle:
for row in rows:
@@ -168,6 +265,28 @@ def _write_json(path: Path, document: dict[str, object]) -> None:
os.fsync(handle.fileno())
def _read_json(path: Path) -> dict[str, object]:
if path.is_symlink() or not path.is_file() or path.stat().st_size > 1024 * 1024:
raise ReferenceGraphResultError("reference graph JSON artifact is invalid")
try:
document = json.loads(path.read_text("utf-8"))
except (OSError, UnicodeDecodeError, json.JSONDecodeError) as error:
raise ReferenceGraphResultError("reference graph JSON artifact is unreadable") from error
if not isinstance(document, dict) or any(not isinstance(key, str) for key in document):
raise ReferenceGraphResultError("reference graph JSON artifact must be an object")
return document
def _safe_result_file(root: Path, name: str) -> Path:
path = root / name
if path.is_symlink():
raise ReferenceGraphResultError("reference graph artifact must not be a symlink")
resolved = path.resolve(strict=True)
if resolved.parent != root or not resolved.is_file():
raise ReferenceGraphResultError("reference graph artifact escaped its result")
return resolved
def _publish_immutable(staging: Path, target: Path) -> None:
if target.exists():
if target.is_symlink() or not target.is_dir():
@@ -199,5 +318,6 @@ __all__ = [
"REFERENCE_GRAPH_RESULT_PREFIX",
"ReferenceGraphResultError",
"SealedReferenceGraphResult",
"read_reference_graph_result",
"seal_reference_graph_result",
]
+4
View File
@@ -98,6 +98,10 @@ def build_m4_threat_replay_router(
"access": "read-only-replay-simulated",
}
@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}/visuals")
def list_visuals(result_id: str) -> dict[str, object]:
frozen = result(result_id)