diff --git a/config/perception/lab-v1-vegetation-candidate-manifest-v1.json b/config/perception/lab-v1-vegetation-candidate-manifest-v1.json new file mode 100644 index 0000000..0b000db --- /dev/null +++ b/config/perception/lab-v1-vegetation-candidate-manifest-v1.json @@ -0,0 +1,174 @@ +{ + "schema_version": "missioncore.vegetation-candidate-manifest/v1", + "lab_id": "LAB-V1", + "ops_issue_id": "88aff22a-43aa-48fb-b7eb-ac424d987d37", + "frozen_utc": "2026-08-27T18:39:00Z", + "worker": { + "worker_id": "worker-006", + "candidate_root": "D:\\NDC_MISSIONCORE\\datasets\\vegetation-v1\\observed-2026-08-27", + "canonical_runtime_mutation_allowed": false + }, + "upstream_sources": [ + { + "source_id": "wildscenes", + "repository": "https://github.com/csiro-robotics/WildScenes.git", + "revision": "9eb4e10b4483a634159e2b371be0437e465fe218", + "worker_relative_path": "sources/wildscenes" + }, + { + "source_id": "rellis-3d", + "repository": "https://github.com/unmannedlab/RELLIS-3D.git", + "revision": "c17a118fcaed1559f03cc32cc3a91dedc557f8b8", + "worker_relative_path": "sources/rellis-3d" + }, + { + "source_id": "orfd-offnet", + "repository": "https://github.com/chaytonmin/Off-Road-Freespace-Detection.git", + "revision": "50e63d24836198e8fb5af707e521f414104b4876", + "worker_relative_path": "sources/orfd" + } + ], + "candidate_assets": [ + { + "candidate_id": "goose-ppliteseg-category-512", + "modality": "camera-2d", + "family": "ppliteseg", + "output_contract": "goose-category-12", + "input_resolution": [512, 512], + "relative_path": "models/goose/ppliteseg_category_512.pth", + "size_bytes": 98180357, + "sha256": "87bf55a1ae994a4bdf3a4d30c8f0dec2916994b37d433f0b5b694d63157ee0ab", + "asset_status": "accepted", + "runner_status": "super-gradients-compatibility-probe-required" + }, + { + "candidate_id": "goose-ppliteseg-class-512", + "modality": "camera-2d", + "family": "ppliteseg", + "output_contract": "goose-class-64", + "input_resolution": [512, 512], + "relative_path": "models/goose/ppliteseg_class_512.pth", + "size_bytes": 98208249, + "sha256": "6dd412c0c99115e359896c4cab43a8e6bce9e09b843e7fa885fe597b0a6121cd", + "asset_status": "accepted", + "runner_status": "super-gradients-compatibility-probe-required" + }, + { + "candidate_id": "goose-ddrnet-category-512", + "modality": "camera-2d", + "family": "ddrnet", + "output_contract": "goose-category-12", + "input_resolution": [512, 512], + "relative_path": "models/goose/ddrnet_category_512.pth", + "size_bytes": 259313579, + "sha256": "ddab58d3b27309e4e1545ecb0eafbe077f3ebd58fe7120defe44478424c2a20e", + "asset_status": "accepted", + "runner_status": "super-gradients-compatibility-probe-required" + }, + { + "candidate_id": "goose-ddrnet-class-512", + "modality": "camera-2d", + "family": "ddrnet", + "output_contract": "goose-class-64", + "input_resolution": [512, 512], + "relative_path": "models/goose/ddrnet_class_512.pth", + "size_bytes": 259419077, + "sha256": "b99c2838051bcd7b092fd3970aa62a77d5c0bbb809c9b9afb2ff4b0ebdaa4ee6", + "asset_status": "accepted", + "runner_status": "super-gradients-compatibility-probe-required" + }, + { + "candidate_id": "rellis-hrnet-ocr", + "modality": "camera-2d", + "family": "hrnet-ocr", + "output_contract": "rellis-20-class", + "relative_path": "models/rellis-3d/hrnet_best.zip", + "size_bytes": 788183119, + "sha256": "2842b7c427d9abb3f34725dea306b72422af5293cd8289da3035edff81deac27", + "asset_status": "accepted", + "runner_status": "upstream-validation-probe-required" + }, + { + "candidate_id": "rellis-gscnn", + "modality": "camera-2d", + "family": "gscnn", + "output_contract": "rellis-20-class", + "relative_path": "models/rellis-3d/gscnn_best.pth", + "size_bytes": 1098515419, + "sha256": "d77a83032ff9b3dea74bdbdd9bb12c0810ddff0dce6a02d42264c592fbdc0b18", + "asset_status": "accepted-size-and-hash-legacy-pickle", + "runner_status": "upstream-validation-probe-required" + }, + { + "candidate_id": "rellis-salsanext", + "modality": "lidar-3d", + "family": "salsanext", + "output_contract": "rellis-20-class", + "relative_path": "models/rellis-3d/salsanext_best.zip", + "size_bytes": 164312336, + "sha256": "6cab4f0c4ac556f9597d338692f2dee1a9e9438941f9d85159685616b948fafb", + "asset_status": "accepted", + "runner_status": "native-scan-compatibility-probe-required" + }, + { + "candidate_id": "rellis-kpconv", + "modality": "lidar-3d", + "family": "kpconv", + "output_contract": "rellis-20-class", + "relative_path": "models/rellis-3d/kpconv_best.zip", + "size_bytes": 1522250650, + "sha256": "d2a11b7a66290cce3d592e830889c3bcb188c62ced83092a7201765621b8bfc3", + "asset_status": "accepted", + "runner_status": "native-scan-compatibility-probe-required" + }, + { + "candidate_id": "wildscenes-model-bundle", + "modality": "camera-2d-and-lidar-3d", + "family": "mmsegmentation-and-mmdetection3d", + "output_contract": "wildscenes-natural-environment", + "bundle_entries": [ + "spvcnn_wildscenes.pth", + "minkunet_wildscenes.pth", + "deeplabv3_wildscenes.pth", + "segformer_wildscenes.pth", + "cylinder3d_wildscenes.pth", + "mask2former_swin_wildscenes.pth", + "upernet_convnext_wildscenes.pth", + "mask2former_resnet_wildscenes.pth" + ], + "relative_path": "models/wildscenes/WildScenes-Models.zip", + "size_bytes": 8637507567, + "sha256": "0b5040b157e928263bdbefeaffbd36414c2cb641ebc70713b3be3460c1feaf2b", + "asset_status": "accepted", + "runner_status": "upstream-docker-validation-probe-required" + }, + { + "candidate_id": "orfd-offnet-roadseg", + "modality": "camera-lidar-fusion", + "family": "offnet", + "output_contract": "binary-freespace", + "relative_path": "models/orfd-offnet/OFF-Net/best_net_RoadSeg.pth", + "size_bytes": 100976531, + "sha256": "4d82a9ba1c5411a8159e1a262f1741a6a163c8bd9751d52a90fb10deb237650d", + "asset_status": "accepted", + "runner_status": "upstream-validation-probe-required" + } + ], + "execution_sequence": [ + "upstream-runner-reproduction", + "official-validation-sample", + "native-fisheye-or-lidar-compatibility", + "shared-vegetation-label-mapping", + "recorded-shadow-quality-and-resource-tournament", + "mission-policy-composition-without-actuation" + ], + "invariants": { + "one_heavy_candidate_at_a_time": true, + "raw_fisheye_is_immutable": true, + "missing_or_unknown_is_free": false, + "semantic_label_can_clear_rigid_geometry": false, + "preset_can_override_explicit_mission_rule": false, + "navigation_authority": false, + "actuation_authority": false + } +} diff --git a/tests/test_vegetation_mission_policy.py b/tests/test_vegetation_mission_policy.py index a23283e..dbd6e1c 100644 --- a/tests/test_vegetation_mission_policy.py +++ b/tests/test_vegetation_mission_policy.py @@ -1,5 +1,6 @@ from __future__ import annotations +import json from pathlib import Path import pytest @@ -14,6 +15,12 @@ REPOSITORY_ROOT = Path(__file__).resolve().parents[1] POLICY_PATH = ( REPOSITORY_ROOT / "config" / "perception" / "lab-v1-vegetation-mission-policy-v1.json" ) +CANDIDATE_MANIFEST_PATH = ( + REPOSITORY_ROOT + / "config" + / "perception" + / "lab-v1-vegetation-candidate-manifest-v1.json" +) def _policy() -> dict[str, object]: @@ -117,3 +124,26 @@ def test_unknown_material_is_treated_as_unknown_vegetation() -> None: assert decision.material_class == "vegetation_unknown" assert decision.effective_action == "NO_GO" assert decision.safety_reason == "hard_safety_interlock:vegetation_unknown" + + +def test_candidate_manifest_freezes_unique_assets_sources_and_no_authority() -> None: + manifest = json.loads(CANDIDATE_MANIFEST_PATH.read_text(encoding="utf-8")) + assert manifest["schema_version"] == "missioncore.vegetation-candidate-manifest/v1" + assert manifest["worker"]["canonical_runtime_mutation_allowed"] is False + + sources = manifest["upstream_sources"] + assert {source["source_id"] for source in sources} == { + "wildscenes", + "rellis-3d", + "orfd-offnet", + } + assert all(len(source["revision"]) == 40 for source in sources) + + candidates = manifest["candidate_assets"] + candidate_ids = [candidate["candidate_id"] for candidate in candidates] + assert len(candidate_ids) == len(set(candidate_ids)) == 10 + assert all(candidate["size_bytes"] > 0 for candidate in candidates) + assert all(len(candidate["sha256"]) == 64 for candidate in candidates) + assert manifest["invariants"]["missing_or_unknown_is_free"] is False + assert manifest["invariants"]["navigation_authority"] is False + assert manifest["invariants"]["actuation_authority"] is False