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",
]
+12
View File
@@ -133,6 +133,7 @@ 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_tgs_fail_closed_api import build_m49_tgs_fail_closed_router
from k1link.web.map_api import (
MapGatewayConfiguration,
MapGatewayProxy,
@@ -992,6 +993,17 @@ app.include_router(
),
)
)
app.include_router(
build_m49_tgs_fail_closed_router(
root_provider=lambda: (
REPOSITORY_ROOT
/ ".runtime"
/ "compute-experiments"
/ "m49"
/ "tgs-fail-closed-results"
),
)
)
app.include_router(
build_m48s_fixed_class_detector_lab_router(
root_provider=lambda: (
+284
View File
@@ -0,0 +1,284 @@
"""Read-only API for sealed gravity-aligned M49 TGS evidence."""
from __future__ import annotations
import copy
import json
import math
import re
from collections.abc import Callable
from functools import lru_cache
from pathlib import Path
from typing import Final
import numpy as np
from fastapi import APIRouter, HTTPException, Query, Response
from k1link.laboratory.m49_tgs_fail_closed import (
M49_TGS_ANCHORS,
M49_TGS_PREFIX,
M49TgsFailClosedError,
M49TgsFailClosedResult,
read_m49_tgs_fail_closed,
)
RootProvider = Callable[[], Path | None]
RESULT_ID: Final = re.compile(rf"^{re.escape(M49_TGS_PREFIX)}[a-f0-9]{{64}}$")
RESULT_VIEW_SCHEMA: Final = "missioncore.m49-tgs-fail-closed-view/v1"
RESULT_CATALOG_SCHEMA: Final = "missioncore.m49-tgs-fail-closed-catalog/v1"
ANCHOR_CATALOG_SCHEMA: Final = "missioncore.m49-tgs-anchor-catalog/v1"
ANCHOR_SPATIAL_SCHEMA: Final = "missioncore.m49-tgs-anchor-spatial/v1"
ENDPOINT_ROOT: Final = "/api/v1/laboratory/m49/tgs-fail-closed"
PROFILES: Final = ("current_increment", "causal_rolling_1s")
def build_m49_tgs_fail_closed_router(*, root_provider: RootProvider = lambda: None) -> APIRouter:
router = APIRouter(prefix=ENDPOINT_ROOT, tags=["laboratory"])
def result(result_id: str) -> M49TgsFailClosedResult:
candidate = _resolve_candidate(root_provider, result_id)
try:
return _read_result_cached(str(candidate), _signature(candidate))
except (M49TgsFailClosedError, OSError, ValueError):
raise HTTPException(status_code=404, detail="M49 TGS result not found") from None
@router.get("/results")
def list_results(limit: int = Query(default=1, ge=1, le=10)) -> dict[str, object]:
root = _configured_root(root_provider)
if root is None:
return _empty_catalog(configured=False)
items: list[dict[str, object]] = []
invalid_total = 0
for candidate in sorted(root.iterdir()):
if not candidate.is_dir() or RESULT_ID.fullmatch(candidate.name) is None:
continue
try:
sealed = _read_result_cached(str(candidate.resolve()), _signature(candidate))
items.append(_project_result(sealed))
except (M49TgsFailClosedError, OSError, ValueError):
invalid_total += 1
items.sort(
key=lambda item: (str(item["created_at_utc"]), str(item["result_id"])),
reverse=True,
)
return {
"schema_version": RESULT_CATALOG_SCHEMA,
"configured": True,
"items": items[:limit],
"candidate_total": len(items) + invalid_total,
"invalid_total": invalid_total,
"access": "read-only",
}
@router.get("/{result_id}")
def get_result(result_id: str) -> dict[str, object]:
return _project_result(result(result_id))
@router.get("/{result_id}/anchors")
def get_anchors(result_id: str) -> dict[str, object]:
sealed = result(result_id)
return {
"schema_version": ANCHOR_CATALOG_SCHEMA,
"result_id": result_id,
"linked_visual_result_id": sealed.report["visual_review"]["linked_visual_result_id"],
"anchors": copy.deepcopy(sealed.report["metrics"]["primary"]),
"anchor_count": len(M49_TGS_ANCHORS),
"profiles": list(PROFILES),
"default_profile": "causal_rolling_1s",
"access": "read-only",
}
@router.get("/{result_id}/anchors/{anchor_frame_index}/spatial")
def get_anchor_spatial(
result_id: str,
anchor_frame_index: int,
profile: str = Query(default="causal_rolling_1s"),
) -> Response:
if profile not in PROFILES or anchor_frame_index not in M49_TGS_ANCHORS:
raise HTTPException(status_code=404, detail="M49 TGS anchor not found")
sealed = result(result_id)
try:
content = _anchor_json_cached(
str(sealed.evidence_path),
result_id,
anchor_frame_index,
profile,
_evidence_signature(sealed.evidence_path),
)
except (KeyError, OSError, ValueError):
raise HTTPException(
status_code=503, detail="M49 TGS spatial evidence failed verification"
) from None
return Response(
content=content,
media_type="application/json",
headers={
"Cache-Control": "private, max-age=31536000, immutable",
"X-Content-Type-Options": "nosniff",
},
)
return router
@lru_cache(maxsize=4)
def _read_result_cached(result_root: str, signature: tuple[int, ...]) -> M49TgsFailClosedResult:
del signature
return read_m49_tgs_fail_closed(Path(result_root))
@lru_cache(maxsize=24)
def _anchor_json_cached(
evidence_path: str,
result_id: str,
anchor_frame_index: int,
profile: str,
signature: tuple[int, int],
) -> bytes:
del signature
slot = M49_TGS_ANCHORS.index(anchor_frame_index)
with np.load(evidence_path, allow_pickle=False) as evidence:
offsets = evidence[f"{profile}_point_offsets"]
start = int(offsets[slot])
end = int(offsets[slot + 1])
points = evidence[f"{profile}_points_xyz_m"][start:end]
point_states = evidence[f"{profile}_point_states"][start:end]
centers = evidence["costmap_cell_centers_xy_m"]
cell_states = evidence[f"{profile}_costmap_states"][slot]
z_bounds = evidence[f"{profile}_costmap_z_bounds_m"][slot]
if (
points.shape[1:] != (3,)
or point_states.shape != (points.shape[0],)
or centers.shape != (2244, 2)
or cell_states.shape != (2244,)
or z_bounds.shape != (2244, 2)
or not np.isfinite(points).all()
or not np.isfinite(centers).all()
or not np.isin(point_states, np.asarray([1, 2, 3], dtype=np.uint8)).all()
or not np.isin(cell_states, np.asarray([0, 1, 2, 3], dtype=np.uint8)).all()
):
raise ValueError("M49 TGS spatial shape changed")
payload = {
"schema_version": ANCHOR_SPATIAL_SCHEMA,
"result_id": result_id,
"anchor_frame_index": anchor_frame_index,
"source_sequence": anchor_frame_index,
"profile": profile,
"coordinate_frame": "map-gravity-local",
"points_xyz_m": points.astype(float).tolist(),
"point_states": point_states.astype(int).tolist(),
"costmap": {
"cell_size_m": 0.45,
"radius_m": 12.0,
"centers_xy_m": centers.astype(float).tolist(),
"states": cell_states.astype(int).tolist(),
"z_bounds_m": [
[
float(row[0]) if math.isfinite(float(row[0])) else None,
float(row[1]) if math.isfinite(float(row[1])) else None,
]
for row in z_bounds
],
},
"state_codes": {
"UNOBSERVED": 0,
"GROUND_SUPPORT": 1,
"NONGROUND_OCCUPIED": 2,
"UNKNOWN_REJECTED": 3,
},
"all_points_accounted": True,
"aos_used": False,
"authority": {
"visual_quality_accepted": False,
"navigation_or_safety_accepted": False,
},
"access": "read-only",
}
return json.dumps(
payload,
ensure_ascii=False,
sort_keys=True,
separators=(",", ":"),
allow_nan=False,
).encode("utf-8")
def _project_result(result: M49TgsFailClosedResult) -> dict[str, object]:
report = result.report
return {
"schema_version": RESULT_VIEW_SCHEMA,
"result_id": result.result_id,
"created_at_utc": result.manifest["created_at_utc"],
"source": copy.deepcopy(report["source"]),
"configuration": copy.deepcopy(report["configuration"]),
"method": copy.deepcopy(report["method"]),
"execution": copy.deepcopy(report["execution"]),
"metrics": copy.deepcopy(report["metrics"]),
"acceptance": copy.deepcopy(report["acceptance"]),
"decision": copy.deepcopy(report["decision"]),
"limitations": copy.deepcopy(report["limitations"]),
"authority": copy.deepcopy(report["authority"]),
"visual_review": copy.deepcopy(report["visual_review"]),
"ground_truth": False,
"access": "read-only",
}
def _resolve_candidate(provider: RootProvider, result_id: str) -> Path:
if RESULT_ID.fullmatch(result_id) is None:
raise HTTPException(status_code=404, detail="M49 TGS result not found")
root = _configured_root(provider)
if root is None:
raise HTTPException(status_code=404, detail="M49 TGS result not found")
candidate = root / result_id
if candidate.is_symlink() or not candidate.is_dir():
raise HTTPException(status_code=404, detail="M49 TGS result not found")
resolved = candidate.resolve(strict=True)
if resolved.parent != root:
raise HTTPException(status_code=404, detail="M49 TGS result not found")
return resolved
def _configured_root(provider: RootProvider) -> Path | None:
value = provider()
if value is None or value.is_symlink() or not value.is_dir():
return None
return value.resolve(strict=True)
def _signature(candidate: Path) -> tuple[int, ...]:
result: list[int] = []
for name in (
"manifest.json",
"report.json",
"evidence.npz",
"worker-summary.json",
"input-manifest.json",
"tgs-timing.tsv",
):
path = candidate / name
if path.is_symlink() or not path.is_file():
raise ValueError("M49 TGS artifact unavailable")
stat = path.stat()
result.extend((stat.st_size, stat.st_mtime_ns))
return tuple(result)
def _evidence_signature(path: Path) -> tuple[int, int]:
stat = path.stat()
return stat.st_size, stat.st_mtime_ns
def _empty_catalog(*, configured: bool) -> dict[str, object]:
return {
"schema_version": RESULT_CATALOG_SCHEMA,
"configured": configured,
"items": [],
"candidate_total": 0,
"invalid_total": 0,
"access": "read-only",
}
__all__ = ["build_m49_tgs_fail_closed_router"]