fix: preserve official Mol CRS provenance
GeoIntel CI / docs-smoke (push) Canceled after 0s
GeoIntel CI / contract-smoke (push) Canceled after 0s

This commit is contained in:
Codex
2026-07-14 05:44:31 +02:00
parent 490325e0cd
commit 480634c301
4 changed files with 50 additions and 9 deletions
+1
View File
@@ -11,6 +11,7 @@
- Added an explicit operator provisioner for the official Digitaal Vlaanderen Mol municipality boundary (NIS `13025`) and the complete GRB GBG building population clipped to that boundary. - Added an explicit operator provisioner for the official Digitaal Vlaanderen Mol municipality boundary (NIS `13025`) and the complete GRB GBG building population clipped to that boundary.
- Added auditable source artifacts and a manifest with page count, checksums, exact WGS84 bounds, municipality area, feature totals and truncation state; incomplete pagination now fails closed. - Added auditable source artifacts and a manifest with page count, checksums, exact WGS84 bounds, municipality area, feature totals and truncation state; incomplete pagination now fails closed.
- Declared EPSG:4326 explicitly in both official GeoJSON artifacts so downstream QA does not downgrade known OGC provenance to an inferred CRS.
- Provisioning remains explicit and imports Project, Area and Dataset records through existing canonical API routes and DatasetService/VectorFeatureService persistence rather than writing directly to PostGIS. - Provisioning remains explicit and imports Project, Area and Dataset records through existing canonical API routes and DatasetService/VectorFeatureService persistence rather than writing directly to PostGIS.
- Made the complete `Mol Municipality Workbench` the preferred fresh-session context and the official municipality boundary its lightweight default layer, ahead of historical Postel validation projects. - Made the complete `Mol Municipality Workbench` the preferred fresh-session context and the official municipality boundary its lightweight default layer, ahead of historical Postel validation projects.
- Replaced large coordinate arrays and spread-based bounds calculations with streaming, memoized GeoJSON bounds so municipality-scale vector layers remain safe in MapLibre. - Replaced large coordinate arrays and spread-based bounds calculations with streaming, memoized GeoJSON bounds so municipality-scale vector layers remain safe in MapLibre.
@@ -52,6 +52,7 @@ def test_mol_provisioner_uses_official_identity_and_exact_boundary_clipping() ->
assert module.MUNICIPALITY_NIS_CODE == "13025" assert module.MUNICIPALITY_NIS_CODE == "13025"
assert module.PROJECT_NAME == "Mol Municipality Workbench" assert module.PROJECT_NAME == "Mol Municipality Workbench"
assert module.GEOJSON_CRS == {"type": "name", "properties": {"name": "EPSG:4326"}}
assert len(buildings) == 2 assert len(buildings) == 2
assert summary["bbox_feature_count"] == 3 assert summary["bbox_feature_count"] == 3
assert summary["outside_boundary_count"] == 1 assert summary["outside_boundary_count"] == 1
@@ -147,4 +148,3 @@ def test_municipality_workspace_is_wired_into_runtime_and_frontend_priority() ->
assert "featureCollectionBounds(featureCollection)" in map_source assert "featureCollectionBounds(featureCollection)" in map_source
assert "useMemo(() => getFeatureCollectionBBox(mapFeatureCollection)" in map_workspace assert "useMemo(() => getFeatureCollectionBBox(mapFeatureCollection)" in map_workspace
assert "Math.min(...xs)" not in map_source assert "Math.min(...xs)" not in map_source
+37 -4
View File
@@ -7406,6 +7406,8 @@ Open:
- Added deterministic persistent source artefacts and a manifest containing - Added deterministic persistent source artefacts and a manifest containing
source URLs, checksums, page/feature counts, boundary bounds and area, and an source URLs, checksums, page/feature counts, boundary bounds and area, and an
explicit truncation flag. Pagination and identity checks fail closed. explicit truncation flag. Pagination and identity checks fail closed.
- Declared EPSG:4326 in both generated GeoJSON FeatureCollections so the
importer records `crs_assumed=false` for this known official OGC source.
- Kept the provider boundary honest: provisioning is an operator action and - Kept the provider boundary honest: provisioning is an operator action and
imports through canonical Project, Area and Dataset HTTP routes. It does not imports through canonical Project, Area and Dataset HTTP routes. It does not
enable the dormant live GRB provider or write directly to `vector_features`. enable the dormant live GRB provider or write directly to `vector_features`.
@@ -7424,12 +7426,43 @@ Open:
- Exact clipping, pagination/truncation, persistence-scaling and frontend - Exact clipping, pagination/truncation, persistence-scaling and frontend
wiring regression coverage passed locally. wiring regression coverage passed locally.
- Full backend suite and readiness gate passed with `496` tests and the
`81`-route API contract audit. Frontend typecheck/build, Ruff, shell syntax,
single Alembic head `202606120900` and the complete offline migration chain
also passed.
- No API route, ORM model, migration, QA metric, detection result or model - No API route, ORM model, migration, QA metric, detection result or model
configuration changed. configuration changed.
## Tower and live GIS evidence
- Pushed and deployed commit `490325e`; live PostGIS `3.6`, required
schema/indexes, Alembic head, frontend proxy, API proxy and icon checks
passed.
- Provisioned project `143dee9a-b279-4984-9d30-1687fac3efcc` and official
area `3166ef08-3b40-410a-a6c0-0b854186e557` with bounds
`[5.035357, 51.1534809, 5.24218961, 51.32265943]` and projected area
`114.546677 km2`.
- The complete source bbox returned `89,153` unique GRB candidates over `90`
pages. Exact municipality clipping retained `36,941` buildings, rejected
`52,212` outside features and clipped `24` boundary-crossing features. The
manifest is complete and explicitly reports `reference_truncated=false`.
- PostGIS contains `36,941` vector feature rows and `36,941` distinct source
IDs, with zero invalid geometries and zero non-EPSG:4326 geometries. Strict
coverage reports 18 floating-point boundary artefacts whose combined
outside area is only `5.75e-9 m2`; no material building area falls outside
Mol.
- A fresh browser session selected the municipality project, official area
and one-feature boundary automatically instead of a historical Postel
validation context. Selecting the complete building layer rendered all
`36,941` features and a live AOI PostGIS query returned `250` persisted
features with dataset/export actions enabled.
- Browser verification at `1280x720` and `2560x1080` found one nonblank
MapLibre canvas, no console warnings/errors and no horizontal overflow. The
widescreen map canvas measured `1678x734` CSS pixels.
## Next pass ## Next pass
- Deploy and execute the explicit provisioner on Tower, verify full PostGIS - Add viewport/zoom-aware vector delivery before expanding beyond Mol or
feature counts and exact Mol bounds, then audit the complete municipality in layering additional municipality-wide reference classes. Then acquire and
MapLibre before acquiring raster imagery for a deliberately selected Mol tile georeferenced imagery only for an explicitly selected Mol analysis zone
analysis zone. and run configured-YOLO plus QA/QC against the persisted GRB reference.
@@ -39,6 +39,7 @@ DEFAULT_OUTPUT_DIR = Path("/app/storage/operator-data/mol-municipality")
DEFAULT_API_URL = "http://127.0.0.1:8000" DEFAULT_API_URL = "http://127.0.0.1:8000"
DEFAULT_PAGE_LIMIT = 1000 DEFAULT_PAGE_LIMIT = 1000
DEFAULT_MAX_FEATURES = 100000 DEFAULT_MAX_FEATURES = 100000
GEOJSON_CRS = {"type": "name", "properties": {"name": "EPSG:4326"}}
def parse_args() -> argparse.Namespace: def parse_args() -> argparse.Namespace:
@@ -336,6 +337,7 @@ def prepare_artifacts(args: argparse.Namespace) -> tuple[Path, Path, dict[str, A
boundary_payload = { boundary_payload = {
"type": "FeatureCollection", "type": "FeatureCollection",
"name": "Official municipality boundary - Mol", "name": "Official municipality boundary - Mol",
"crs": GEOJSON_CRS,
"features": [boundary_feature], "features": [boundary_feature],
"source": "Digitaal Vlaanderen VRBG OGC API Features collection Refgem", "source": "Digitaal Vlaanderen VRBG OGC API Features collection Refgem",
"source_url": boundary_source_url, "source_url": boundary_source_url,
@@ -348,6 +350,7 @@ def prepare_artifacts(args: argparse.Namespace) -> tuple[Path, Path, dict[str, A
buildings_payload = { buildings_payload = {
"type": "FeatureCollection", "type": "FeatureCollection",
"name": "GRB buildings - complete municipality Mol", "name": "GRB buildings - complete municipality Mol",
"crs": GEOJSON_CRS,
"features": buildings, "features": buildings,
"source": "Digitaal Vlaanderen GRB OGC API Features collection GBG", "source": "Digitaal Vlaanderen GRB OGC API Features collection GBG",
"source_url": building_summary["source_urls"][0], "source_url": building_summary["source_urls"][0],
@@ -567,10 +570,14 @@ def provision_workspace(
) )
return { return {
"project": project, "project_id": project_id,
"area": area, "project_name": project.get("name"),
"boundary_dataset": boundary_dataset, "area_id": area_id,
"building_dataset": building_dataset, "area_name": area.get("name"),
"boundary_dataset_id": str(boundary_dataset["id"]),
"boundary_feature_count": boundary_dataset.get("feature_count"),
"building_dataset_id": str(building_dataset["id"]),
"building_feature_count": building_dataset.get("feature_count"),
} }