Prefer governed orthophoto editions in source status
GeoIntel CI / docs-smoke (push) Canceled after 0s
GeoIntel CI / contract-smoke (push) Canceled after 0s

This commit is contained in:
Codex
2026-07-17 02:33:15 +02:00
parent 0c2ebc1ffc
commit 0befca02f8
4 changed files with 84 additions and 10 deletions
+3
View File
@@ -28,6 +28,9 @@
- Made staged, reviewed and applied release evidence write-once. An idempotent - Made staged, reviewed and applied release evidence write-once. An idempotent
apply validates and reuses the existing evidence instead of changing its apply validates and reuses the existing evidence instead of changing its
timestamp or authorization history. timestamp or authorization history.
- Made the read-only source-freshness audit prefer the governed official
`YYYY.NN` orthophoto edition over retained legacy `most_recent_at_*` labels,
while preserving the existing rolling-source review interval.
## Sprint 230 Governed orthophoto release preflight (2026-07-17) ## Sprint 230 Governed orthophoto release preflight (2026-07-17)
@@ -4,6 +4,7 @@ from collections import defaultdict
from dataclasses import dataclass from dataclasses import dataclass
from datetime import datetime, timedelta, timezone from datetime import datetime, timedelta, timezone
from pathlib import Path from pathlib import Path
import re
from typing import Iterable from typing import Iterable
from uuid import UUID from uuid import UUID
@@ -51,6 +52,7 @@ SOURCE_POLICIES: dict[str, SourcePolicy] = {
} }
DEFAULT_POLICY = SourcePolicy("Niet-geclassificeerde bron", "edition") DEFAULT_POLICY = SourcePolicy("Niet-geclassificeerde bron", "edition")
_ORTHOPHOTO_EDITION = re.compile(r"^20\d{2}\.\d{2}$")
def _as_utc(value: datetime | None) -> datetime | None: def _as_utc(value: datetime | None) -> datetime | None:
@@ -81,10 +83,16 @@ def _latest_dataset(datasets: list[Dataset]) -> Dataset:
) )
def _latest_source_version(policy: SourcePolicy, datasets: list[Dataset]) -> str | None: def _latest_source_version(source_name: str, policy: SourcePolicy, datasets: list[Dataset]) -> str | None:
versioned = [item for item in datasets if item.source_version] versioned = [item for item in datasets if item.source_version]
if not versioned: if not versioned:
return None return None
if source_name == "digitaal_vlaanderen_orthophoto":
official_editions = [
item for item in versioned if _ORTHOPHOTO_EDITION.fullmatch((item.source_version or "").strip())
]
if official_editions:
return _latest_dataset(official_editions).source_version
if policy.refresh_policy == "rolling_snapshot": if policy.refresh_policy == "rolling_snapshot":
named_current = [ named_current = [
item item
@@ -258,7 +266,7 @@ class SourceFreshnessService:
version_count=sum(len(versions_by_dataset.get(item.id, [])) for item in source_datasets), version_count=sum(len(versions_by_dataset.get(item.id, [])) for item in source_datasets),
latest_imported_at=_latest_datetime(item.imported_at for item in source_datasets), latest_imported_at=_latest_datetime(item.imported_at for item in source_datasets),
latest_observed_at=_latest_datetime(item.observed_at for item in source_datasets), latest_observed_at=_latest_datetime(item.observed_at for item in source_datasets),
latest_source_version=_latest_source_version(policy, source_datasets), latest_source_version=_latest_source_version(source_name, policy, source_datasets),
refresh_policy=policy.refresh_policy, refresh_policy=policy.refresh_policy,
review_interval_days=policy.review_interval_days, review_interval_days=policy.review_interval_days,
next_review_at=next_review_at, next_review_at=next_review_at,
@@ -157,6 +157,33 @@ def test_rolling_orthophoto_prefers_explicit_current_snapshot_over_historical_ob
assert report.items[0].latest_source_version == "most_recent_at_2026-07-14" assert report.items[0].latest_source_version == "most_recent_at_2026-07-14"
def test_orthophoto_freshness_prefers_governed_official_edition_over_rolling_marker() -> None:
legacy = _dataset(
"digitaal_vlaanderen_orthophoto",
imported_at=NOW - timedelta(days=2),
observed_at=datetime(2026, 7, 15, tzinfo=timezone.utc),
source_version="most_recent_at_2026-07-15",
)
official = _dataset(
"digitaal_vlaanderen_orthophoto",
imported_at=NOW - timedelta(days=1),
observed_at=datetime(2025, 4, 5, tzinfo=timezone.utc),
source_version="2025.04",
)
report = SourceFreshnessService.build_report(
legacy.project_id,
[legacy, official],
[_version(legacy), _version(official)],
now=NOW,
)
item = report.items[0]
assert item.latest_source_version == "2025.04"
assert item.refresh_policy == "rolling_snapshot"
assert item.review_interval_days == 180
def test_spatial_partitions_do_not_become_a_false_historical_series() -> None: def test_spatial_partitions_do_not_become_a_false_historical_series() -> None:
first = _dataset( first = _dataset(
"dov_soil_map", "dov_soil_map",
+44 -8
View File
@@ -9791,13 +9791,49 @@ Implemented:
the original checksum-bound evidence and never rewrite approval history. the original checksum-bound evidence and never rewrite approval history.
Validation so far: Validation so far:
- 38 focused Sprint 222/230/231 tests pass with deprecations treated as errors. - 48 focused Sprint 221/222/230/231 tests pass. The release-management suite
Coverage includes official-edition ordering, first-baseline authorization, contains 11 direct plan/stage/review/apply tests. Coverage includes
GetMap allowlisting/limits, RGB/CRS normalization, preview generation, official-edition ordering in both catalog and source-freshness views,
tampering, preflight drift, named review, loopback-only apply and complete first-baseline authorization, GetMap allowlisting/limits, RGB/CRS
upload provenance. normalization, preview generation, tampering, preflight drift, named review,
loopback-only apply and complete upload provenance.
- Complete local readiness passed with 878 backend tests, 110 documented
routes, one Alembic head `202607160001`, frontend typecheck and production
build. Target compile and Ruff checks also passed.
Live validation:
- Commits `06d05f0` and `0c2ebc1` were pushed, deployed through the repository
to Tower and validated against PostGIS 3.6. The all-in-one container became
healthy on port 1202 and passed migrations, schema/collation, API proxy and
browser shell checks.
- The packaged operator staged official edition `2025.04` for bbox
`5.110,51.180,5.117,51.185`: one 921,848-byte official WMS response became a
496x562, three-band EPSG:31370 GeoTIFF at an approximately one-metre grid.
All 20 deterministic flight-day samples reported `2025-04-05`.
- The generated preview was visually inspected as a complete RGB orthophoto
with expected Mol roads, buildings and sports context. Named review bound
plan SHA-256 `c6cefd19dc60d7469b4885d9d1f5eff4e52a88808bbe3ac21879c5650e558662`
and review SHA-256
`9f0a3a65eb184fea7f91daa5018c0980ed03b792bd465a98c65f2add2413d90b`.
- Checksum-confirmed apply created exactly one immutable raster Dataset
`3cf14603-03da-42f5-b152-4bbecad7d006`; project total moved from 636 to 637.
Dataset, version and staged GeoTIFF share SHA-256
`f87701de6680f8ad25407996ddfd08056bf0533c05572ae489e9d478a72e7e46`.
The canonical API returns the complete request, catalog, flight-date,
reviewer and artifact provenance.
- An idempotent retry retained 637 Datasets and the same Dataset ID. A live
audit exposed that the applied-evidence timestamp could still be rewritten;
write-once validation was added, tested, redeployed and the evidence file
remained byte-identical on the next retry at SHA-256
`f4ae7b2315aed9370c8ca04dcb57eabf0c0e49c40cf63a862bb4e69bacd4b16d`.
- Browser validation at 1920x911 showed a correctly rendered MapLibre canvas,
coherent regional layer workflow, no horizontal overflow and no console
warnings or errors. A final live API audit found the generic source status
still selected a retained rolling label; source-freshness now prefers the
official edition without changing the 180-day review policy.
Next: Next:
- Run complete readiness, deploy the packaged operator to Tower, inspect the - Surface the existing release evidence read-only in the operator Status
live bounded Mol review preview and only then apply the first official workspace so official/local edition, review identity, Dataset ID and hash
`2025.04` immutable baseline with explicit review evidence. integrity can be inspected without shell access. Keep all refresh actions
operator-only and outside the browser.