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
+2 -1
View File
@@ -127,7 +127,7 @@ def test_product_registry_declares_every_advanced_evidence_source() -> None:
repository_root / "config" / "laboratories"
)
assert len(registry.definitions) == 39
assert len(registry.definitions) == 41
assert {item.work_id for item in registry.definitions} >= {
"e31-source-binding",
"e46j-raw-fisheye-realtime",
@@ -144,6 +144,7 @@ def test_product_registry_declares_every_advanced_evidence_source() -> None:
"m48-static-occupancy-qualification",
"m48s-fixed-class-detector",
"m48t-risk-quality-temporal",
"m49-tgs-fail-closed-evidence",
}
m48 = next(
item for item in registry.definitions if item.work_id == "m48-object-centric-quality"
+4
View File
@@ -101,6 +101,7 @@ def test_repository_registry_classifies_every_evidence_definition() -> None:
"e47-semantic-slam-shadow",
"m48s-fixed-class-detector",
"m48t-risk-quality-temporal",
"m49-tgs-fail-closed-evidence",
}
by_work_id = {row.work_id: row for row in execution.definitions}
assert by_work_id["m48-small-static-passage-regression"].evidence_contract == (
@@ -118,6 +119,8 @@ def test_repository_registry_classifies_every_evidence_definition() -> None:
assert by_work_id["m48s-fixed-class-detector"].isolation == "bounded-adapter"
assert by_work_id["m48t-risk-quality-temporal"].lifecycle == "experimental"
assert by_work_id["m48t-risk-quality-temporal"].isolation == "bounded-adapter"
assert by_work_id["m49-tgs-fail-closed-evidence"].lifecycle == "experimental"
assert by_work_id["m49-tgs-fail-closed-evidence"].isolation == "bounded-adapter"
assert all(
row.lifecycle == "canonical"
for row in execution.definitions
@@ -126,6 +129,7 @@ def test_repository_registry_classifies_every_evidence_definition() -> None:
"e47-semantic-slam-shadow",
"m48s-fixed-class-detector",
"m48t-risk-quality-temporal",
"m49-tgs-fail-closed-evidence",
}
)
assert len(execution.definitions) + len(execution.legacy_work_ids) == len(
@@ -80,7 +80,7 @@ def test_product_value_review_registry_covers_reviewed_laboratory_families() ->
root / "config" / "laboratory-value-review.json"
)
assert len(registry.entries) == 38
assert len(registry.entries) == 39
assert {entry.catalog_id for entry in registry.entries} >= {
"e28-local-surface",
"e46d-temporal-failure-audit",
@@ -91,4 +91,5 @@ def test_product_value_review_registry_covers_reviewed_laboratory_families() ->
"m48-static-occupancy-qualification",
"m48s-fixed-class-detector",
"m48t-risk-quality-temporal",
"m49-tgs-fail-closed-evidence",
}
+165
View File
@@ -0,0 +1,165 @@
from __future__ import annotations
import hashlib
import json
from pathlib import Path
import numpy as np
from fastapi import FastAPI
from fastapi.testclient import TestClient
from k1link.laboratory.m49_tgs_fail_closed import (
M49_TGS_ANCHORS,
read_m49_tgs_fail_closed,
seal_m49_tgs_fail_closed,
)
from k1link.web.m49_tgs_fail_closed_api import build_m49_tgs_fail_closed_router
REPOSITORY_ROOT = Path(__file__).resolve().parents[1]
def _sha(path: Path) -> str:
return hashlib.sha256(path.read_bytes()).hexdigest()
def _write_json(path: Path, value: object) -> None:
path.write_text(json.dumps(value, sort_keys=True), encoding="utf-8")
def _source(root: Path) -> Path:
root.mkdir()
centers = np.zeros((2244, 2), dtype=np.float32)
arrays: dict[str, np.ndarray] = {"costmap_cell_centers_xy_m": centers}
summaries: list[dict[str, object]] = []
for profile in ("current_increment", "causal_rolling_1s"):
arrays[f"{profile}_points_xyz_m"] = np.asarray(
[[float(index), 0.0, 0.1] for index in range(10)], dtype=np.float32
)
arrays[f"{profile}_point_states"] = np.asarray([1, 2] * 5, dtype=np.uint8)
arrays[f"{profile}_point_offsets"] = np.arange(11, dtype=np.int64)
arrays[f"{profile}_costmap_states"] = np.zeros((10, 2244), dtype=np.uint8)
arrays[f"{profile}_costmap_ground_point_counts"] = np.zeros((10, 2244), dtype=np.int32)
arrays[f"{profile}_costmap_nonground_point_counts"] = np.zeros((10, 2244), dtype=np.int32)
arrays[f"{profile}_costmap_rejected_point_counts"] = np.zeros((10, 2244), dtype=np.int32)
arrays[f"{profile}_costmap_z_bounds_m"] = np.full((10, 2244, 2), np.nan, dtype=np.float32)
for slot, anchor in enumerate(M49_TGS_ANCHORS):
summaries.append(
{
"profile_id": profile,
"slot": slot,
"anchor_frame_index": anchor,
"point_count": 1,
"ground_point_count": 1 if slot % 2 == 0 else 0,
"nonground_point_count": 0 if slot % 2 == 0 else 1,
"rejected_point_count": 0,
"ground_cell_count": 0,
"nonground_cell_count": 0,
"rejected_cell_count": 0,
"unobserved_cell_count": 2244,
"all_points_accounted": True,
}
)
np.savez_compressed(root / "evidence.npz", **arrays)
records = [
{
"profile_id": profile,
"slot": slot,
"anchor_frame_index": anchor,
}
for profile in ("current_increment", "causal_rolling_1s")
for slot, anchor in enumerate(M49_TGS_ANCHORS)
]
_write_json(
root / "input-manifest.json",
{
"schema_version": "missioncore.m49-tgs-fail-closed-input/v1",
"coordinate_frame": "map-gravity-local",
"records": records,
},
)
_write_json(
root / "worker-summary.json",
{
"schema_version": "missioncore.m49-tgs-worker-summary/v1",
"code_revision": "a" * 40,
"wall_seconds": 1.5,
"free_memory_gib_before": 42.0,
"canonical_triton_id": "b" * 64,
"canonical_triton_health": "healthy",
"all_eligible_points_accounted": True,
"aos_used": False,
},
)
timing = ["profile\tslot\twall_seconds\tmax_rss_kib"]
timing.extend(
f"{profile}\t{slot}\t0.02\t7000"
for profile in ("current_increment", "causal_rolling_1s")
for slot in range(10)
)
(root / "tgs-timing.tsv").write_text("\n".join(timing) + "\n", encoding="utf-8")
_write_json(
root / "result.json",
{
"schema_version": "missioncore.m49-tgs-fail-closed-evidence-result/v1",
"status": "passed",
"config_sha256": "c" * 64,
"source_pack_sha256": "d" * 64,
"input_manifest_sha256": _sha(root / "input-manifest.json"),
"evidence": {
"path": "evidence.npz",
"bytes": (root / "evidence.npz").stat().st_size,
"sha256": _sha(root / "evidence.npz"),
},
"costmap": {
"coordinate_frame": "map-gravity-local",
"cell_size_m": 0.45,
"radius_m": 12.0,
"cell_count": 2244,
},
"summary": {
"aos_used": False,
"all_eligible_points_accounted": True,
"primary_profile": "causal_rolling_1s",
},
"anchors": summaries,
},
)
return root
def test_m49_tgs_seal_and_api_are_immutable_and_fail_closed(tmp_path: Path) -> None:
source = _source(tmp_path / "source")
destination = tmp_path / "results"
linked = "m4-threat-replay-" + "e" * 64
sealed = seal_m49_tgs_fail_closed(
source_root=source,
destination_root=destination,
profile_path=(
REPOSITORY_ROOT / "config" / "perception" / "m49-tgs-fail-closed-evidence-v1.json"
),
linked_visual_result_id=linked,
created_at_utc="2026-08-26T17:30:00Z",
)
assert read_m49_tgs_fail_closed(sealed.root).result_id == sealed.result_id
app = FastAPI()
app.include_router(build_m49_tgs_fail_closed_router(root_provider=lambda: destination))
client = TestClient(app)
catalog = client.get("/api/v1/laboratory/m49/tgs-fail-closed/results")
assert catalog.status_code == 200
assert catalog.json()["items"][0]["result_id"] == sealed.result_id
anchors = client.get(f"/api/v1/laboratory/m49/tgs-fail-closed/{sealed.result_id}/anchors")
assert anchors.status_code == 200
assert anchors.json()["anchor_count"] == 10
spatial = client.get(
f"/api/v1/laboratory/m49/tgs-fail-closed/{sealed.result_id}/anchors/171/spatial"
)
assert spatial.status_code == 200
assert spatial.json()["point_states"] == [1]
assert spatial.json()["costmap"]["states"] == [0] * 2244
assert spatial.json()["authority"]["navigation_or_safety_accepted"] is False
(sealed.root / "worker-summary.json").write_text("{}", encoding="utf-8")
assert (
client.get(f"/api/v1/laboratory/m49/tgs-fail-closed/{sealed.result_id}").status_code == 404
)