feat(perception): establish object centric contracts

This commit is contained in:
DCCONSTRUCTIONS
2026-08-05 13:32:34 +03:00
parent 8ef215e98f
commit ae1e41f7fe
8 changed files with 2665 additions and 0 deletions
+287
View File
@@ -0,0 +1,287 @@
"""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"
_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",
}
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")
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")
modalities = _string_array(source.get("modalities"), "source modalities")
if set(modalities) != {"image", "registered-point-increment", "pose"}:
raise BaselineContractError("baseline source must bind image, points and pose")
if _integer(source.get("frame_count"), "source frame count") != 4489:
raise BaselineContractError("baseline source frame count changed")
authority = _object(document.get("authority"), "authority")
if authority.get("mode") != "replay-simulated":
raise BaselineContractError("M4 authority must remain replay-simulated")
for key in (
"ground_truth",
"physical_live",
"physical_collision_accepted",
"commands_enabled",
"actuation_allowed",
"navigation_or_safety_accepted",
):
if authority.get(key) is not False:
raise BaselineContractError(f"baseline authority {key} must remain false")
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.get("worker_id") != "worker-006":
raise BaselineContractError("rollback worker identity changed")
if rollback.get("worker_node") != "DESKTOP-OPJ8J04":
raise BaselineContractError("rollback worker node changed")
entrypoint = rollback.get("entrypoint")
if not isinstance(entrypoint, str) or "run_e15_shadow_inference.py serve" not in entrypoint:
raise BaselineContractError("rollback E15 process identity is missing")
_digest(rollback.get("runner_sha256"), "rollback runner digest")
_digest(rollback.get("orchestrator_sha256"), "rollback orchestrator digest")
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()
verified: list[str] = []
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 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