From df015e10e09ff2aa110e4b83ea792064cbf4a820 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 15 Jul 2026 23:49:30 +0200 Subject: [PATCH] Align historical metrics with polygon semantics --- .../app/services/vector_feature_service.py | 13 +++++++++++- ...st_sprint201_semantic_selection_metrics.py | 20 +++++++++++++++++++ ...t_sprint209_regional_historical_landuse.py | 3 +++ .../provision_regional_historical_landuse.py | 4 +++- 4 files changed, 38 insertions(+), 2 deletions(-) diff --git a/backend/app/services/vector_feature_service.py b/backend/app/services/vector_feature_service.py index 1fe1f498..626f5e6d 100644 --- a/backend/app/services/vector_feature_service.py +++ b/backend/app/services/vector_feature_service.py @@ -30,6 +30,12 @@ FULL_AREA_CLIPPED_OPERATOR_TOOLS = { "provision_buildings_addresses_register.py", } +SEMANTIC_METRICS_DISABLED_OPERATOR_TOOLS = { + # Historical land-use themes are polygon map classes. Generic live-theme + # line metrics (road/watercourse length) would therefore be meaningless. + "provision_regional_historical_landuse.py", +} + SEMANTIC_SELECTION_METRICS: dict[str, tuple[dict[str, Any], ...]] = { "buildings": ( @@ -379,9 +385,14 @@ class VectorFeatureService: "is_estimate": bool(config.get("is_estimate", False)), **({"property": config.get("property")} if config.get("property") else {}), } + provenance = dataset.provenance_metadata if isinstance(dataset.provenance_metadata, dict) else {} + semantic_metrics_disabled = ( + source_metadata.get("semantic_metrics") is False + or provenance.get("operator_tool") in SEMANTIC_METRICS_DISABLED_OPERATOR_TOOLS + ) semantic_metrics = ( [] - if source_metadata.get("semantic_metrics") is False + if semantic_metrics_disabled else [dict(metric) for metric in SEMANTIC_SELECTION_METRICS.get(theme or "", ())] ) primary_config = configured_metric diff --git a/backend/tests/test_sprint201_semantic_selection_metrics.py b/backend/tests/test_sprint201_semantic_selection_metrics.py index dce17eb5..2aa22054 100644 --- a/backend/tests/test_sprint201_semantic_selection_metrics.py +++ b/backend/tests/test_sprint201_semantic_selection_metrics.py @@ -144,6 +144,26 @@ def test_station_measurement_uses_numeric_mean_without_area_extrapolation() -> N assert result["warning"] == "Puntmeting; geen gebiedsdekkend watervolume." +def test_regional_historical_polygons_do_not_emit_irrelevant_line_metrics() -> None: + dataset = themed_dataset("water", method="intersection_area") + dataset.source_metadata["selection_aggregation"].update( + {"metric_key": "water_area", "label": "Historische wateroppervlakte", "unit": "ha"} + ) + dataset.provenance_metadata = {"operator_tool": "provision_regional_historical_landuse.py"} + + result = VectorFeatureService.summarize_features_by_bbox( + SequenceScalarSession([52_500.0]), + dataset=dataset, + bbox=BBOX, + total_feature_count=23, + ) + + assert [(item["metric_key"], item["metric_unit"]) for item in result["metrics"]] == [ + ("water_area", "ha"), + ("feature_count", "objecten"), + ] + + def test_future_regional_imports_persist_semantic_aggregation_configuration() -> None: buildings = (ROOT / "scripts/provision_regional_grb_buildings.py").read_text(encoding="utf-8") context = (ROOT / "scripts/provision_regional_grb_context.py").read_text(encoding="utf-8") diff --git a/backend/tests/test_sprint209_regional_historical_landuse.py b/backend/tests/test_sprint209_regional_historical_landuse.py index 94aa5227..d72caafc 100644 --- a/backend/tests/test_sprint209_regional_historical_landuse.py +++ b/backend/tests/test_sprint209_regional_historical_landuse.py @@ -228,6 +228,9 @@ def test_upload_contract_is_regional_temporal_and_partition_audited(tmp_path: Pa assert source_metadata["partitioned_source_audit"] is True assert source_metadata["geometry_clipped_to_area"] is True assert source_metadata["identity_stable"] is False + assert source_metadata["semantic_metrics"] is False + assert source_metadata["selection_aggregation"]["metric_key"] == "roads_area" + assert source_metadata["selection_aggregation"]["label"] == "Oppervlakte historische wegen" assert provenance["partition_count"] == 28 assert provenance["raw_source_responses_retained"] is True assert provenance["geometry_clipped_to_area"] is True diff --git a/scripts/provision_regional_historical_landuse.py b/scripts/provision_regional_historical_landuse.py index e58f8e23..1b727f3e 100644 --- a/scripts/provision_regional_historical_landuse.py +++ b/scripts/provision_regional_historical_landuse.py @@ -566,10 +566,12 @@ def upload_snapshot( "attribution": ATTRIBUTION, "source_catalog_url": SOURCE_CATALOG_URL, "identity_stable": False, + "semantic_metrics": False, "geometry_simplification_tolerance_degrees": simplify_tolerance_degrees, "selection_aggregation": { + "metric_key": f"{definition.key}_area", "method": "intersection_area", - "label": "Oppervlakte", + "label": f"Oppervlakte {definition.label.lower()}", "unit": "ha", "is_estimate": False, "warning": (