feat: add governed Mol nature value layer
GeoIntel CI / docs-smoke (push) Canceled after 0s
GeoIntel CI / contract-smoke (push) Canceled after 0s

This commit is contained in:
Codex
2026-07-15 13:20:13 +02:00
parent a0795ae008
commit 16be7564f3
16 changed files with 1251 additions and 7 deletions
+37 -5
View File
@@ -24,6 +24,7 @@ FULL_AREA_CLIPPED_OPERATOR_TOOLS = {
"provision_regional_grb_buildings.py",
"provision_regional_grb_context.py",
"provision_waterinfo_station_history.py",
"provision_mol_bwk_natura2000.py",
}
@@ -84,6 +85,7 @@ SEMANTIC_SELECTION_METRICS: dict[str, tuple[dict[str, Any], ...]] = {
"warning": "GRB-percelen zijn een grafische referentie en vormen geen juridische grensopmeting.",
},
),
"nature_value": (),
}
SEMANTIC_COUNT_LABELS = {
@@ -93,6 +95,7 @@ SEMANTIC_COUNT_LABELS = {
"water": "Waterobjecten",
"roads": "Wegsegmenten",
"parcels": "Percelen",
"nature_value": "BWK-kaartvlakken",
}
@@ -114,6 +117,10 @@ class VectorFeatureService:
"waterways": "water",
"road": "roads",
"parcel": "parcels",
"nature": "nature_value",
"biodiversity": "nature_value",
"bwk": "nature_value",
"natura2000": "nature_value",
}
for candidate in candidates:
if not isinstance(candidate, str) or not candidate.strip():
@@ -356,6 +363,17 @@ class VectorFeatureService:
primary_config = semantic_metrics[0]
metric_configs = [primary_config]
configured_metrics = source_metadata.get("selection_metrics")
if isinstance(configured_metrics, list):
existing_metric_keys = {str(primary_config.get("metric_key") or "")}
for configured_item in configured_metrics:
if not isinstance(configured_item, dict):
continue
metric_key = str(configured_item.get("metric_key") or "").strip()
if not metric_key or metric_key in existing_metric_keys:
continue
metric_configs.append(dict(configured_item))
existing_metric_keys.add(metric_key)
for semantic_metric in semantic_metrics:
signature = (semantic_metric["method"], semantic_metric["unit"])
existing = {
@@ -419,6 +437,20 @@ class VectorFeatureService:
metric_filter = selection_filter
if dimension in {1, 2}:
metric_filter += (func.ST_Dimension(VectorFeature.geometry) == int(dimension),)
filter_property = str(config.get("filter_property") or "").strip()
filter_values = config.get("filter_values")
if filter_property:
if not isinstance(filter_values, list) or not filter_values:
raise AppError(
code="INVALID_SELECTION_AGGREGATION",
message="Dataset selection metric filter requires one or more values",
details={"dataset_id": str(dataset.id), "filter_property": filter_property},
status_code=500,
)
normalized_filter_values = [str(value) for value in filter_values]
metric_filter += (
VectorFeature.properties_json.op("->>")(filter_property).in_(normalized_filter_values),
)
if method == "intersection_area":
measured_geometry = (
@@ -461,7 +493,7 @@ class VectorFeatureService:
aggregate_function = func.avg if method == "mean" else func.sum
aggregate_value = (
db.query(func.coalesce(aggregate_function(value_expression), 0.0))
.filter(*selection_filter)
.filter(*metric_filter)
.filter(VectorFeature.properties_json.op("->>")(property_name).isnot(None))
.scalar()
)
@@ -469,16 +501,16 @@ class VectorFeatureService:
if method == "area_weighted_sum" and not full_dataset_area:
partial_feature_count = (
db.query(func.count(VectorFeature.id))
.filter(*selection_filter)
.filter(*metric_filter)
.filter(coverage_ratio < 0.999999)
.scalar()
)
is_estimate = bool(partial_feature_count)
is_estimate = bool(config.get("is_estimate", False)) or bool(partial_feature_count)
if not is_estimate and config.get("warning_only_when_estimate", True):
warning = None
elif method == "area_weighted_sum":
is_estimate = False
if config.get("warning_only_when_estimate", True):
is_estimate = bool(config.get("is_estimate", False))
if not is_estimate and config.get("warning_only_when_estimate", True):
warning = None
elif method != "feature_count":
raise AppError(