Files
NODEDC_MISSION_CORE/src/k1link/perception/baseline.py
T

493 lines
20 KiB
Python

"""Executable Milestone 4 baseline binding.
The profile points at immutable local evidence without copying large or sensitive
artifacts into Git. Verification is explicit: missing evidence is a failure, not
an invitation to silently select a different source or experiment result.
"""
from __future__ import annotations
import hashlib
import json
import re
from dataclasses import dataclass
from pathlib import Path
from typing import Final
BASELINE_SCHEMA: Final = "missioncore.perception-m4-baseline/v1"
REUSE_INVENTORY_SCHEMA: Final = "missioncore.perception-reuse-inventory/v1"
BASELINE_PROFILE_ID: Final = "m4-ravnoves00-recorded-realtime/v1"
BASELINE_SOURCE_ID: Final = "RAVNOVES00"
BASELINE_SESSION_ID: Final = "20260720T065719Z_viewer_live"
BASELINE_CAMERA_SOURCE_ID: Final = "sensor.camera.right"
BASELINE_RECORDED_JOB_ID: Final = "recorded-camera-602ac89026ed12978619801d"
BASELINE_CAMERA_STREAM_SHA256: Final = (
"cadd1696ff000904eb78633a0a8418104b8024f178b91f3421789021ccb160e8"
)
BASELINE_CAMERA_SUMMARY_SHA256: Final = (
"b280f40b198aad5d5335819107fb1405ad65d5695d187c61a2c027ad853a3181"
)
BASELINE_CAMERA_INDEX_SHA256: Final = (
"e029815a60ad9fbfedb6169142c7449df2b119a51d1ce001f08806e04eb0be14"
)
BASELINE_SOURCE_PACK_ID: Final = (
"e10-lidar-pack-576c994a6c814e2592dd6240ace3902a5db94843312c759a73ba0c9166157d2b"
)
BASELINE_SOURCE_PACK_MANIFEST_SHA256: Final = (
"7e4af82eb7dfd47e242dc5207d55456cd0a5ab4c6780c584d4685ef854a73bf5"
)
BASELINE_SOURCE_PACK_SHA256: Final = (
"0685d24219d8236caf8b7f1685e93f6d6b59e7fd015a768d88a92bbe8b154944"
)
BASELINE_PREPROCESS_PROFILE_SHA256: Final = (
"19c17dbc23f2b1c539eb6b8214e69fa487ea3fec8db9d88768dffc714895fb88"
)
BASELINE_FILE_SHA256: Final = (
"ea10359339e6cce31b5780a2710299771cab7cc0c1c2a2b56a1621f786b31fa8"
)
_SHA256 = re.compile(r"^[a-f0-9]{64}$")
_EXPECTED_EVIDENCE_ROLES: Final = {
"source-fusion",
"track-geometry",
"source-paced-worker",
"temporal-occupied",
"degradation-recovery",
"raw-fisheye-detector-capacity",
}
_BASELINE_KEYS: Final = {
"schema_version",
"profile_id",
"source",
"calibration",
"detector",
"evidence",
"authority",
"non_goals",
"rollback",
}
_EVIDENCE_KEYS: Final = {
"role",
"relative_path",
"schema_version",
"result_id",
"identity_sha256",
"file_sha256",
}
_SOURCE_KEYS: Final = {
"source_id",
"session_id",
"camera_source_id",
"recorded_job_id",
"frame_count",
"duration_seconds",
"frame_rate",
"modalities",
"camera_stream_sha256",
"source_pack_id",
"source_pack_artifact_sha256",
}
_EXPECTED_CALIBRATION: Final[dict[str, object]] = {
"slot": "camera_1",
"model": "KB4",
"sha256": "05f3ad9b38b3a4fc95388a8ec83da83c745e217709e51787b3d5aad0969f6fa9",
"valid_fov_result_id": (
"valid-fov-mask-b4dd8ddf2b87c1d520ee8a0868c4fea062d7c14d1bae73ccabd3abe1f3acbac2"
),
"valid_fov_mask_sha256": (
"a40cee06b7c6f69b6a09a11563dcfd237f3de833b1ccd31459e66692e528ba63"
),
}
_EXPECTED_DETECTOR: Final[dict[str, object]] = {
"provider_id": "triton-yolox-s-raw-kb4/v1",
"model_id": "yolox_s",
"model_version": 1,
"model_sha256": "c5c2d13e59ae883e6af3b45daea64af4833a4951c92d116ec270d9ddbe998063",
"config_sha256": "5795c737a7935a655961b069e8404d336d891f9762fb6dffb93956a076479604",
"preprocess_profile_sha256": BASELINE_PREPROCESS_PROFILE_SHA256,
"minimum_score": 0.5,
"nms_iou_threshold": 0.45,
"runtime": "NVIDIA Triton 2.70.0 ONNX Runtime GPU backend",
}
_EXPECTED_NON_GOALS: Final = (
"semantic-class-quality",
"persistent-reidentification",
"physical-live-k1",
"physical-threat-authority",
"navigation-or-command-authority",
"second-source-transfer",
"second-worker-bootstrap",
"ros2-nav2-px4-gazebo-integration",
"deepstream-migration",
)
_EXPECTED_ROLLBACK: Final[dict[str, object]] = {
"worker_id": "worker-006",
"worker_node": "DESKTOP-OPJ8J04",
"container_name": "ndc-mission-core-perception-worker",
"container_image": (
"nvcr.io/nvidia/tritonserver:26.06-py3@"
"sha256:58df7489c3f2276f9591d500a012dee03e23d35543ce3c390b4c001e6bf90794"
),
"worker_package_id": (
"e15-worker-package-dbf55ccb75664b778a2e0f5d34284af10ec0971945bbbee67b27bc264b765b51"
),
"runner_sha256": "86e9b25c80908a520ed483541b708cde1d1c74605e094053fcb62b610ecefb20",
"orchestrator_sha256": (
"82de50ae83debe26fc5463799b1e1e15217a8db8cc090671ba2993200b8ed95c"
),
"entrypoint": "python3 /runner/run_e15_shadow_inference.py serve",
"observed_container_id": (
"db2024d05098a6beb6b73bbf43f02c88ede586a4664b2c91182f436a42b3e3ff"
),
"observed_at_utc": "2026-08-05T10:30:00Z",
}
class BaselineContractError(ValueError):
"""The recorded-realtime baseline is ambiguous, mutated or incomplete."""
@dataclass(frozen=True, slots=True)
class BaselineEvidence:
role: str
relative_path: str
schema_version: str
result_id: str
identity_sha256: str
file_sha256: str
@dataclass(frozen=True, slots=True)
class BaselineProfile:
path: Path
document: dict[str, object]
evidence: tuple[BaselineEvidence, ...]
@dataclass(frozen=True, slots=True)
class BaselineVerification:
profile_id: str
source_id: str
session_id: str
verified_paths: tuple[str, ...]
def load_m4_baseline(path: Path) -> BaselineProfile:
"""Load and fail-closed validate the one admitted M4 baseline profile."""
document = _read_object(path)
_exact_keys(document, _BASELINE_KEYS, "baseline")
if document.get("schema_version") != BASELINE_SCHEMA:
raise BaselineContractError("baseline schema is incompatible")
if document.get("profile_id") != BASELINE_PROFILE_ID:
raise BaselineContractError("baseline profile identity changed")
source = _object(document.get("source"), "source")
_exact_keys(source, _SOURCE_KEYS, "source")
if source.get("source_id") != BASELINE_SOURCE_ID:
raise BaselineContractError("M4 source must remain RAVNOVES00")
if source.get("session_id") != BASELINE_SESSION_ID:
raise BaselineContractError("M4 source session identity changed")
if source.get("camera_source_id") != BASELINE_CAMERA_SOURCE_ID:
raise BaselineContractError("M4 camera source identity changed")
if source.get("recorded_job_id") != BASELINE_RECORDED_JOB_ID:
raise BaselineContractError("M4 recorded job identity changed")
if source.get("source_pack_id") != BASELINE_SOURCE_PACK_ID:
raise BaselineContractError("M4 source pack identity changed")
if source.get("source_pack_artifact_sha256") != BASELINE_SOURCE_PACK_SHA256:
raise BaselineContractError("M4 source pack artifact identity changed")
if source.get("camera_stream_sha256") != BASELINE_CAMERA_STREAM_SHA256:
raise BaselineContractError("M4 camera stream identity changed")
if source.get("frame_count") != 4489:
raise BaselineContractError("baseline source frame count changed")
if source.get("duration_seconds") != 448.723:
raise BaselineContractError("baseline source duration changed")
if source.get("frame_rate") != 10.003944527024467:
raise BaselineContractError("baseline source frame rate changed")
modalities = _string_array(source.get("modalities"), "source modalities")
if modalities != ("image", "registered-point-increment", "pose"):
raise BaselineContractError("baseline source must bind image, points and pose")
calibration = _object(document.get("calibration"), "calibration")
if calibration != _EXPECTED_CALIBRATION:
raise BaselineContractError("baseline calibration identity changed")
detector = _object(document.get("detector"), "detector")
if detector != _EXPECTED_DETECTOR:
raise BaselineContractError("baseline detector identity changed")
authority = _object(document.get("authority"), "authority")
if authority != {
"mode": "replay-simulated",
"ground_truth": False,
"physical_live": False,
"physical_collision_accepted": False,
"commands_enabled": False,
"actuation_allowed": False,
"navigation_or_safety_accepted": False,
}:
raise BaselineContractError("M4 authority must remain replay-simulated and false")
if _string_array(document.get("non_goals"), "non-goals") != _EXPECTED_NON_GOALS:
raise BaselineContractError("baseline non-goals changed")
evidence_items = document.get("evidence")
if not isinstance(evidence_items, list):
raise BaselineContractError("baseline evidence must be an array")
evidence = tuple(_evidence(item) for item in evidence_items)
roles = [item.role for item in evidence]
if len(set(roles)) != len(roles) or set(roles) != _EXPECTED_EVIDENCE_ROLES:
raise BaselineContractError("baseline evidence roles are incomplete or duplicated")
paths = [item.relative_path for item in evidence]
if len(set(paths)) != len(paths):
raise BaselineContractError("baseline evidence paths must be unique")
rollback = _object(document.get("rollback"), "rollback")
if rollback != _EXPECTED_ROLLBACK:
raise BaselineContractError("rollback E15 identity changed")
if _file_sha256(path) != BASELINE_FILE_SHA256:
raise BaselineContractError("baseline file bytes changed")
return BaselineProfile(path=path, document=document, evidence=evidence)
def verify_m4_baseline(repository_root: Path, profile: BaselineProfile) -> BaselineVerification:
"""Resolve every immutable evidence document and verify its exact digest."""
root = repository_root.resolve()
source_paths = _repository_source_paths(root, profile)
verify_m4_execution_source(
profile,
camera_summary_path=source_paths[0],
camera_index_path=source_paths[1],
source_pack_manifest_path=source_paths[2],
source_pack_path=source_paths[3],
)
verified = [str(path.relative_to(root)) for path in source_paths]
for item in profile.evidence:
evidence_path = (root / item.relative_path).resolve()
if root not in evidence_path.parents:
raise BaselineContractError("baseline evidence escapes the repository root")
if not evidence_path.is_file():
raise BaselineContractError(f"baseline evidence is missing: {item.relative_path}")
if _file_sha256(evidence_path) != item.file_sha256:
raise BaselineContractError(f"baseline evidence digest changed: {item.role}")
evidence_document = _read_object(evidence_path)
if evidence_document.get("schema_version") != item.schema_version:
raise BaselineContractError(f"baseline evidence schema changed: {item.role}")
if evidence_document.get("identity_sha256") != item.identity_sha256:
raise BaselineContractError(f"baseline evidence identity changed: {item.role}")
result_id = evidence_document.get("result_id")
if result_id is None and item.role == "source-fusion":
result_id = evidence_path.parent.name
if result_id != item.result_id:
raise BaselineContractError(f"baseline evidence result changed: {item.role}")
verified.append(item.relative_path)
source = _object(profile.document.get("source"), "source")
return BaselineVerification(
profile_id=BASELINE_PROFILE_ID,
source_id=_string(source.get("source_id"), "source id"),
session_id=_string(source.get("session_id"), "session id"),
verified_paths=tuple(verified),
)
def verify_m4_execution_source(
profile: BaselineProfile,
*,
camera_summary_path: Path,
camera_index_path: Path,
source_pack_manifest_path: Path,
source_pack_path: Path,
) -> tuple[Path, ...]:
"""Verify only immutable source inputs required by a deployed replay runner."""
source = _object(profile.document.get("source"), "source")
camera_source_id = _string(source.get("camera_source_id"), "camera source id")
source_pack_id = _string(source.get("source_pack_id"), "source pack id")
expected_frames = _integer(source.get("frame_count"), "source frame count")
source_inputs = (
camera_summary_path,
camera_index_path,
source_pack_manifest_path,
source_pack_path,
)
if any(path.is_symlink() or not path.is_file() for path in source_inputs):
raise BaselineContractError("execution source inputs must be regular non-symlink files")
paths = tuple(path.resolve(strict=True) for path in source_inputs)
summary_path, index_path, pack_manifest_path, pack_artifact_path = paths
if _file_sha256(summary_path) != BASELINE_CAMERA_SUMMARY_SHA256:
raise BaselineContractError("camera recording summary digest changed")
if _file_sha256(index_path) != BASELINE_CAMERA_INDEX_SHA256:
raise BaselineContractError("camera recording index digest changed")
summary = _read_object(summary_path)
if summary.get("schema_version") != "missioncore.camera-recording/v1":
raise BaselineContractError("camera recording summary schema changed")
if summary.get("source_id") != camera_source_id:
raise BaselineContractError("camera recording source identity changed")
if summary.get("status") != "complete":
raise BaselineContractError("camera recording is incomplete")
if _integer(summary.get("media_segment_count"), "camera segment count") != expected_frames:
raise BaselineContractError("camera recording frame count changed")
if summary.get("stream_sha256") != source.get("camera_stream_sha256"):
raise BaselineContractError("camera recording stream digest changed")
if _file_sha256(index_path) != summary.get("index_sha256"):
raise BaselineContractError("camera recording index digest changed")
if _file_sha256(pack_manifest_path) != BASELINE_SOURCE_PACK_MANIFEST_SHA256:
raise BaselineContractError("source pack manifest file digest changed")
pack_manifest = _read_object(pack_manifest_path)
if pack_manifest.get("schema_version") != "missioncore.e10-lidar-replay-pack/v1":
raise BaselineContractError("source pack schema changed")
if pack_manifest.get("pack_id") != source_pack_id:
raise BaselineContractError("source pack identity changed")
identity = _object(pack_manifest.get("identity"), "source pack identity")
if _integer(identity.get("frame_count"), "source pack frame count") != expected_frames:
raise BaselineContractError("source pack frame count changed")
artifact = _object(pack_manifest.get("artifact"), "source pack artifact")
expected_pack_sha = _string(
source.get("source_pack_artifact_sha256"),
"source pack artifact digest",
)
if artifact.get("sha256") != expected_pack_sha:
raise BaselineContractError("source pack manifest digest changed")
if _file_sha256(pack_artifact_path) != expected_pack_sha:
raise BaselineContractError("source pack artifact digest changed")
return paths
def _repository_source_paths(root: Path, profile: BaselineProfile) -> tuple[Path, ...]:
source = _object(profile.document.get("source"), "source")
recorded_job_id = _string(source.get("recorded_job_id"), "recorded job id")
camera_source_id = _string(source.get("camera_source_id"), "camera source id")
source_pack_id = _string(source.get("source_pack_id"), "source pack id")
camera_root = (
root
/ ".runtime/compute-jobs"
/ recorded_job_id
/ "input/camera"
/ camera_source_id
/ "epoch-1"
)
pack_root = root / ".runtime/compute-experiments/e10/lidar-packs" / source_pack_id
return (
camera_root / "summary.json",
camera_root / "index.jsonl",
pack_root / "manifest.json",
pack_root / "lidar-pack.npz",
)
def validate_reuse_inventory(path: Path) -> dict[str, object]:
"""Validate the M4 primitive/wrapper split used by architecture tests."""
document = _read_object(path)
_exact_keys(
document,
{
"schema_version",
"profile_id",
"reusable_primitives",
"historical_wrappers",
"rules",
},
"reuse inventory",
)
if document.get("schema_version") != REUSE_INVENTORY_SCHEMA:
raise BaselineContractError("reuse inventory schema is incompatible")
reusable = document.get("reusable_primitives")
wrappers = document.get("historical_wrappers")
if not isinstance(reusable, list) or not reusable:
raise BaselineContractError("reuse inventory has no admitted primitives")
if not isinstance(wrappers, list) or not wrappers:
raise BaselineContractError("reuse inventory has no historical wrappers")
reusable_modules = {_module(item, "reusable primitive") for item in reusable}
wrapper_modules = {_module(item, "historical wrapper") for item in wrappers}
if reusable_modules & wrapper_modules:
raise BaselineContractError("a module cannot be reusable and historical")
rules = _object(document.get("rules"), "reuse rules")
expected_rules = {
"historical_wrappers_are_product_dependencies": False,
"contracts_may_import_compute": False,
"graph_may_import_experiment_modules": False,
"providers_may_import_admitted_primitives": True,
"bulk_legacy_migration_required": False,
}
if rules != expected_rules:
raise BaselineContractError("reuse dependency rules changed")
return document
def _evidence(value: object) -> BaselineEvidence:
document = _object(value, "evidence item")
_exact_keys(document, _EVIDENCE_KEYS, "evidence item")
relative_path = _string(document.get("relative_path"), "evidence path")
path = Path(relative_path)
if path.is_absolute() or ".." in path.parts or path.suffix != ".json":
raise BaselineContractError("evidence path must be a relative JSON path")
return BaselineEvidence(
role=_string(document.get("role"), "evidence role"),
relative_path=relative_path,
schema_version=_string(document.get("schema_version"), "evidence schema"),
result_id=_string(document.get("result_id"), "evidence result id"),
identity_sha256=_digest(document.get("identity_sha256"), "evidence identity"),
file_sha256=_digest(document.get("file_sha256"), "evidence file digest"),
)
def _module(value: object, label: str) -> str:
document = _object(value, label)
return _string(document.get("module"), f"{label} module")
def _read_object(path: Path) -> dict[str, object]:
try:
value = json.loads(path.read_text("utf-8"))
except (OSError, json.JSONDecodeError) as exc:
raise BaselineContractError(f"cannot read baseline document: {path}") from exc
return _object(value, str(path))
def _file_sha256(path: Path) -> str:
digest = hashlib.sha256()
with path.open("rb") as handle:
for chunk in iter(lambda: handle.read(1024 * 1024), b""):
digest.update(chunk)
return digest.hexdigest()
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 BaselineContractError(f"{label} must be an object")
return value
def _exact_keys(document: dict[str, object], expected: set[str], label: str) -> None:
if set(document) != expected:
raise BaselineContractError(f"{label} fields are incompatible")
def _string(value: object, label: str) -> str:
if not isinstance(value, str) or not value:
raise BaselineContractError(f"{label} must be a nonempty string")
return value
def _integer(value: object, label: str) -> int:
if not isinstance(value, int) or isinstance(value, bool):
raise BaselineContractError(f"{label} must be an integer")
return value
def _string_array(value: object, label: str) -> tuple[str, ...]:
if not isinstance(value, list):
raise BaselineContractError(f"{label} must be an array")
return tuple(_string(item, label) for item in value)
def _digest(value: object, label: str) -> str:
digest = _string(value, label)
if _SHA256.fullmatch(digest) is None:
raise BaselineContractError(f"{label} must be a SHA-256 digest")
return digest