feat(lab): stabilize autonomous TGS playback

This commit is contained in:
DCCONSTRUCTIONS
2026-08-27 20:34:20 +03:00
parent c8593207d3
commit 95a1ef5057
26 changed files with 3326 additions and 253 deletions
@@ -0,0 +1,538 @@
"""Build and verify autonomous chunked M49 physical-safety playback artifacts."""
from __future__ import annotations
import hashlib
import json
import math
import shutil
import struct
import tempfile
from dataclasses import dataclass
from datetime import UTC, datetime
from pathlib import Path
from typing import Any, Final
import numpy as np
SCHEMA: Final = "missioncore.m49-physical-safety-playback/v1"
PROFILE_SCHEMA: Final = "missioncore.m49-physical-safety-shadow-profile/v1"
PREFIX: Final = "m49-physical-safety-playback-"
CHUNK_MAGIC: Final = b"MCPSCH01"
CHUNK_HEADER: Final = struct.Struct("<8sIIIII")
SOURCE_TRACKS: Final = (
"costmap-cell-centers-xy-m.npy",
"costmap-states.npy",
"costmap-z-bounds-m.npy",
"frames.ndjson",
)
_HASH_BLOCK_BYTES: Final = 1024 * 1024
_MAX_JSON_BYTES: Final = 4 * 1024 * 1024
class M49PhysicalSafetyPlaybackError(RuntimeError):
"""The autonomous playback artifact is missing or violates its contract."""
@dataclass(frozen=True, slots=True)
class M49PhysicalSafetyPlayback:
result_id: str
root: Path
manifest: dict[str, Any]
def _sha256(path: Path) -> str:
digest = hashlib.sha256()
with path.open("rb") as stream:
for block in iter(lambda: stream.read(_HASH_BLOCK_BYTES), b""):
digest.update(block)
return digest.hexdigest()
def _canonical_sha256(value: object) -> str:
content = json.dumps(
value,
ensure_ascii=False,
sort_keys=True,
separators=(",", ":"),
allow_nan=False,
).encode("utf-8")
return hashlib.sha256(content).hexdigest()
def _json(path: Path, label: str) -> dict[str, Any]:
if path.is_symlink() or not path.is_file() or path.stat().st_size > _MAX_JSON_BYTES:
raise M49PhysicalSafetyPlaybackError(f"{label} is unavailable")
try:
value = json.loads(path.read_text(encoding="utf-8-sig"))
except (OSError, UnicodeDecodeError, json.JSONDecodeError) as error:
raise M49PhysicalSafetyPlaybackError(f"{label} is invalid") from error
if not isinstance(value, dict):
raise M49PhysicalSafetyPlaybackError(f"{label} is invalid")
return value
def _artifact(path: Path, *, media_type: str, role: str) -> dict[str, object]:
return {
"path": path.name,
"media_type": media_type,
"role": role,
"byte_length": path.stat().st_size,
"sha256": _sha256(path),
}
def _source_artifacts(source: Path, manifest: dict[str, Any]) -> dict[str, dict[str, Any]]:
artifacts = manifest.get("artifacts")
if not isinstance(artifacts, list):
raise M49PhysicalSafetyPlaybackError("source artifact catalog is unavailable")
result: dict[str, dict[str, Any]] = {}
for value in artifacts:
if not isinstance(value, dict) or not isinstance(value.get("path"), str):
raise M49PhysicalSafetyPlaybackError("source artifact catalog is invalid")
name = value["path"]
if name in (*SOURCE_TRACKS, "report.json"):
path = source / name
if (
path.parent != source
or path.is_symlink()
or not path.is_file()
or value.get("byte_length") != path.stat().st_size
or value.get("sha256") != _sha256(path)
):
raise M49PhysicalSafetyPlaybackError(f"source artifact changed: {name}")
result[name] = value
if set(result) != {*SOURCE_TRACKS, "report.json"}:
raise M49PhysicalSafetyPlaybackError("source spatial tracks are incomplete")
return result
def _state_codes(report: dict[str, Any]) -> dict[str, int]:
candidates = (
report.get("state_codes"),
report.get("visual_review", {}).get("state_codes")
if isinstance(report.get("visual_review"), dict)
else None,
)
for candidate in candidates:
if not isinstance(candidate, dict):
continue
parsed = {
str(name): int(code)
for name, code in candidate.items()
if isinstance(name, str)
and isinstance(code, int)
and not isinstance(code, bool)
and 0 <= code <= 255
}
if len(parsed) == len(candidate) and parsed.get("UNOBSERVED") == 0:
return parsed
raise M49PhysicalSafetyPlaybackError("source state codes are unavailable")
def _frame_rows(path: Path) -> tuple[dict[str, Any], ...]:
rows: list[dict[str, Any]] = []
try:
with path.open("r", encoding="utf-8") as stream:
for sequence, line in enumerate(stream):
value = json.loads(line)
if (
not isinstance(value, dict)
or not isinstance(value.get("sample_available"), bool)
or not isinstance(value.get("source_frame_index"), int)
or isinstance(value.get("source_frame_index"), bool)
or not isinstance(value.get("session_seconds"), (int, float))
or isinstance(value.get("session_seconds"), bool)
or not math.isfinite(float(value["session_seconds"]))
):
raise M49PhysicalSafetyPlaybackError(
f"source frame catalog changed at sequence {sequence}"
)
rows.append(value)
except (OSError, UnicodeDecodeError, json.JSONDecodeError) as error:
raise M49PhysicalSafetyPlaybackError("source frame catalog is invalid") from error
if not rows:
raise M49PhysicalSafetyPlaybackError("source frame catalog is empty")
return tuple(rows)
def _source_geometry(report: dict[str, Any]) -> tuple[float, float, str]:
configuration = report.get("configuration")
if not isinstance(configuration, dict):
raise M49PhysicalSafetyPlaybackError("source geometry is unavailable")
cell_size = configuration.get("cell_size_m")
radius = configuration.get("radius_m")
coordinate_frame = configuration.get("coordinate_frame")
if (
not isinstance(cell_size, (int, float))
or isinstance(cell_size, bool)
or not math.isfinite(float(cell_size))
or float(cell_size) <= 0
or not isinstance(radius, (int, float))
or isinstance(radius, bool)
or not math.isfinite(float(radius))
or float(radius) <= 0
or coordinate_frame != "map-gravity-local"
):
raise M49PhysicalSafetyPlaybackError("source geometry changed")
return float(cell_size), float(radius), coordinate_frame
def _profile_policy(profile: dict[str, Any], cell_size_m: float) -> dict[str, int]:
visual = profile.get("operator_visual")
terrain = profile.get("terrain_evidence")
if (
profile.get("schema_version") != PROFILE_SCHEMA
or not isinstance(visual, dict)
or not isinstance(terrain, dict)
or visual.get("worker_role") != "realtime-only"
or visual.get("worker_runtime_dependency") is not False
or visual.get("sealed_artifact_required") is not True
):
raise M49PhysicalSafetyPlaybackError("physical-safety profile changed")
playback = visual.get("playback_buffer")
admitted_sizes = [
terrain.get("accepted_baseline_cell_size_m"),
*(terrain.get("challenger_cell_sizes_m") or []),
]
if (
not isinstance(playback, dict)
or playback.get("chunk_frame_count") != 32
or playback.get("startup_prebuffer_chunk_count") != 2
or playback.get("resident_chunk_count_max") != 3
or not any(
isinstance(value, (int, float))
and not isinstance(value, bool)
and math.isclose(float(value), cell_size_m, abs_tol=1e-9)
for value in admitted_sizes
)
):
raise M49PhysicalSafetyPlaybackError("physical-safety playback policy changed")
return {
"chunk_frame_count": 32,
"startup_prebuffer_chunk_count": 2,
"resident_chunk_count_max": 3,
"forward_prefetch_chunk_count": 1,
}
def _chunk_payload(
path: Path,
*,
start: int,
states: np.ndarray,
z_bounds: np.ndarray,
) -> None:
frame_count, cell_count = states.shape
state_values = np.ascontiguousarray(states, dtype=np.uint8)
z_values = np.ascontiguousarray(z_bounds, dtype="<f4")
state_bytes = state_values.nbytes
z_bytes = z_values.nbytes
padding = (4 - ((CHUNK_HEADER.size + state_bytes) % 4)) % 4
with path.open("wb") as stream:
stream.write(
CHUNK_HEADER.pack(
CHUNK_MAGIC,
start,
frame_count,
cell_count,
state_bytes,
z_bytes,
)
)
stream.write(memoryview(state_values).cast("B"))
if padding:
stream.write(b"\0" * padding)
stream.write(memoryview(z_values).cast("B"))
def seal_m49_physical_safety_playback(
*,
source_root: Path,
destination_root: Path,
profile_path: Path,
created_at_utc: str | None = None,
) -> M49PhysicalSafetyPlayback:
"""Sequentially seal local tracks without starting or contacting Worker 006."""
raw_source = source_root.expanduser().absolute()
if raw_source.is_symlink() or not raw_source.is_dir():
raise M49PhysicalSafetyPlaybackError("sealed source root is unavailable")
source = raw_source.resolve(strict=True)
destination = destination_root.expanduser().absolute()
destination.mkdir(parents=True, exist_ok=True)
if destination.is_symlink():
raise M49PhysicalSafetyPlaybackError("destination must not be a symlink")
raw_profile = profile_path.expanduser().absolute()
if raw_profile.is_symlink() or not raw_profile.is_file():
raise M49PhysicalSafetyPlaybackError("physical-safety profile is unavailable")
profile_file = raw_profile.resolve(strict=True)
source_manifest = _json(source / "manifest.json", "source manifest")
source_report = _json(source / "report.json", "source report")
source_result_id = source_manifest.get("result_id")
source_identity = source_manifest.get("identity")
source_identity_sha256 = source_manifest.get("identity_sha256")
if (
not isinstance(source_result_id, str)
or source_report.get("result_id") != source_result_id
or not isinstance(source_identity, dict)
or not isinstance(source_identity_sha256, str)
or source_identity_sha256 != _canonical_sha256(source_identity)
or not source_result_id.endswith(source_identity_sha256)
):
raise M49PhysicalSafetyPlaybackError("source result identity changed")
source_artifacts = _source_artifacts(source, source_manifest)
state_codes = _state_codes(source_report)
cell_size_m, radius_m, coordinate_frame = _source_geometry(source_report)
profile = _json(profile_file, "physical-safety profile")
policy = _profile_policy(profile, cell_size_m)
profile_sha256 = _sha256(profile_file)
source_manifest_sha256 = _sha256(source / "manifest.json")
try:
centers = np.load(
source / "costmap-cell-centers-xy-m.npy", mmap_mode="r", allow_pickle=False
)
states = np.load(source / "costmap-states.npy", mmap_mode="r", allow_pickle=False)
z_bounds = np.load(
source / "costmap-z-bounds-m.npy", mmap_mode="r", allow_pickle=False
)
except (OSError, ValueError) as error:
raise M49PhysicalSafetyPlaybackError("source numeric tracks are invalid") from error
frames = _frame_rows(source / "frames.ndjson")
if (
centers.dtype != np.dtype("<f4")
or states.dtype != np.dtype("uint8")
or z_bounds.dtype != np.dtype("<f4")
or centers.ndim != 2
or centers.shape[1] != 2
or states.ndim != 2
or z_bounds.ndim != 3
or z_bounds.shape[2] != 2
or states.shape[0] != len(frames)
or states.shape[1] != centers.shape[0]
or z_bounds.shape != (states.shape[0], states.shape[1], 2)
or not np.isfinite(centers).all()
):
raise M49PhysicalSafetyPlaybackError("source numeric shape or dtype changed")
frame_count, cell_count = states.shape
admitted_codes = np.asarray(sorted(set(state_codes.values())), dtype=np.uint8)
identity = {
"schema_version": SCHEMA,
"source_result_id": source_result_id,
"source_manifest_sha256": source_manifest_sha256,
"source_track_sha256": {
name: source_artifacts[name]["sha256"] for name in SOURCE_TRACKS
},
"profile_id": profile.get("profile_id"),
"profile_sha256": profile_sha256,
"coordinate_frame": coordinate_frame,
"frame_count": frame_count,
"cell_count": cell_count,
"cell_size_m": cell_size_m,
"radius_m": radius_m,
"state_codes": state_codes,
"playback_policy": policy,
"authority": {
"commands_enabled": False,
"navigation_or_safety_accepted": False,
"actuation_accepted": False,
},
}
identity_sha256 = _canonical_sha256(identity)
result_id = f"{PREFIX}{identity_sha256}"
target = destination / result_id
if target.exists():
existing = read_m49_physical_safety_playback(target)
existing_playback = existing.manifest["playback"]
assert isinstance(existing_playback, dict)
existing_chunks = existing_playback["chunks"]
assert isinstance(existing_chunks, list)
for value in (
existing_playback["centers"],
existing_playback["frames"],
*existing_chunks,
):
assert isinstance(value, dict)
verify_m49_physical_safety_artifact(existing, value)
return existing
created = created_at_utc or datetime.now(tz=UTC).isoformat().replace("+00:00", "Z")
chunk_frame_count = int(policy["chunk_frame_count"])
with tempfile.TemporaryDirectory(
prefix="mission-core-m49-physical-safety-", dir=destination
) as raw_staging:
staging = Path(raw_staging) / result_id
staging.mkdir()
centers_path = staging / "centers.f32"
np.ascontiguousarray(centers, dtype="<f4").tofile(centers_path)
frames_path = staging / "frames.ndjson"
shutil.copyfile(source / "frames.ndjson", frames_path)
centers_artifact = _artifact(
centers_path,
media_type="application/octet-stream",
role="costmap-cell-centers-f32le",
)
frames_artifact = _artifact(
frames_path,
media_type="application/x-ndjson",
role="frame-catalog",
)
chunks: list[dict[str, object]] = []
for index, start in enumerate(range(0, frame_count, chunk_frame_count)):
count = min(chunk_frame_count, frame_count - start)
state_slice = states[start : start + count]
if not np.isin(state_slice, admitted_codes).all():
raise M49PhysicalSafetyPlaybackError(
f"source state code changed in chunk {index}"
)
for local_index, frame in enumerate(frames[start : start + count]):
if frame["sample_available"] is False and (
np.any(state_slice[local_index] != 0)
or np.isfinite(z_bounds[start + local_index]).any()
):
raise M49PhysicalSafetyPlaybackError(
"missing source sample did not remain fail-closed"
)
chunk_path = staging / f"chunk-{index:06d}.bin"
_chunk_payload(
chunk_path,
start=start,
states=state_slice,
z_bounds=z_bounds[start : start + count],
)
descriptor = _artifact(
chunk_path,
media_type="application/octet-stream",
role="states-u8-and-z-bounds-f32le",
)
descriptor.update(
{
"index": index,
"start": start,
"count": count,
"header_bytes": CHUNK_HEADER.size,
"format": "mcpsch01-states-u8-aligned-z-bounds-f32le",
}
)
chunks.append(descriptor)
manifest = {
"schema_version": SCHEMA,
"result_id": result_id,
"created_at_utc": created,
"identity_sha256": identity_sha256,
"identity": identity,
"execution": {
"execution_class": "local-sequential-offline",
"worker_role": "realtime-only",
"worker_runtime_dependency": False,
"worker_requests_required": 0,
},
"playback": {
"coordinate_frame": coordinate_frame,
"source_pace_hz": profile["operator_visual"]["source_pace_hz"],
"frame_count": frame_count,
"cell_count": cell_count,
"cell_size_m": cell_size_m,
"radius_m": radius_m,
"state_codes": state_codes,
**policy,
"centers": {
**centers_artifact,
"dtype": "<f4",
"shape": [cell_count, 2],
},
"frames": {
**frames_artifact,
"dtype": "ndjson",
"shape": [frame_count],
},
"chunks": chunks,
},
"authority": identity["authority"],
}
(staging / "manifest.json").write_text(
json.dumps(manifest, indent=2, sort_keys=True, allow_nan=False) + "\n",
encoding="utf-8",
)
staging.replace(target)
return read_m49_physical_safety_playback(target)
def read_m49_physical_safety_playback(root: Path) -> M49PhysicalSafetyPlayback:
raw_candidate = root.expanduser().absolute()
if raw_candidate.is_symlink() or not raw_candidate.is_dir():
raise M49PhysicalSafetyPlaybackError("physical-safety playback root is invalid")
candidate = raw_candidate.resolve(strict=True)
manifest = _json(candidate / "manifest.json", "physical-safety playback manifest")
identity = manifest.get("identity")
execution = manifest.get("execution")
if (
manifest.get("schema_version") != SCHEMA
or not isinstance(identity, dict)
or not isinstance(execution, dict)
or manifest.get("identity_sha256") != _canonical_sha256(identity)
or manifest.get("result_id") != candidate.name
or candidate.name != f"{PREFIX}{manifest.get('identity_sha256')}"
or execution.get("worker_requests_required") != 0
or execution.get("worker_runtime_dependency") is not False
):
raise M49PhysicalSafetyPlaybackError("physical-safety playback identity changed")
playback = manifest.get("playback")
if not isinstance(playback, dict) or not isinstance(playback.get("chunks"), list):
raise M49PhysicalSafetyPlaybackError("physical-safety playback catalog changed")
descriptors = [playback.get("centers"), playback.get("frames"), *playback["chunks"]]
seen: set[str] = set()
for descriptor in descriptors:
if not isinstance(descriptor, dict) or not isinstance(descriptor.get("path"), str):
raise M49PhysicalSafetyPlaybackError("physical-safety artifact entry changed")
name = descriptor["path"]
path = candidate / name
if (
name in seen
or path.parent != candidate
or path.is_symlink()
or not path.is_file()
or descriptor.get("byte_length") != path.stat().st_size
or not isinstance(descriptor.get("sha256"), str)
or len(descriptor["sha256"]) != 64
or any(character not in "0123456789abcdef" for character in descriptor["sha256"])
):
raise M49PhysicalSafetyPlaybackError("physical-safety artifact changed")
seen.add(name)
return M49PhysicalSafetyPlayback(candidate.name, candidate, manifest)
def verify_m49_physical_safety_artifact(
result: M49PhysicalSafetyPlayback,
descriptor: dict[str, Any],
) -> Path:
name = descriptor.get("path")
if not isinstance(name, str):
raise M49PhysicalSafetyPlaybackError("physical-safety artifact path changed")
path = result.root / name
if (
path.parent != result.root
or path.is_symlink()
or not path.is_file()
or descriptor.get("byte_length") != path.stat().st_size
or descriptor.get("sha256") != _sha256(path)
):
raise M49PhysicalSafetyPlaybackError("physical-safety artifact digest changed")
return path
__all__ = [
"CHUNK_HEADER",
"CHUNK_MAGIC",
"M49PhysicalSafetyPlayback",
"M49PhysicalSafetyPlaybackError",
"PREFIX",
"SCHEMA",
"read_m49_physical_safety_playback",
"seal_m49_physical_safety_playback",
"verify_m49_physical_safety_artifact",
]
+35 -7
View File
@@ -452,6 +452,32 @@ def build_threat_replay(
def read_threat_replay_result(root: Path) -> ThreatReplayResult:
"""Read and deeply verify a sealed threat replay result.
This is the acceptance/build seam. It deliberately walks every ledger row
before returning and therefore must not sit on the synchronous LAB open
path for a hundreds-of-megabytes recorded result.
"""
return _read_threat_replay_result(root, validate_ledgers=True)
def read_threat_replay_result_metadata(root: Path) -> ThreatReplayResult:
"""Read verified result metadata without eagerly parsing the full ledger.
Artifact bytes are still digest checked against the sealed manifest. The
bounded timeline reader validates every requested row before projection;
only the redundant all-4489-row JSON accounting pass is deferred.
"""
return _read_threat_replay_result(root, validate_ledgers=False)
def _read_threat_replay_result(
root: Path,
*,
validate_ledgers: bool,
) -> ThreatReplayResult:
resolved = root.resolve(strict=True)
if resolved.is_symlink() or not resolved.name.startswith(THREAT_REPLAY_RESULT_PREFIX):
raise ThreatReplayError("threat replay result root is invalid")
@@ -498,7 +524,8 @@ def read_threat_replay_result(root: Path) -> ThreatReplayResult:
for role, (name, identity_key) in expected.items():
path = _validated_artifact(resolved, by_role[role], name)
paths[role] = path
if identity_key is not None and _file_sha256(path) != identity.get(identity_key):
artifact = _object(by_role[role], "threat artifact")
if identity_key is not None and artifact.get("sha256") != identity.get(identity_key):
raise ThreatReplayError("threat artifact identity changed")
report = _read_json(paths["threat-replay-report"])
metrics = _object(identity.get("metrics"), "threat metrics")
@@ -522,12 +549,13 @@ def read_threat_replay_result(root: Path) -> ThreatReplayResult:
or requirements != expected_requirements
):
raise ThreatReplayError("threat replay report or acceptance changed")
_validate_ledgers(
paths["threat-replay-frames"],
paths["threat-visual-frames"],
metrics,
is_v2=is_v2,
)
if validate_ledgers:
_validate_ledgers(
paths["threat-replay-frames"],
paths["threat-visual-frames"],
metrics,
is_v2=is_v2,
)
return ThreatReplayResult(
result_id=resolved.name,
result_root=resolved,
+125 -15
View File
@@ -13,6 +13,8 @@ from pathlib import Path
from threading import RLock
from typing import Final
import numpy as np
from .geometry import RecordedGeometryStore
from .recorded_source import RECORDED_REPRESENTATION_ID
from .spatial_evidence import (
@@ -78,24 +80,56 @@ class RecordedThreatTimeline:
}
if any(identity.get(key) != value for key, value in expected_identity.items()):
raise RecordedThreatTimelineError("recorded timeline escaped the threat profile")
self.store = RecordedGeometryStore.from_repository(self.repository_root)
if (
self.store.profile.source_pack_id != self.profile.source_pack_id
or self.store.profile.source_pack_sha256 != self.profile.source_pack_sha256
or self.store.profile.frame_count != _EXPECTED_FRAME_COUNT
):
raise RecordedThreatTimelineError("recorded timeline geometry identity changed")
if self.store.maximum_current_point_count > RECORDED_SPATIAL_POINT_LIMIT:
raise RecordedThreatTimelineError(
"recorded timeline exact point delivery exceeds its declared bound"
)
self.body_frames = RecordedReplayBodyFrameResolver(
self.store,
profile=self.profile.body_frame,
self._maximum_source_points_per_frame = _read_source_point_bound(
self.repository_root,
source_pack_id=self.profile.source_pack_id,
source_pack_sha256=self.profile.source_pack_sha256,
)
self._store: RecordedGeometryStore | None = None
self._body_frames: RecordedReplayBodyFrameResolver | None = None
self.index = _index_frame_ledger(self.frames_path)
self._lock = RLock()
@property
def store(self) -> RecordedGeometryStore:
"""Load and deeply verify the large geometry archives on first use.
Timeline metadata, camera playback and the independent TGS artifact can
become visible without waiting for the source cloud archive. Any
endpoint that actually delivers source points still crosses the full
digest and shape validation in ``RecordedGeometryStore``.
"""
with self._lock:
if self._store is None:
store = RecordedGeometryStore.from_repository(self.repository_root)
if (
store.profile.source_pack_id != self.profile.source_pack_id
or store.profile.source_pack_sha256 != self.profile.source_pack_sha256
or store.profile.frame_count != _EXPECTED_FRAME_COUNT
or store.maximum_current_point_count
!= self._maximum_source_points_per_frame
):
raise RecordedThreatTimelineError(
"recorded timeline geometry identity changed"
)
if store.maximum_current_point_count > RECORDED_SPATIAL_POINT_LIMIT:
raise RecordedThreatTimelineError(
"recorded timeline exact point delivery exceeds its declared bound"
)
self._store = store
return self._store
@property
def body_frames(self) -> RecordedReplayBodyFrameResolver:
with self._lock:
if self._body_frames is None:
self._body_frames = RecordedReplayBodyFrameResolver(
self.store,
profile=self.profile.body_frame,
)
return self._body_frames
def metadata(self) -> dict[str, object]:
times = self.index.source_times_ns
intervals = [(current - previous) / 1_000_000_000 for previous, current in pairwise(times)]
@@ -120,7 +154,7 @@ class RecordedThreatTimeline:
"max_chunk_frames": RECORDED_SPATIAL_MAX_CHUNK_FRAMES,
"point_sample_limit": RECORDED_SPATIAL_POINT_LIMIT,
"point_delivery": "exact-current-increment",
"maximum_source_points_per_frame": self.store.maximum_current_point_count,
"maximum_source_points_per_frame": self._maximum_source_points_per_frame,
"local_surface_visualization": {
"derivation": "bounded-registered-increment-accumulation",
"window_seconds": RECORDED_LOCAL_SURFACE_WINDOW_SECONDS,
@@ -258,6 +292,82 @@ class RecordedThreatTimeline:
}
def _read_source_point_bound(
repository_root: Path,
*,
source_pack_id: str,
source_pack_sha256: str,
) -> int:
"""Read the small offsets member without inflating the 70 MiB source pack.
This is metadata only. The exact archive digest, every array shape and the
local-surface binding are still verified lazily by ``RecordedGeometryStore``
before any source point is delivered.
"""
base = (
repository_root / ".runtime/compute-experiments/e10/lidar-packs"
).resolve(strict=True)
pack_root = (base / source_pack_id).resolve(strict=True)
manifest_path = (pack_root / "manifest.json").resolve(strict=True)
pack_path = (pack_root / "lidar-pack.npz").resolve(strict=True)
if (
pack_root.parent != base
or pack_root.is_symlink()
or manifest_path.parent != pack_root
or manifest_path.is_symlink()
or pack_path.parent != pack_root
or pack_path.is_symlink()
or not pack_path.is_file()
):
raise RecordedThreatTimelineError("recorded timeline source pack path changed")
try:
manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
if not isinstance(manifest, dict):
raise RecordedThreatTimelineError(
"recorded timeline source pack manifest is invalid"
)
identity = manifest.get("identity")
artifact = manifest.get("artifact")
if not isinstance(identity, dict) or not isinstance(artifact, dict):
raise RecordedThreatTimelineError(
"recorded timeline source pack manifest is invalid"
)
point_count = identity.get("point_count")
if (
manifest.get("pack_id") != source_pack_id
or identity.get("frame_count") != _EXPECTED_FRAME_COUNT
or not isinstance(point_count, int)
or isinstance(point_count, bool)
or point_count < 0
or artifact.get("path") != "lidar-pack.npz"
or artifact.get("sha256") != source_pack_sha256
or artifact.get("byte_length") != pack_path.stat().st_size
):
raise RecordedThreatTimelineError(
"recorded timeline source pack identity changed"
)
with np.load(pack_path, allow_pickle=False) as archive:
offsets = np.asarray(archive["cloud_offsets"], dtype=np.int64)
except (KeyError, OSError, ValueError, json.JSONDecodeError) as error:
raise RecordedThreatTimelineError(
"recorded timeline source point offsets are unavailable"
) from error
if (
offsets.shape != (_EXPECTED_FRAME_COUNT + 1,)
or int(offsets[0]) != 0
or int(offsets[-1]) != point_count
or np.any(np.diff(offsets) < 0)
):
raise RecordedThreatTimelineError("recorded timeline source point offsets changed")
maximum = int(np.diff(offsets).max(initial=0))
if maximum > RECORDED_SPATIAL_POINT_LIMIT:
raise RecordedThreatTimelineError(
"recorded timeline exact point delivery exceeds its declared bound"
)
return maximum
def _index_frame_ledger(path: Path) -> RecordedThreatTimelineIndex:
offsets: list[int] = []
source_times: list[int] = []
+14
View File
@@ -133,6 +133,9 @@ from k1link.web.m48s_fixed_class_detector_lab_api import (
build_m48s_fixed_class_detector_lab_router,
)
from k1link.web.m48t_risk_quality_lab_api import build_m48t_risk_quality_lab_router
from k1link.web.m49_physical_safety_playback_api import (
build_m49_physical_safety_playback_router,
)
from k1link.web.m49_tgs_fail_closed_api import build_m49_tgs_fail_closed_router
from k1link.web.m49_tgs_full_shadow_api import build_m49_tgs_full_shadow_router
from k1link.web.map_api import (
@@ -1016,6 +1019,17 @@ app.include_router(
),
)
)
app.include_router(
build_m49_physical_safety_playback_router(
root_provider=lambda: (
REPOSITORY_ROOT
/ ".runtime"
/ "compute-experiments"
/ "m49"
/ "physical-safety-playback-results"
),
)
)
app.include_router(
build_m48s_fixed_class_detector_lab_router(
root_provider=lambda: (
@@ -0,0 +1,221 @@
"""Read-only local API for autonomous M49 physical-safety playback artifacts."""
from __future__ import annotations
import copy
import re
from collections.abc import Callable
from functools import lru_cache
from pathlib import Path
from typing import Any, Final
from fastapi import APIRouter, HTTPException, Query
from fastapi.responses import FileResponse
from k1link.laboratory.m49_physical_safety_playback import (
PREFIX,
M49PhysicalSafetyPlayback,
M49PhysicalSafetyPlaybackError,
read_m49_physical_safety_playback,
verify_m49_physical_safety_artifact,
)
RootProvider = Callable[[], Path | None]
RESULT_ID: Final = re.compile(rf"^{re.escape(PREFIX)}[a-f0-9]{{64}}$")
SOURCE_RESULT_ID: Final = re.compile(r"^m49-tgs-full-shadow-[a-f0-9]{64}$")
ENDPOINT_ROOT: Final = "/api/v1/laboratory/m49/physical-safety-playback"
def build_m49_physical_safety_playback_router(
*, root_provider: RootProvider = lambda: None
) -> APIRouter:
router = APIRouter(prefix=ENDPOINT_ROOT, tags=["laboratory"])
def sealed(result_id: str) -> M49PhysicalSafetyPlayback:
root = _configured_root(root_provider)
if root is None or RESULT_ID.fullmatch(result_id) is None:
raise HTTPException(status_code=404, detail="M49 physical-safety playback not found")
candidate = root / result_id
if candidate.is_symlink() or not candidate.is_dir():
raise HTTPException(status_code=404, detail="M49 physical-safety playback not found")
try:
resolved = candidate.resolve(strict=True)
if resolved.parent != root:
raise ValueError("result escaped configured root")
return _read_cached(str(resolved), _signature(resolved))
except (M49PhysicalSafetyPlaybackError, OSError, ValueError):
raise HTTPException(
status_code=404, detail="M49 physical-safety playback not found"
) from None
@router.get("/results")
def list_results(
limit: int = Query(default=10, ge=1, le=25),
source_result_id: str | None = Query(default=None),
) -> dict[str, object]:
if source_result_id is not None and SOURCE_RESULT_ID.fullmatch(source_result_id) is None:
raise HTTPException(status_code=422, detail="M49 source result identity is invalid")
root = _configured_root(root_provider)
if root is None:
return _catalog([], configured=False, invalid_total=0)
items: list[dict[str, object]] = []
invalid = 0
for candidate in sorted(root.iterdir()):
if candidate.is_symlink() or not candidate.is_dir() or not RESULT_ID.fullmatch(
candidate.name
):
continue
try:
summary = _summary(
_read_cached(str(candidate.resolve()), _signature(candidate))
)
if source_result_id is None or summary["source_result_id"] == source_result_id:
items.append(summary)
except (M49PhysicalSafetyPlaybackError, OSError, ValueError):
invalid += 1
items.sort(
key=lambda value: (str(value["created_at_utc"]), str(value["result_id"])),
reverse=True,
)
return _catalog(items[:limit], configured=True, invalid_total=invalid)
@router.get("/{result_id}/manifest")
def get_manifest(result_id: str) -> dict[str, object]:
return _project_manifest(sealed(result_id))
@router.get("/{result_id}/tracks/{track_id}")
def get_track(result_id: str, track_id: str) -> FileResponse:
result = sealed(result_id)
playback = _playback(result)
if track_id == "centers":
descriptor = _descriptor(playback.get("centers"), "centers")
elif track_id == "frames":
descriptor = _descriptor(playback.get("frames"), "frames")
else:
raise HTTPException(status_code=404, detail="M49 physical-safety track not found")
return _file_response(result, descriptor)
@router.get("/{result_id}/chunks/{chunk_index}")
def get_chunk(result_id: str, chunk_index: int) -> FileResponse:
result = sealed(result_id)
chunks = _playback(result).get("chunks")
if not isinstance(chunks, list) or chunk_index < 0 or chunk_index >= len(chunks):
raise HTTPException(status_code=404, detail="M49 physical-safety chunk not found")
descriptor = _descriptor(chunks[chunk_index], f"chunk {chunk_index}")
if descriptor.get("index") != chunk_index:
raise HTTPException(status_code=503, detail="M49 physical-safety chunk catalog changed")
return _file_response(result, descriptor)
return router
@lru_cache(maxsize=8)
def _read_cached(root: str, signature: tuple[int, ...]) -> M49PhysicalSafetyPlayback:
del signature
return read_m49_physical_safety_playback(Path(root))
def _file_response(
result: M49PhysicalSafetyPlayback,
descriptor: dict[str, Any],
) -> FileResponse:
try:
path = verify_m49_physical_safety_artifact(result, descriptor)
except (KeyError, OSError, TypeError, ValueError, M49PhysicalSafetyPlaybackError):
raise HTTPException(
status_code=503,
detail="M49 physical-safety playback artifact failed verification",
) from None
return FileResponse(
path,
media_type=str(descriptor.get("media_type") or "application/octet-stream"),
headers={
"Cache-Control": "private, max-age=31536000, immutable",
"Content-Encoding": "identity",
"ETag": f'"{descriptor["sha256"]}"',
"X-Content-Type-Options": "nosniff",
"X-Mission-Core-Worker-Dependency": "none",
},
)
def _playback(result: M49PhysicalSafetyPlayback) -> dict[str, Any]:
playback = result.manifest.get("playback")
if not isinstance(playback, dict):
raise HTTPException(status_code=503, detail="M49 physical-safety playback changed")
return playback
def _descriptor(value: object, label: str) -> dict[str, Any]:
if not isinstance(value, dict):
raise HTTPException(status_code=503, detail=f"M49 physical-safety {label} changed")
return value
def _project_manifest(result: M49PhysicalSafetyPlayback) -> dict[str, object]:
payload = copy.deepcopy(result.manifest)
playback = payload["playback"]
assert isinstance(playback, dict)
centers = playback["centers"]
frames = playback["frames"]
chunks = playback["chunks"]
assert isinstance(centers, dict) and isinstance(frames, dict) and isinstance(chunks, list)
centers["url"] = f"{ENDPOINT_ROOT}/{result.result_id}/tracks/centers"
frames["url"] = f"{ENDPOINT_ROOT}/{result.result_id}/tracks/frames"
for index, value in enumerate(chunks):
assert isinstance(value, dict)
value["url"] = f"{ENDPOINT_ROOT}/{result.result_id}/chunks/{index}"
payload["access"] = "read-only-sealed-local"
return payload
def _summary(result: M49PhysicalSafetyPlayback) -> dict[str, object]:
playback = _playback(result)
return {
"schema_version": "missioncore.m49-physical-safety-playback-summary/v1",
"result_id": result.result_id,
"created_at_utc": result.manifest.get("created_at_utc"),
"source_result_id": result.manifest["identity"]["source_result_id"],
"frame_count": playback.get("frame_count"),
"cell_count": playback.get("cell_count"),
"cell_size_m": playback.get("cell_size_m"),
"radius_m": playback.get("radius_m"),
"chunk_count": len(playback.get("chunks", [])),
"worker_runtime_dependency": False,
"navigation_or_safety_accepted": False,
}
def _catalog(
items: list[dict[str, object]], *, configured: bool, invalid_total: int
) -> dict[str, object]:
return {
"schema_version": "missioncore.m49-physical-safety-playback-catalog/v1",
"configured": configured,
"items": items,
"candidate_total": len(items) + invalid_total,
"invalid_total": invalid_total,
"worker_runtime_dependency": False,
"access": "read-only-sealed-local",
}
def _configured_root(provider: RootProvider) -> Path | None:
value = provider()
if value is None:
return None
raw = value.expanduser().absolute()
if raw.is_symlink() or not raw.is_dir():
return None
return raw.resolve(strict=True)
def _signature(root: Path) -> tuple[int, ...]:
path = root / "manifest.json"
if path.is_symlink() or not path.is_file():
raise ValueError("physical-safety manifest unavailable")
stat = path.stat()
return (stat.st_size, stat.st_mtime_ns)
__all__ = ["build_m49_physical_safety_playback_router"]
+104 -3
View File
@@ -22,7 +22,7 @@ from k1link.perception.threat_replay import (
THREAT_REPLAY_VISUAL_SCHEMA_V2,
ThreatReplayError,
ThreatReplayResult,
read_threat_replay_result,
read_threat_replay_result_metadata,
)
from k1link.perception.threat_timeline import (
RECORDED_SPATIAL_MAX_CHUNK_FRAMES,
@@ -34,6 +34,7 @@ from k1link.sessions import RecordedCameraFrame, SessionIntegrityError
M4_THREAT_CATALOG_SCHEMA: Final = "missioncore.m4-threat-replay-catalog/v1"
M4_THREAT_VIEW_SCHEMA: Final = "missioncore.m4-threat-replay-view/v1"
M4_THREAT_VISUAL_CATALOG_SCHEMA: Final = "missioncore.m4-threat-visual-catalog/v1"
M4_THREAT_PLAYBACK_CHUNK_FRAMES: Final = 24
_RESULT_ID = re.compile(rf"^{THREAT_REPLAY_RESULT_PREFIX}[a-f0-9]{{64}}$")
RootProvider = Callable[[], Path | None]
CameraFrameProvider = Callable[[str, int], RecordedCameraFrame]
@@ -212,13 +213,19 @@ def build_m4_threat_replay_router(
projected = timeline(result_id)
points = projected.store.playback_points_map()
offsets = projected.store.playback_point_offsets()
content_sha256 = hashlib.sha256(memoryview(points).cast("B")).hexdigest()
points_view = memoryview(points).cast("B")
content_sha256 = hashlib.sha256(points_view).hexdigest()
chunks = _playback_chunk_catalog(result_id, points_view, offsets)
return {
"schema_version": "missioncore.recorded-spatial-playback/v1",
"result_id": result_id,
"frame_count": len(offsets) - 1,
"point_count": int(points.shape[0]),
"point_offsets": list(offsets),
"chunk_frame_count": M4_THREAT_PLAYBACK_CHUNK_FRAMES,
"resident_chunk_count_max": 4,
"forward_prefetch_chunk_count": 1,
"chunks": chunks,
"track": {
"id": "points-map-f32",
"url": (
@@ -238,6 +245,42 @@ def build_m4_threat_replay_router(
"access": "read-only-sealed-binary-playback",
}
@router.get(
"/results/{result_id}/timeline/playback/chunks/{chunk_index}",
response_class=Response,
)
def get_timeline_playback_chunk(result_id: str, chunk_index: int) -> Response:
projected = timeline(result_id)
points = projected.store.playback_points_map()
offsets = projected.store.playback_point_offsets()
points_view = memoryview(points).cast("B")
descriptor = _playback_chunk_descriptor(
result_id,
points_view,
offsets,
chunk_index,
)
if descriptor is None:
raise HTTPException(status_code=404, detail="M4.6 playback chunk не найден")
point_start = descriptor["point_start"]
byte_length = descriptor["bytes"]
assert isinstance(point_start, int)
assert isinstance(byte_length, int)
byte_start = point_start * 3 * 4
byte_stop = byte_start + byte_length
return Response(
content=bytes(points_view[byte_start:byte_stop]),
media_type="application/octet-stream",
headers={
"Cache-Control": "private, max-age=31536000, immutable",
"Content-Encoding": "identity",
"Content-Length": str(byte_length),
"ETag": f'"{descriptor["sha256"]}"',
"X-Content-Type-Options": "nosniff",
"X-Uncompressed-Content-Length": str(byte_length),
},
)
@router.get(
"/results/{result_id}/timeline/playback/tracks/points-map-f32",
response_class=StreamingResponse,
@@ -276,13 +319,71 @@ def _binary_chunks(view: memoryview, chunk_size: int = 1024 * 1024) -> Iterator[
yield bytes(view[start : start + chunk_size])
def _playback_chunk_catalog(
result_id: str,
points_view: memoryview,
offsets: tuple[int, ...],
) -> list[dict[str, object]]:
frame_count = len(offsets) - 1
chunk_count = (
frame_count + M4_THREAT_PLAYBACK_CHUNK_FRAMES - 1
) // M4_THREAT_PLAYBACK_CHUNK_FRAMES
return [
descriptor
for chunk_index in range(chunk_count)
if (
descriptor := _playback_chunk_descriptor(
result_id,
points_view,
offsets,
chunk_index,
)
)
is not None
]
def _playback_chunk_descriptor(
result_id: str,
points_view: memoryview,
offsets: tuple[int, ...],
chunk_index: int,
) -> dict[str, object] | None:
frame_count = len(offsets) - 1
start = chunk_index * M4_THREAT_PLAYBACK_CHUNK_FRAMES
if chunk_index < 0 or start >= frame_count:
return None
count = min(M4_THREAT_PLAYBACK_CHUNK_FRAMES, frame_count - start)
point_start = offsets[start]
point_stop = offsets[start + count]
byte_start = point_start * 3 * 4
byte_stop = point_stop * 3 * 4
payload = points_view[byte_start:byte_stop]
return {
"index": chunk_index,
"start": start,
"count": count,
"point_start": point_start,
"point_count": point_stop - point_start,
"url": (
f"/api/v1/laboratory/m4-threat/results/{result_id}"
f"/timeline/playback/chunks/{chunk_index}"
),
"media_type": "application/octet-stream",
"dtype": "<f4",
"shape": [point_stop - point_start, 3],
"bytes": payload.nbytes,
"sha256": hashlib.sha256(payload).hexdigest(),
}
@lru_cache(maxsize=4)
def _read_threat_result_cached(
root_value: str,
signature: tuple[int, ...],
) -> ThreatReplayResult:
del signature
return read_threat_replay_result(Path(root_value))
return read_threat_replay_result_metadata(Path(root_value))
@lru_cache(maxsize=4)