Complete regional history live validation
GeoIntel CI / docs-smoke (push) Canceled after 0s
GeoIntel CI / contract-smoke (push) Canceled after 0s

This commit is contained in:
Codex
2026-07-16 00:01:14 +02:00
parent df015e10e0
commit 9db0ac7811
8 changed files with 77 additions and 12 deletions
+13
View File
@@ -19,6 +19,19 @@
feature limits and one canonical regional Dataset upload per theme/year.
- Extended the regional time-series coordinator and release packaging without
changing API contracts, database migrations or frontend architecture.
- Provisioned all nine snapshots on live Tower/PostGIS: 207,717 persisted
polygon features across three complete 28-municipality temporal series.
Every Dataset is ready, has one immutable DatasetVersion and was reused by
the idempotency run without duplicate persistence.
- Added the exact-area fast path for these already-clipped regional artifacts,
reducing complete-Kempen comparisons from minutes to 0.9-4.1 seconds in the
live audit while preserving the calculated values.
- Suppressed inapplicable generic line metrics for historical polygon classes;
results now show governed hectares plus object counts, never artificial
`0 km` road/watercourse measurements.
- Kept the top workbench source context synchronized with the selected
Evolution series. Browser verification covered complete Kempen, Mol and a
3440 x 1440 viewport with no console warnings or errors.
## Sprint 208 Governed VMM flood-hazard scenarios (2026-07-15)
@@ -15,7 +15,8 @@ def test_long_context_names_remain_compact_and_inspectable() -> None:
assert "selectedProject?.name === REGIONAL_WORKSPACE_PROJECT_NAME" in app
assert "? REGIONAL_WORKSPACE_LABEL" in app
assert "const datasetContextLabel = analysisMapLayerActive && mapFeatureCollection" in app
assert "const datasetContextLabel = activeWorkspace === 'map' && mapContextSourceLabel" in app
assert ": analysisMapLayerActive && mapFeatureCollection" in app
assert "? getDatasetDisplayName(selectedDataset)" in app
assert "`${mapLayerLabel} · controle vereist`" in app
assert "<strong title={projectContextLabel}>{projectContextLabel}</strong>" in app
@@ -239,6 +239,10 @@ def test_upload_contract_is_regional_temporal_and_partition_audited(tmp_path: Pa
def test_regional_historical_operator_is_packaged_and_release_checked() -> None:
dockerfile = (ROOT / "deploy/unraid/Dockerfile.all-in-one").read_text(encoding="utf-8")
readiness = (ROOT / "scripts/run_readiness_check.sh").read_text(encoding="utf-8")
app = (ROOT / "frontend/src/App.tsx").read_text(encoding="utf-8")
workspace = (ROOT / "frontend/src/components/map/MapWorkspace.tsx").read_text(encoding="utf-8")
assert "COPY scripts/provision_regional_historical_landuse.py" in dockerfile
assert "py_compile scripts/provision_regional_historical_landuse.py" in readiness
assert "onSetContextSourceLabel={setMapContextSourceLabel}" in app
assert "analysisMode === 'evolution' ? activeTemporalSeriesGroup?.label" in workspace
+37 -9
View File
@@ -8833,12 +8833,39 @@ Implemented:
- Extended `provision_regional_timeseries.py`, all-in-one packaging, readiness
compilation and operator/source documentation.
Validation evidence before live provisioning:
- Fourteen focused partition, raw-evidence, clipping, assembly, upload,
coordinator and packaging tests pass.
- The official source catalog still reports the production WFS and the three
governed historical collections. Live partition provisioning and browser
Evolution validation follow in this pass.
Validation and live evidence:
- The final release gate passes with 685 backend tests, frontend typecheck and
production build, one Alembic head (`202607150001`) and script syntax checks.
- Live Tower/PostGIS provisioning completed all 252 municipality/theme/year
partitions and nine combined snapshots. No snapshot has an empty municipal
partition. The retained regional historical audit cache is about 518 MB.
- Persisted feature counts are: buildings 14,245 / 22,036 / 69,869; water
9,010 / 13,571 / 8,188; roads 6,305 / 33,578 / 30,915 for 1778 / 1873 /
1969 respectively. Total persisted geometry count is 207,717.
- Each of the nine ready Datasets belongs to regional Area
`46ab5614-fcf8-4e63-8ea8-6049f34c14fd`, exposes one immutable
DatasetVersion/checksum and participates in one of three ordered temporal
series. A second complete operator run returned `existing` for all nine with
identical audited feature counts.
- The live audit found that the full-Area fast path did not yet recognize the
new clipped operator. Adding its governed provenance reduced exact complete-
Kempen comparisons from multi-minute redundant clipping to 4.0 s for
buildings, 0.9 s for water and 1.9 s for roads.
- Complete-Kempen 1778 -> 1969 results are 481.62 -> 1,833.23 ha built land,
1,546.89 -> 2,198.80 ha mapped water and 4,382.49 -> 6,978.12 ha mapped
roads. These are map-class surfaces, not modern footprints, centreline
lengths, bathymetry or volume.
- Browser validation selected the historical buildings series, analyzed the
complete persisted Kempen Area and then municipality Mol. Mol returned
24.35 / 32.45 / 120.81 ha for 1778 / 1873 / 1969 and explicitly disclosed
the cartographic-method and unstable-object-identity limitations.
- The irrelevant generic `0 km` metrics for polygon-only historical water and
road classes were removed. The workbench source context now follows the
selected Evolution series. Normal and 3440 x 1440 visual checks found no
overlap; browser console warnings/errors were empty.
- Each deployment passed live PostGIS 3.6 connectivity, required schema/index
checks, database collation, Alembic head `202607150001`, frontend/API proxy
and icon verification.
Known limitations:
- Historical `buildings` are mapped built land-use surfaces, not individual
@@ -8849,6 +8876,7 @@ Known limitations:
continuous equivalent to modern GRB or 10 m land-use products.
Next:
- Run the complete nine-snapshot operator on live Tower/PostGIS, verify all 28
partition manifests and then validate regional/municipality Evolution in the
browser before marking the backlog item complete.
- Keep permanent inland bathymetry blocked on a governed depth source. The
next implementation pass can focus on current-only nature/terrain/flood
regional expansion or on a benchmarked data-refresh scheduler; it must not
reinterpret these historical surfaces as modern object lineage.
+1 -1
View File
@@ -26,7 +26,7 @@
- [x] Add bounded historical orthophoto acquisition for official 1971-2025 products with a map overlay and no current-GRB QA on old imagery.
- [x] Add BWK/Natura 2000 through an explicit provider/operator contract.
- [x] Add annual agricultural-use parcels through an explicit provider/operator contract.
- [ ] Extend the official 1778/1873/1969 historical buildings, water and roads series from Mol to the approved regional scope with partitioned source audits.
- [x] Extend the official 1778/1873/1969 historical buildings, water and roads series from Mol to the approved regional scope with partitioned source audits.
- [x] Connect a drawn rectangle to bounded official orthophoto acquisition, local configured-YOLO detection and persisted GRB QA.
## Governed source expansion backlog
+5
View File
@@ -31,6 +31,11 @@ selectable and is never merged into the same trend.
Regional building, water and road evolution uses the same selector after the
partition-audited 1778/1873/1969 snapshots are provisioned. Historical built
surfaces never replace current GRB building footprints in Latest state.
The persistent top context bar follows the selected historical series while
Evolution is active, so its source label cannot disagree with the result panel.
Because these historical WFS classes are polygonal map surfaces, their metrics
are hectares plus a supporting object count; generic live road/water line
metrics are deliberately not shown.
Selection results use dataset-specific PostGIS summaries with end-user units.
Building footprints, forest, water surfaces and parcels show intersected
+5 -1
View File
@@ -65,6 +65,7 @@ function App(): JSX.Element {
const [activeWorkspace, setActiveWorkspace] = useState<WorkspaceKey>('map')
const [inspectorOpen, setInspectorOpen] = useState(false)
const [mapContentMode, setMapContentMode] = useState<'dataset' | 'analysis'>('dataset')
const [mapContextSourceLabel, setMapContextSourceLabel] = useState<string | null>(null)
useEffect(() => {
window.scrollTo({ top: 0, left: 0 })
setInspectorOpen(false)
@@ -715,7 +716,9 @@ function App(): JSX.Element {
? REGIONAL_WORKSPACE_LABEL
: selectedProject?.name ?? 'Geen werkruimte'
const areaContextLabel = selectedArea?.name ?? (areas.length > 0 ? 'Kies een gebied' : 'Geen gebied')
const datasetContextLabel = analysisMapLayerActive && mapFeatureCollection
const datasetContextLabel = activeWorkspace === 'map' && mapContextSourceLabel
? mapContextSourceLabel
: analysisMapLayerActive && mapFeatureCollection
? `${mapLayerLabel} · controle vereist`
: selectedDataset
? getDatasetDisplayName(selectedDataset)
@@ -1035,6 +1038,7 @@ function App(): JSX.Element {
selectedMapDatasetId={selectedDataset && availableMapDatasets.some((dataset) => dataset.id === selectedDataset.id) ? selectedDataset.id : ''}
selectedFeature={selectedMapFeature}
onSelectMapArea={setSelectedMapAreaId}
onSetContextSourceLabel={setMapContextSourceLabel}
onOpenDatasetInMap={openDatasetInMap}
onSetAreaLayerVisible={setAreaLayerVisible}
onSetAreaLayerOpacity={setAreaLayerOpacity}
@@ -559,6 +559,7 @@ interface MapWorkspaceProps {
availableMapDatasets: DatasetCreateResponse[]
selectedMapDatasetId: string
onSelectMapArea: (areaId: string) => void
onSetContextSourceLabel: (label: string | null) => void
onOpenDatasetInMap: (dataset: DatasetCreateResponse) => void
onSetAreaLayerVisible: (visible: boolean) => void
onSetAreaLayerOpacity: (opacity: number) => void
@@ -639,6 +640,7 @@ export function MapWorkspace({
availableMapDatasets,
selectedMapDatasetId,
onSelectMapArea,
onSetContextSourceLabel,
onOpenDatasetInMap,
onSetAreaLayerVisible,
onSetAreaLayerOpacity,
@@ -776,6 +778,14 @@ export function MapWorkspace({
const activeTemporalSeriesGroup = activeTemporalSeriesGroups.find((group) => group.key === selectedTemporalSeriesKey)
?? activeTemporalSeriesGroups[0]
const activeTemporalSeries = activeTemporalSeriesGroup?.items ?? EMPTY_TEMPORAL_SERIES
useEffect(() => {
onSetContextSourceLabel(
analysisMode === 'evolution' ? activeTemporalSeriesGroup?.label ?? null : null,
)
return () => onSetContextSourceLabel(null)
}, [activeTemporalSeriesGroup?.label, analysisMode, onSetContextSourceLabel])
const themeResults = useMemo(
() =>
themeInsights.flatMap((insight) => {