Scope bounded coverage to persisted extents
This commit is contained in:
@@ -32,6 +32,8 @@
|
|||||||
catalog content hash remain mandatory stable identity fields.
|
catalog content hash remain mandatory stable identity fields.
|
||||||
- Kept Statbel population materialization theme-specific so it can never be
|
- Kept Statbel population materialization theme-specific so it can never be
|
||||||
reported as an NGI administrative boundary layer.
|
reported as an NGI administrative boundary layer.
|
||||||
|
- Made bounded API coverage spatially honest: a persisted provider selection
|
||||||
|
is operational only for selections contained by its retained source bbox.
|
||||||
|
|
||||||
## Autonomous Belgium and North Sea RC program (2026-07-17)
|
## Autonomous Belgium and North Sea RC program (2026-07-17)
|
||||||
|
|
||||||
|
|||||||
@@ -422,6 +422,7 @@ class CoverageRegistryService:
|
|||||||
definition: _SourceDefinition,
|
definition: _SourceDefinition,
|
||||||
theme: str,
|
theme: str,
|
||||||
zone: str,
|
zone: str,
|
||||||
|
selection: Any,
|
||||||
) -> list[Dataset]:
|
) -> list[Dataset]:
|
||||||
if definition.operational_themes and theme not in definition.operational_themes:
|
if definition.operational_themes and theme not in definition.operational_themes:
|
||||||
return []
|
return []
|
||||||
@@ -444,6 +445,18 @@ class CoverageRegistryService:
|
|||||||
coverage_zones = metadata.get("coverage_zones") or metadata.get("coverage_zone") or []
|
coverage_zones = metadata.get("coverage_zones") or metadata.get("coverage_zone") or []
|
||||||
if isinstance(coverage_zones, str):
|
if isinstance(coverage_zones, str):
|
||||||
coverage_zones = [coverage_zones]
|
coverage_zones = [coverage_zones]
|
||||||
|
acquired_bbox = metadata.get("bbox_epsg4326")
|
||||||
|
if (
|
||||||
|
definition.contract.acquisition_mode == "bounded_api"
|
||||||
|
and isinstance(acquired_bbox, list)
|
||||||
|
and len(acquired_bbox) == 4
|
||||||
|
):
|
||||||
|
try:
|
||||||
|
acquired_scope = box(*(float(value) for value in acquired_bbox))
|
||||||
|
except (TypeError, ValueError):
|
||||||
|
continue
|
||||||
|
if not acquired_scope.is_valid or not acquired_scope.covers(selection):
|
||||||
|
continue
|
||||||
layer_matches = not layer_names or dataset.reference_layer_name in layer_names
|
layer_matches = not layer_names or dataset.reference_layer_name in layer_names
|
||||||
zone_matches = not coverage_zones or zone in coverage_zones or "belgium" in coverage_zones
|
zone_matches = not coverage_zones or zone in coverage_zones or "belgium" in coverage_zones
|
||||||
if layer_matches and zone_matches:
|
if layer_matches and zone_matches:
|
||||||
@@ -456,6 +469,7 @@ class CoverageRegistryService:
|
|||||||
zone: str,
|
zone: str,
|
||||||
theme: str,
|
theme: str,
|
||||||
datasets: list[Dataset],
|
datasets: list[Dataset],
|
||||||
|
selection: Any,
|
||||||
) -> CoverageResolutionItem:
|
) -> CoverageResolutionItem:
|
||||||
definitions = [
|
definitions = [
|
||||||
definition
|
definition
|
||||||
@@ -481,6 +495,7 @@ class CoverageRegistryService:
|
|||||||
definition,
|
definition,
|
||||||
theme,
|
theme,
|
||||||
zone,
|
zone,
|
||||||
|
selection,
|
||||||
)
|
)
|
||||||
materialized.extend(matches)
|
materialized.extend(matches)
|
||||||
if matches:
|
if matches:
|
||||||
@@ -535,7 +550,12 @@ class CoverageRegistryService:
|
|||||||
)
|
)
|
||||||
|
|
||||||
items = [
|
items = [
|
||||||
CoverageRegistryService._resolve_item(zone=zone, theme=theme, datasets=datasets)
|
CoverageRegistryService._resolve_item(
|
||||||
|
zone=zone,
|
||||||
|
theme=theme,
|
||||||
|
datasets=datasets,
|
||||||
|
selection=selection,
|
||||||
|
)
|
||||||
for zone in zones
|
for zone in zones
|
||||||
for theme in requested_themes
|
for theme in requested_themes
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -180,6 +180,47 @@ def test_statbel_population_materialization_does_not_masquerade_as_admin_data()
|
|||||||
assert population.materialized_dataset_ids == [statbel_id]
|
assert population.materialized_dataset_ids == [statbel_id]
|
||||||
|
|
||||||
|
|
||||||
|
def test_bounded_api_materialization_only_covers_its_persisted_bbox() -> None:
|
||||||
|
project_id = uuid4()
|
||||||
|
dataset_id = uuid4()
|
||||||
|
dataset = SimpleNamespace(
|
||||||
|
id=dataset_id,
|
||||||
|
status="ready",
|
||||||
|
source_name="spw_picc",
|
||||||
|
reference_layer_name="buildings",
|
||||||
|
source_metadata={
|
||||||
|
"coverage_zones": ["wallonia"],
|
||||||
|
"bbox_epsg4326": [4.55, 50.58, 4.56, 50.59],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
session = FakeSession(
|
||||||
|
project=SimpleNamespace(id=project_id),
|
||||||
|
areas=[
|
||||||
|
scope_area("Belgium land", box(2.5, 49.5, 6.4, 51.5)),
|
||||||
|
scope_area("Wallonia", box(2.5, 49.5, 6.4, 50.8)),
|
||||||
|
],
|
||||||
|
datasets=[dataset],
|
||||||
|
)
|
||||||
|
|
||||||
|
inside = CoverageRegistryService.resolve(
|
||||||
|
session,
|
||||||
|
project_id,
|
||||||
|
CoverageBBox(minx=4.551, miny=50.581, maxx=4.559, maxy=50.589),
|
||||||
|
["buildings"],
|
||||||
|
)
|
||||||
|
outside = CoverageRegistryService.resolve(
|
||||||
|
session,
|
||||||
|
project_id,
|
||||||
|
CoverageBBox(minx=4.7, miny=50.6, maxx=4.71, maxy=50.61),
|
||||||
|
["buildings"],
|
||||||
|
)
|
||||||
|
|
||||||
|
assert inside.items[0].status == "operational"
|
||||||
|
assert inside.items[0].materialized_dataset_ids == [dataset_id]
|
||||||
|
assert outside.items[0].status == "partial"
|
||||||
|
assert outside.items[0].materialized_dataset_ids == []
|
||||||
|
|
||||||
|
|
||||||
def test_mixed_land_and_north_sea_selection_remains_split() -> None:
|
def test_mixed_land_and_north_sea_selection_remains_split() -> None:
|
||||||
project_id = uuid4()
|
project_id = uuid4()
|
||||||
project = SimpleNamespace(id=project_id)
|
project = SimpleNamespace(id=project_id)
|
||||||
|
|||||||
@@ -28,6 +28,9 @@
|
|||||||
the Statbel population Dataset also appeared under `admin`. The coverage
|
the Statbel population Dataset also appeared under `admin`. The coverage
|
||||||
registry now enforces each source's `operational_themes`, leaving NGI as the
|
registry now enforces each source's `operational_themes`, leaving NGI as the
|
||||||
administrative authority and Statbel as population evidence only.
|
administrative authority and Statbel as population evidence only.
|
||||||
|
- Bounded provider materialization now also checks its persisted
|
||||||
|
`bbox_epsg4326`; one small PICC/UrbIS/GRB/raster acquisition can no longer
|
||||||
|
claim that an entire region is locally loaded.
|
||||||
- Focused backend and frontend suites passed before full release validation;
|
- Focused backend and frontend suites passed before full release validation;
|
||||||
full local and Tower evidence follows in the final P5 gate.
|
full local and Tower evidence follows in the final P5 gate.
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user