fix: preserve official Mol CRS provenance
This commit is contained in:
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user