feat(lab): publish fail-closed TGS evidence

This commit is contained in:
DCCONSTRUCTIONS
2026-08-26 21:32:35 +03:00
parent 67d5d6fa05
commit 6544d9e918
27 changed files with 2167 additions and 73 deletions
@@ -0,0 +1,440 @@
"""Seal and verify bounded gravity-aligned TRAVEL TGS evidence."""
from __future__ import annotations
import hashlib
import json
import os
import shutil
import tempfile
from dataclasses import dataclass
from datetime import UTC, datetime
from pathlib import Path
from typing import Any, Final
M49_TGS_RESULT_SCHEMA: Final = "missioncore.m49-tgs-fail-closed-result/v1"
M49_TGS_REPORT_SCHEMA: Final = "missioncore.m49-tgs-fail-closed-report/v1"
M49_TGS_WORKER_RESULT_SCHEMA: Final = "missioncore.m49-tgs-fail-closed-evidence-result/v1"
M49_TGS_PREFIX: Final = "m49-tgs-fail-closed-"
M49_TGS_PROFILE_ID: Final = "m49-ravnoves00-tgs-fail-closed-evidence/v1"
M49_TGS_ANCHORS: Final = (171, 306, 368, 402, 450, 509, 525, 744, 1122, 1856)
M49_TGS_PROFILES: Final = ("current_increment", "causal_rolling_1s")
_MAX_JSON_BYTES: Final = 1024 * 1024
_HASH_CHUNK_BYTES: Final = 1024 * 1024
class M49TgsFailClosedError(RuntimeError):
"""The TGS evidence pack is unavailable or failed its immutable contract."""
@dataclass(frozen=True, slots=True)
class M49TgsFailClosedResult:
result_id: str
root: Path
manifest: dict[str, Any]
report: dict[str, Any]
@property
def evidence_path(self) -> Path:
return self.root / "evidence.npz"
def seal_m49_tgs_fail_closed(
*,
source_root: Path,
destination_root: Path,
profile_path: Path,
linked_visual_result_id: str,
created_at_utc: str | None = None,
) -> M49TgsFailClosedResult:
source = _real_directory(source_root, "M49 Worker evidence")
destination = destination_root.expanduser().absolute()
destination.mkdir(parents=True, exist_ok=True)
if destination.is_symlink():
raise M49TgsFailClosedError("M49 destination must not be a symlink")
profile = _json_file(profile_path, "M49 profile")
worker_result = _json_file(source / "result.json", "M49 Worker result")
worker_summary = _json_file(source / "worker-summary.json", "M49 Worker summary")
input_manifest = _json_file(source / "input-manifest.json", "M49 input manifest")
timing = _timing_metrics(source / "tgs-timing.tsv")
_validate_source(profile, worker_result, worker_summary, input_manifest, source)
if (
not linked_visual_result_id.startswith("m4-threat-replay-")
or len(linked_visual_result_id) != len("m4-threat-replay-") + 64
):
raise M49TgsFailClosedError("M49 linked visual result is invalid")
evidence_sha = _file_sha256(source / "evidence.npz")
identity = {
"schema_version": M49_TGS_RESULT_SCHEMA,
"source": {
"source_id": "RAVNOVES00",
"source_session_id": "20260720T065719Z_viewer_live",
"source_pack_sha256": worker_result["source_pack_sha256"],
"input_manifest_sha256": worker_result["input_manifest_sha256"],
"linked_visual_result_id": linked_visual_result_id,
"anchor_frame_indices": list(M49_TGS_ANCHORS),
},
"configuration": {
"profile_id": M49_TGS_PROFILE_ID,
"config_sha256": worker_result["config_sha256"],
"coordinate_frame": "map-gravity-local",
"primary_profile": "causal_rolling_1s",
"cell_size_m": worker_result["costmap"]["cell_size_m"],
"radius_m": worker_result["costmap"]["radius_m"],
},
"method": {
"execution_class": "deterministic",
"pipeline_id": "travel-tgs-gravity-aligned-fail-closed/v1",
"travel_revision": profile["source"]["travel_revision"],
"aos_used": False,
"missing_support_means_free": False,
"eligible_point_accounting": "exact-multiset-complement",
},
"evidence": {
"sha256": evidence_sha,
"byte_length": (source / "evidence.npz").stat().st_size,
"state_codes": profile["state_codes"],
},
"authority": {
"commands_enabled": False,
"navigation_or_safety_accepted": False,
"visual_quality_accepted": False,
},
}
identity_sha256 = _canonical_sha256(identity)
result_id = f"{M49_TGS_PREFIX}{identity_sha256}"
target = destination / result_id
if target.exists():
return read_m49_tgs_fail_closed(target)
created = created_at_utc or datetime.now(tz=UTC).isoformat().replace("+00:00", "Z")
anchors = worker_result["anchors"]
primary = [row for row in anchors if row["profile_id"] == "causal_rolling_1s"]
report = {
"schema_version": M49_TGS_REPORT_SCHEMA,
"result_id": result_id,
"created_at_utc": created,
"source": identity["source"],
"configuration": {
**identity["configuration"],
"state_priority": profile["costmap"]["state_priority"],
"tgs": profile["tgs"],
},
"method": {
**identity["method"],
"components": [
{
"kind": "algorithm",
"name": "TRAVEL GroundSeg",
"version": profile["source"]["travel_revision"],
"role": "gravity-aligned ground/nonground separation",
},
{
"kind": "algorithm",
"name": "fail-closed complement adapter",
"version": "v1",
"role": "retain rejected points and explicit unobserved cells",
},
{
"kind": "runtime",
"name": "Worker 006 CPU qualification",
"version": worker_summary["code_revision"],
"role": "20 bounded TGS invocations without GPU",
},
],
},
"execution": {
"worker": "Worker 006",
"device": "cpu",
"gpu_used": False,
"wrapper_elapsed_seconds": worker_summary["wall_seconds"],
"canonical_triton_id": worker_summary["canonical_triton_id"],
"canonical_triton_health": worker_summary["canonical_triton_health"],
"free_memory_gib_before": worker_summary["free_memory_gib_before"],
},
"metrics": {
"anchor_count": len(M49_TGS_ANCHORS),
"anchor_profile_count": len(anchors),
"all_eligible_points_accounted": True,
"primary_profile": "causal_rolling_1s",
"primary": primary,
"costmap_cell_count": worker_result["costmap"]["cell_count"],
"process_wall_current_p50_ms": timing["current_increment"]["p50_ms"],
"process_wall_current_max_ms": timing["current_increment"]["max_ms"],
"process_wall_rolling_p50_ms": timing["causal_rolling_1s"]["p50_ms"],
"process_wall_rolling_max_ms": timing["causal_rolling_1s"]["max_ms"],
"process_max_rss_kib": timing["max_rss_kib"],
},
"acceptance": {
"representation_complete": True,
"all_points_accounted": True,
"aos_absent": True,
"gpu_absent": True,
"visual_quality_accepted": False,
"traversability_accepted": False,
},
"decision": {
"state": "visual-review-required",
"candidate_retained": True,
"next_action": (
"Review exact gravity-aligned points and fail-closed costmap "
"on the ten immutable anchors."
),
},
"limitations": [
"The ten anchors are bounded diagnostic evidence, not a full 4,489-frame replay.",
"No independent terrain or traversability truth is available.",
"No vehicle envelope exists, so occupied cells do not grant or deny physical passage.",
"Visual quality, realtime integration, navigation and actuation remain unaccepted.",
],
"authority": {
"mode": "replay-simulated",
"commands_enabled": False,
"navigation_or_safety_accepted": False,
"visual_quality_accepted": False,
},
"visual_review": {
"instrument": "m4-canonical-reference-graph",
"linked_visual_result_id": linked_visual_result_id,
"anchors": list(M49_TGS_ANCHORS),
"profiles": list(M49_TGS_PROFILES),
"default_profile": "causal_rolling_1s",
"point_states": profile["state_codes"],
},
}
with tempfile.TemporaryDirectory(prefix="mission-core-m49-tgs-", dir=destination) as raw:
staging = Path(raw) / result_id
staging.mkdir()
for name in (
"evidence.npz",
"worker-summary.json",
"input-manifest.json",
"tgs-timing.tsv",
):
shutil.copyfile(source / name, staging / name)
_write_json(staging / "report.json", report)
artifacts = [
_artifact(staging / "report.json", "report", M49_TGS_REPORT_SCHEMA, "application/json"),
_artifact(
staging / "evidence.npz", "visual-spatial-evidence", None, "application/x-npz"
),
_artifact(staging / "worker-summary.json", "runtime-summary", None, "application/json"),
_artifact(staging / "input-manifest.json", "source-manifest", None, "application/json"),
_artifact(
staging / "tgs-timing.tsv", "runtime-timing", None, "text/tab-separated-values"
),
]
manifest = {
"schema_version": M49_TGS_RESULT_SCHEMA,
"result_id": result_id,
"created_at_utc": created,
"identity_sha256": identity_sha256,
"identity": identity,
"artifacts": artifacts,
"authority": report["authority"],
"ground_truth": False,
}
_write_json(staging / "manifest.json", manifest)
os.replace(staging, target)
return read_m49_tgs_fail_closed(target)
def read_m49_tgs_fail_closed(root: Path) -> M49TgsFailClosedResult:
candidate = _real_directory(root, "M49 result")
if not candidate.name.startswith(M49_TGS_PREFIX):
raise M49TgsFailClosedError("M49 result identity is invalid")
manifest = _json_file(candidate / "manifest.json", "M49 manifest")
report = _json_file(candidate / "report.json", "M49 report")
if (
manifest.get("schema_version") != M49_TGS_RESULT_SCHEMA
or manifest.get("result_id") != candidate.name
or report.get("schema_version") != M49_TGS_REPORT_SCHEMA
or report.get("result_id") != candidate.name
):
raise M49TgsFailClosedError("M49 result contract changed")
identity = manifest.get("identity")
identity_sha = manifest.get("identity_sha256")
if (
not isinstance(identity, dict)
or not isinstance(identity_sha, str)
or _canonical_sha256(identity) != identity_sha
or candidate.name != f"{M49_TGS_PREFIX}{identity_sha}"
):
raise M49TgsFailClosedError("M49 identity proof changed")
artifacts = manifest.get("artifacts")
if not isinstance(artifacts, list) or len(artifacts) != 5:
raise M49TgsFailClosedError("M49 artifact manifest changed")
for item in artifacts:
if not isinstance(item, dict):
raise M49TgsFailClosedError("M49 artifact descriptor changed")
path = candidate / str(item.get("path", ""))
if (
path.is_symlink()
or not path.is_file()
or path.parent != candidate
or path.stat().st_size != item.get("byte_length")
or _file_sha256(path) != item.get("sha256")
):
raise M49TgsFailClosedError("M49 artifact proof changed")
return M49TgsFailClosedResult(candidate.name, candidate, manifest, report)
def _validate_source(
profile: dict[str, Any],
worker_result: dict[str, Any],
worker_summary: dict[str, Any],
input_manifest: dict[str, Any],
source: Path,
) -> None:
if (
profile.get("schema_version") != "missioncore.m49-tgs-fail-closed-evidence-profile/v1"
or profile.get("profile_id") != M49_TGS_PROFILE_ID
or tuple(profile.get("anchors", ())) != M49_TGS_ANCHORS
or profile.get("invariants", {}).get("aos_allowed") is not False
or profile.get("invariants", {}).get("missing_support_means_free") is not False
):
raise M49TgsFailClosedError("M49 profile changed")
if (
worker_result.get("schema_version") != M49_TGS_WORKER_RESULT_SCHEMA
or worker_result.get("status") != "passed"
or worker_result.get("summary", {}).get("aos_used") is not False
or worker_result.get("summary", {}).get("all_eligible_points_accounted") is not True
or worker_result.get("summary", {}).get("primary_profile") != "causal_rolling_1s"
or len(worker_result.get("anchors", ())) != 20
):
raise M49TgsFailClosedError("M49 Worker result changed")
if (
input_manifest.get("schema_version") != "missioncore.m49-tgs-fail-closed-input/v1"
or input_manifest.get("coordinate_frame") != "map-gravity-local"
or len(input_manifest.get("records", ())) != 20
):
raise M49TgsFailClosedError("M49 input manifest changed")
if (
worker_summary.get("gpu_requested") is not False
and worker_summary.get("gpu_requested") is not None
):
raise M49TgsFailClosedError("M49 Worker GPU contract changed")
if (
worker_summary.get("aos_used") is not False
or worker_summary.get("all_eligible_points_accounted") is not True
or worker_summary.get("canonical_triton_health") != "healthy"
):
raise M49TgsFailClosedError("M49 Worker cleanup changed")
evidence = worker_result.get("evidence", {})
if (
evidence.get("path") != "evidence.npz"
or evidence.get("bytes") != (source / "evidence.npz").stat().st_size
or evidence.get("sha256") != _file_sha256(source / "evidence.npz")
or worker_result.get("input_manifest_sha256")
!= _file_sha256(source / "input-manifest.json")
):
raise M49TgsFailClosedError("M49 evidence proof changed")
def _artifact(
path: Path,
role: str,
schema_version: str | None,
media_type: str,
) -> dict[str, object]:
result: dict[str, object] = {
"role": role,
"path": path.name,
"byte_length": path.stat().st_size,
"sha256": _file_sha256(path),
"media_type": media_type,
}
if schema_version is not None:
result["schema_version"] = schema_version
return result
def _timing_metrics(path: Path) -> dict[str, Any]:
if path.is_symlink() or not path.is_file():
raise M49TgsFailClosedError("M49 timing evidence is unavailable")
profiles: dict[str, list[float]] = {name: [] for name in M49_TGS_PROFILES}
maximum_rss = 0
lines = path.read_text(encoding="utf-8-sig").splitlines()
if not lines or lines[0] != "profile\tslot\twall_seconds\tmax_rss_kib":
raise M49TgsFailClosedError("M49 timing evidence changed")
for line in lines[1:]:
fields = line.split("\t")
if len(fields) != 4 or fields[0] not in profiles:
raise M49TgsFailClosedError("M49 timing row changed")
profiles[fields[0]].append(float(fields[2]))
maximum_rss = max(maximum_rss, int(fields[3]))
if any(len(values) != len(M49_TGS_ANCHORS) for values in profiles.values()):
raise M49TgsFailClosedError("M49 timing coverage changed")
result: dict[str, Any] = {"max_rss_kib": maximum_rss}
for name, values in profiles.items():
ordered = sorted(values)
result[name] = {
"p50_ms": ordered[len(ordered) // 2] * 1000,
"max_ms": max(ordered) * 1000,
}
return result
def _real_directory(path: Path, label: str) -> Path:
candidate = path.expanduser().absolute()
if candidate.is_symlink():
raise M49TgsFailClosedError(f"{label} must not be a symlink")
try:
resolved = candidate.resolve(strict=True)
except OSError as exc:
raise M49TgsFailClosedError(f"{label} is unavailable") from exc
if not resolved.is_dir():
raise M49TgsFailClosedError(f"{label} is unavailable")
return resolved
def _json_file(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 M49TgsFailClosedError(f"{label} is unavailable")
try:
value = json.loads(path.read_text(encoding="utf-8-sig"))
except (json.JSONDecodeError, OSError) as exc:
raise M49TgsFailClosedError(f"{label} is invalid") from exc
if not isinstance(value, dict):
raise M49TgsFailClosedError(f"{label} is invalid")
return value
def _write_json(path: Path, value: object) -> None:
path.write_bytes(_canonical_json(value) + b"\n")
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(_HASH_CHUNK_BYTES), b""):
digest.update(chunk)
return digest.hexdigest()
__all__ = [
"M49_TGS_ANCHORS",
"M49_TGS_PREFIX",
"M49_TGS_REPORT_SCHEMA",
"M49_TGS_RESULT_SCHEMA",
"M49TgsFailClosedError",
"M49TgsFailClosedResult",
"read_m49_tgs_fail_closed",
"seal_m49_tgs_fail_closed",
]