Prefer governed orthophoto editions in source status
This commit is contained in:
@@ -28,6 +28,9 @@
|
||||
- Made staged, reviewed and applied release evidence write-once. An idempotent
|
||||
apply validates and reuses the existing evidence instead of changing its
|
||||
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)
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ from collections import defaultdict
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from pathlib import Path
|
||||
import re
|
||||
from typing import Iterable
|
||||
from uuid import UUID
|
||||
|
||||
@@ -51,6 +52,7 @@ SOURCE_POLICIES: dict[str, SourcePolicy] = {
|
||||
}
|
||||
|
||||
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:
|
||||
@@ -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]
|
||||
if not versioned:
|
||||
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":
|
||||
named_current = [
|
||||
item
|
||||
@@ -258,7 +266,7 @@ class SourceFreshnessService:
|
||||
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_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,
|
||||
review_interval_days=policy.review_interval_days,
|
||||
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"
|
||||
|
||||
|
||||
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:
|
||||
first = _dataset(
|
||||
"dov_soil_map",
|
||||
|
||||
@@ -9791,13 +9791,49 @@ Implemented:
|
||||
the original checksum-bound evidence and never rewrite approval history.
|
||||
|
||||
Validation so far:
|
||||
- 38 focused Sprint 222/230/231 tests pass with deprecations treated as errors.
|
||||
Coverage includes official-edition ordering, first-baseline authorization,
|
||||
GetMap allowlisting/limits, RGB/CRS normalization, preview generation,
|
||||
tampering, preflight drift, named review, loopback-only apply and complete
|
||||
upload provenance.
|
||||
- 48 focused Sprint 221/222/230/231 tests pass. The release-management suite
|
||||
contains 11 direct plan/stage/review/apply tests. Coverage includes
|
||||
official-edition ordering in both catalog and source-freshness views,
|
||||
first-baseline authorization, GetMap allowlisting/limits, RGB/CRS
|
||||
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:
|
||||
- Run complete readiness, deploy the packaged operator to Tower, inspect the
|
||||
live bounded Mol review preview and only then apply the first official
|
||||
`2025.04` immutable baseline with explicit review evidence.
|
||||
- Surface the existing release evidence read-only in the operator Status
|
||||
workspace so official/local edition, review identity, Dataset ID and hash
|
||||
integrity can be inspected without shell access. Keep all refresh actions
|
||||
operator-only and outside the browser.
|
||||
|
||||
Reference in New Issue
Block a user