From 8085d106d4f5294b0e9b83a3b623351481113f4d Mon Sep 17 00:00:00 2001 From: Codex Date: Sun, 19 Jul 2026 01:47:43 +0200 Subject: [PATCH] Keep coverage materialization theme-specific --- CHANGELOG.md | 2 ++ .../app/services/coverage_registry_service.py | 2 ++ backend/tests/test_rc4_national_coverage.py | 31 +++++++++++++++++++ docs/CODEX_EXECUTION_LOG.md | 4 +++ 4 files changed, 39 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 92f63bd8..d1984222 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,8 @@ - Fixed the governed Statbel review gate so a new probe timestamp does not masquerade as a changed publication; release URL, identifier, version and catalog content hash remain mandatory stable identity fields. +- Kept Statbel population materialization theme-specific so it can never be + reported as an NGI administrative boundary layer. ## Autonomous Belgium and North Sea RC program (2026-07-17) diff --git a/backend/app/services/coverage_registry_service.py b/backend/app/services/coverage_registry_service.py index fb463b1f..1f8a9080 100644 --- a/backend/app/services/coverage_registry_service.py +++ b/backend/app/services/coverage_registry_service.py @@ -423,6 +423,8 @@ class CoverageRegistryService: theme: str, zone: str, ) -> list[Dataset]: + if definition.operational_themes and theme not in definition.operational_themes: + return [] matches: list[Dataset] = [] for dataset in datasets: if dataset.status != "ready" or dataset.source_name not in definition.materialized_source_names: diff --git a/backend/tests/test_rc4_national_coverage.py b/backend/tests/test_rc4_national_coverage.py index 69f67127..b9e1f8eb 100644 --- a/backend/tests/test_rc4_national_coverage.py +++ b/backend/tests/test_rc4_national_coverage.py @@ -149,6 +149,37 @@ def test_coverage_resolver_only_reports_operational_for_materialized_ready_datas assert admin_item.materialized_dataset_ids == [dataset_id] +def test_statbel_population_materialization_does_not_masquerade_as_admin_data() -> None: + project_id = uuid4() + statbel_id = uuid4() + statbel = SimpleNamespace( + id=statbel_id, + status="ready", + source_name="statbel", + reference_layer_name="population", + source_metadata={"coverage_zones": ["belgium", "flanders", "wallonia", "brussels"]}, + ) + result = CoverageRegistryService.resolve( + FakeSession( + project=SimpleNamespace(id=project_id), + areas=[ + scope_area("Belgium land", box(2.5, 49.5, 6.4, 51.5)), + scope_area("Flanders", box(2.5, 50.7, 5.9, 51.5)), + ], + datasets=[statbel], + ), + project_id, + CoverageBBox(minx=4.9, miny=50.9, maxx=5.0, maxy=51.0), + ["admin", "population"], + ) + + admin = next(item for item in result.items if item.theme == "admin") + population = next(item for item in result.items if item.theme == "population") + assert admin.materialized_dataset_ids == [] + assert population.status == "operational" + assert population.materialized_dataset_ids == [statbel_id] + + def test_mixed_land_and_north_sea_selection_remains_split() -> None: project_id = uuid4() project = SimpleNamespace(id=project_id) diff --git a/docs/CODEX_EXECUTION_LOG.md b/docs/CODEX_EXECUTION_LOG.md index 4201b84b..cd52a695 100644 --- a/docs/CODEX_EXECUTION_LOG.md +++ b/docs/CODEX_EXECUTION_LOG.md @@ -24,6 +24,10 @@ `catalog_checked_at` was incorrectly compared as publication identity. Reviews now tolerate a later probe timestamp while still blocking any identifier, release URL/version or catalog content-hash change. +- Live coverage verification then exposed a cross-theme materialization leak: + the Statbel population Dataset also appeared under `admin`. The coverage + registry now enforces each source's `operational_themes`, leaving NGI as the + administrative authority and Statbel as population evidence only. - Focused backend and frontend suites passed before full release validation; full local and Tower evidence follows in the final P5 gate.