from __future__ import annotations import json from pathlib import Path import pytest from k1link.laboratory.vegetation_mission_policy import ( VegetationMissionPolicyError, load_vegetation_mission_policy, load_vegetation_provider_label_map, map_provider_material, resolve_terrain_policy, ) 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" ) PROVIDER_LABEL_MAP_PATH = ( REPOSITORY_ROOT / "config" / "perception" / "lab-v1-vegetation-provider-label-map-v1.json" ) def _policy() -> dict[str, object]: return load_vegetation_mission_policy(POLICY_PATH, repository_root=REPOSITORY_ROOT) def _provider_label_map() -> dict[str, object]: policy = _policy() return load_vegetation_provider_label_map(PROVIDER_LABEL_MAP_PATH, policy=policy) def test_presets_are_defaults_and_explicit_mission_rule_wins() -> None: policy = _policy() urban_default = resolve_terrain_policy( policy, preset_id="urban", material_class="grass", evidence_state="VEGETATION_POTENTIALLY_TRAVERSABLE", ) assert urban_default.requested_action == "NO_GO" assert urban_default.effective_action == "NO_GO" assert urban_default.policy_source == "selected_preset_default" explicit_allow = resolve_terrain_policy( policy, preset_id="urban", material_class="grass", evidence_state="VEGETATION_POTENTIALLY_TRAVERSABLE", mission_rules={"grass": "ALLOW"}, ) assert explicit_allow.requested_action == "ALLOW" assert explicit_allow.effective_action == "ALLOW" assert explicit_allow.policy_source == "explicit_mission_rule" assert explicit_allow.actuation_authority is False def test_offroad_grass_is_high_cost_until_mission_changes_it() -> None: decision = resolve_terrain_policy( _policy(), preset_id="offroad", material_class="grass", evidence_state="VEGETATION_POTENTIALLY_TRAVERSABLE", ) assert decision.requested_action == "HIGH_COST" assert decision.effective_action == "HIGH_COST" assert decision.safety_reason is None @pytest.mark.parametrize( "state", [ "UNOBSERVED", "NEGATIVE_OR_UNSUPPORTED", "RIGID_OR_UNKNOWN_OBSTACLE", "VEGETATION_UNKNOWN", "VEGETATION_WITH_RIGID_GEOMETRY", ], ) def test_mission_allow_never_clears_hard_safety_interlock(state: str) -> None: decision = resolve_terrain_policy( _policy(), preset_id="offroad", material_class="grass", evidence_state=state, mission_rules={"grass": "ALLOW"}, ) assert decision.requested_action == "ALLOW" assert decision.effective_action == "NO_GO" assert decision.safety_reason == f"hard_safety_interlock:{state}" def test_missing_semantics_and_support_fail_closed() -> None: decision = resolve_terrain_policy( _policy(), preset_id="rural", material_class=None, evidence_state=None, ) assert decision.material_class == "vegetation_unknown" assert decision.evidence_state == "UNOBSERVED" assert decision.effective_action == "NO_GO" def test_woody_material_cannot_be_enabled_by_mission() -> None: with pytest.raises( VegetationMissionPolicyError, match="material cannot be overridden by a mission: tree_or_trunk", ): resolve_terrain_policy( _policy(), preset_id="offroad", material_class="tree_or_trunk", evidence_state="SUPPORTED_GROUND", mission_rules={"tree_or_trunk": "ALLOW"}, ) def test_unknown_material_is_treated_as_unknown_vegetation() -> None: decision = resolve_terrain_policy( _policy(), preset_id="offroad", material_class="provider_specific_leaf", evidence_state="SUPPORTED_GROUND", ) 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 @pytest.mark.parametrize( ("provider_id", "provider_label", "material"), [ ("goose-fine-64", "low_grass", "grass"), ("goose-fine-64", "high_grass", "herbaceous_vegetation"), ("goose-fine-64", "bush", "woody_shrub"), ("goose-fine-64", "tree_trunk", "tree_or_trunk"), ("wildscenes-19", "tree-trunk", "tree_or_trunk"), ("rellis-20", "tree", "tree_or_trunk"), ], ) def test_fine_provider_labels_map_to_separate_material_claims( provider_id: str, provider_label: str, material: str, ) -> None: assert ( map_provider_material( _provider_label_map(), provider_id=provider_id, provider_label=provider_label, ) == material ) def test_coarse_vegetation_never_becomes_grass_permission() -> None: material = map_provider_material( _provider_label_map(), provider_id="goose-category-12", provider_label="vegetation", ) assert material == "vegetation_unknown" decision = resolve_terrain_policy( _policy(), preset_id="offroad", material_class=material, evidence_state="SUPPORTED_GROUND", ) assert decision.effective_action == "NO_GO" def test_binary_freespace_and_unmapped_labels_make_no_material_claim() -> None: label_map = _provider_label_map() assert ( map_provider_material( label_map, provider_id="orfd-binary-freespace", provider_label="freespace", ) is None ) assert ( map_provider_material( label_map, provider_id="goose-fine-64", provider_label="person", ) is None )