from __future__ import annotations from types import SimpleNamespace from uuid import uuid4 import pytest from shapely.geometry import box from app.core.errors import AppError from app.models import Dataset, SourceRegistry, SourceSnapshot from app.services.coverage_registry_service import CoverageRegistryService, SOURCE_DEFINITIONS import app.services.dataset_consumption_gate_service as gate_module from app.services.dataset_consumption_gate_service import DatasetConsumptionGate from app.services.export_service import ExportService def _governed_dataset( *, source_key: str = "grb", classification: str = "authoritative", snapshot_freshness_status: str = "current", ) -> Dataset: source_id = uuid4() snapshot_id = uuid4() checksum = "a" * 64 source = SourceRegistry( id=source_id, source_key=source_key, display_name=f"{source_key} test source", classification=classification, authority_name="GeoIntel test authority", authority_scope_json={"scope": "test"}, usage_policy_json={ "ground_truth_allowed": classification == "authoritative", "validation_authority": {"building_validation": "primary"} if classification == "authoritative" else {}, }, ) snapshot = SourceSnapshot( id=snapshot_id, source_registry_id=source_id, snapshot_key="test-snapshot", checksum_sha256=checksum, freshness_status=snapshot_freshness_status, ingest_status="ingested", ) dataset = Dataset( id=uuid4(), project_id=uuid4(), name="governed.tif", dataset_type="raster", source=source_key, source_name=source_key, dataset_role="source", checksum_sha256=checksum, source_registry_id=source_id, source_snapshot_id=snapshot_id, data_contract_key="geointel.raster.geotiff", data_contract_version="1.0.0", validation_status="passed", provenance_status="complete", lineage_status="not_applicable", quarantine_status="not_quarantined", status="ready", ) dataset.source_registry = source dataset.source_snapshot = snapshot return dataset def test_governed_dataset_passes_production_inference_and_authoritative_coverage() -> None: dataset = _governed_dataset() inference = DatasetConsumptionGate.assert_eligible(dataset, purpose="production_inference") coverage = DatasetConsumptionGate.assert_eligible(dataset, purpose="authoritative_coverage") assert inference.eligible is True assert coverage.eligible is True @pytest.mark.parametrize( ("field", "value", "error_code"), ( ("provenance_status", "incomplete", "DATASET_PROVENANCE_INCOMPLETE"), ("validation_status", "failed", "DATASET_QUARANTINED"), ("quarantine_status", "quarantined", "DATASET_QUARANTINED"), ), ) def test_explicit_unsafe_states_can_never_be_relaxed(field: str, value: str, error_code: str) -> None: dataset = _governed_dataset() setattr(dataset, field, value) with pytest.raises(AppError) as exc_info: DatasetConsumptionGate.assert_eligible( dataset, purpose="production_inference", fixture_mode=True, ) assert exc_info.value.code == error_code assert field.replace("_status", "") in " ".join(exc_info.value.details["reasons"]) def test_legacy_fixture_can_support_fixture_qa_but_never_authoritative_coverage() -> None: fixture = Dataset( id=uuid4(), project_id=uuid4(), name="fixture.tif", dataset_type="raster", source="fixture", ) qa = DatasetConsumptionGate.assert_eligible(fixture, purpose="quality_assessment") with pytest.raises(AppError) as inference_error: DatasetConsumptionGate.assert_eligible( fixture, purpose="production_inference", fixture_mode=True, ) with pytest.raises(AppError) as export_error: DatasetConsumptionGate.assert_eligible(fixture, purpose="export") with pytest.raises(AppError) as fixture_export_error: DatasetConsumptionGate.assert_eligible(fixture, purpose="export", fixture_mode=True) coverage = DatasetConsumptionGate.evaluate(fixture, purpose="authoritative_coverage") assert qa.fixture_legacy_exception is True assert inference_error.value.code == "DATASET_PROVENANCE_INCOMPLETE" assert "fixture_qa_only" in inference_error.value.details["reasons"] assert export_error.value.code == "DATASET_PROVENANCE_INCOMPLETE" assert fixture_export_error.value.code == "DATASET_PROVENANCE_INCOMPLETE" assert "fixture_qa_only" in fixture_export_error.value.details["reasons"] assert coverage.eligible is False assert "fixture_not_authoritative_coverage" in coverage.reasons def test_unprovenanced_persistent_dataset_is_blocked(monkeypatch) -> None: dataset = Dataset( id=uuid4(), project_id=uuid4(), name="manual.tif", dataset_type="raster", source="manual_upload", ) monkeypatch.setattr(gate_module, "sa_inspect", lambda _dataset: SimpleNamespace(transient=False)) with pytest.raises(AppError) as exc_info: DatasetConsumptionGate.assert_eligible( dataset, purpose="production_inference", fixture_mode=True, ) assert exc_info.value.code == "DATASET_PROVENANCE_INCOMPLETE" assert "phase2_provenance_missing" in exc_info.value.details["reasons"] assert "fixture_source_required" in exc_info.value.details["reasons"] def test_transient_orm_test_double_can_only_bypass_missing_legacy_fields_for_qa() -> None: transient = Dataset( id=uuid4(), project_id=uuid4(), name="transient-test.tif", dataset_type="raster", source="manual_upload", ) decision = DatasetConsumptionGate.assert_eligible(transient, purpose="quality_assessment") coverage = DatasetConsumptionGate.evaluate(transient, purpose="authoritative_coverage") with pytest.raises(AppError) as production_error: DatasetConsumptionGate.assert_eligible(transient, purpose="production_inference") assert decision.fixture_legacy_exception is True assert production_error.value.code == "DATASET_PROVENANCE_INCOMPLETE" assert coverage.eligible is False assert "phase2_provenance_missing" in coverage.reasons @pytest.mark.parametrize("purpose", ("production_inference", "derived_processing", "export")) def test_passed_manual_or_experimental_dataset_cannot_cross_production_boundary(purpose: str) -> None: """A syntactically valid manual upload remains experimental, never production-ready.""" manual = _governed_dataset(source_key="manual", classification="experimental") manual.source = "manual_upload" with pytest.raises(AppError) as exc_info: DatasetConsumptionGate.assert_eligible(manual, purpose=purpose) # type: ignore[arg-type] assert exc_info.value.code == "DATASET_PROVENANCE_INCOMPLETE" assert "experimental_source_not_allowed_for_purpose" in exc_info.value.details["reasons"] def test_reference_validation_requires_authoritative_ground_truth_reference() -> None: reference = _governed_dataset() reference.dataset_type = "vector" reference.dataset_role = "reference" decision = DatasetConsumptionGate.assert_eligible( reference, purpose="reference_validation", reference_task="building_validation", ) assert decision.eligible is True reference.source_registry.classification = "corroborative" with pytest.raises(AppError) as exc_info: DatasetConsumptionGate.assert_eligible( reference, purpose="reference_validation", reference_task="building_validation", ) assert exc_info.value.code == "DATASET_PROVENANCE_INCOMPLETE" assert "reference_source_not_authoritative" in exc_info.value.details["reasons"] def test_pending_regional_building_authority_cannot_become_truth_without_approval() -> None: reference = _governed_dataset(source_key="spw_picc", classification="authoritative") reference.dataset_type = "vector" reference.dataset_role = "reference" reference.source_registry.authority_scope_json = {"zone": "Wallonia"} reference.source_registry.usage_policy_json = { "ground_truth_allowed": True, "validation_authority": {"building_validation": "regional_primary_pending_contract"}, } with pytest.raises(AppError) as exc_info: DatasetConsumptionGate.assert_eligible( reference, purpose="reference_validation", reference_task="building_validation", ) assert exc_info.value.code == "DATASET_PROVENANCE_INCOMPLETE" assert "reference_task_authority_not_approved" in exc_info.value.details["reasons"] def test_source_snapshot_must_belong_to_the_dataset_source_registry() -> None: dataset = _governed_dataset() dataset.source_snapshot.source_registry_id = uuid4() with pytest.raises(AppError) as exc_info: DatasetConsumptionGate.assert_eligible(dataset, purpose="production_inference") assert exc_info.value.code == "DATASET_PROVENANCE_INCOMPLETE" assert "source_snapshot_registry_mismatch" in exc_info.value.details["reasons"] @pytest.mark.parametrize("freshness_status", ("unknown", "review_required", "due", "stale")) def test_non_consumable_source_snapshot_freshness_is_blocked_at_production_boundaries( freshness_status: str, ) -> None: dataset = _governed_dataset(snapshot_freshness_status=freshness_status) for purpose in ("production_inference", "authoritative_coverage"): with pytest.raises(AppError) as exc_info: DatasetConsumptionGate.assert_eligible(dataset, purpose=purpose) # type: ignore[arg-type] assert exc_info.value.code == "DATASET_PROVENANCE_INCOMPLETE" assert "source_snapshot_freshness_not_eligible" in exc_info.value.details["reasons"] def test_coverage_registry_ignores_explicitly_incomplete_materialization() -> None: definition = next(item for item in SOURCE_DEFINITIONS if item.contract.source_name == "digitaal_vlaanderen") unsafe_materialization = SimpleNamespace( id=uuid4(), status="ready", source_name="grb", validation_status="passed", provenance_status="incomplete", lineage_status="complete", quarantine_status="not_quarantined", ) matches, fully_covered = CoverageRegistryService._matching_datasets( [unsafe_materialization], definition, "buildings", "flanders", box(4.0, 50.8, 4.1, 50.9), ) assert matches == [] assert fully_covered is False def test_vector_export_is_fail_closed_before_selection(monkeypatch) -> None: dataset = _governed_dataset() dataset.dataset_type = "vector" dataset.status = "quarantined" queried = False class _Session: @staticmethod def get(model, item_id): return dataset if model is Dataset and item_id == dataset.id else None def _unexpected_selection(*_args, **_kwargs): nonlocal queried queried = True raise AssertionError("unsafe dataset must be rejected before querying vector features") monkeypatch.setattr( "app.services.export_service.VectorFeatureService.select_features_by_bbox", _unexpected_selection, ) with pytest.raises(AppError) as exc_info: ExportService.export_vector_selection_geojson( _Session(), dataset.id, {"min_x": 4.0, "min_y": 50.0, "max_x": 4.1, "max_y": 50.1, "crs": "EPSG:4326"}, ) assert exc_info.value.code == "DATASET_QUARANTINED" assert queried is False