From 7af17e8667325f0fe65a025da86cde28202c3cff Mon Sep 17 00:00:00 2001 From: Jens Date: Thu, 30 Jul 2026 04:53:19 +0200 Subject: [PATCH] Add independent Flemish low-rise calibration candidates --- docs/CODEX_EXECUTION_LOG.md | 29 +++++++++++++++++++ docs/TODO.md | 2 ++ ...ion_belgium_building_training_portfolio.py | 6 ++++ ...ion_belgium_building_training_portfolio.py | 13 +++++++++ 4 files changed, 50 insertions(+) diff --git a/docs/CODEX_EXECUTION_LOG.md b/docs/CODEX_EXECUTION_LOG.md index 1194e195..e5ce8767 100644 --- a/docs/CODEX_EXECUTION_LOG.md +++ b/docs/CODEX_EXECUTION_LOG.md @@ -3779,6 +3779,35 @@ Validation: - Add an auditable image/footprint alignment stage or select lower-parallax independent Flemish AOIs, then repeat visual QA before corpus composition. +## 2026-07-30 - V66 independent Flemish low-rise replacement audit + +### What changed + +- Added and provisioned three spatially independent Flemish low-rise calibration candidates: Zutendaal, Zoersel and Landen. +- Materialized immutable temporal corpus `building-be-v66-lowrise-temporal-r1` with manifest SHA-256 `d861da48aca40121e158e6ab243a6ccbe53e14d500a186af64b620f612935b07`. +- Applied the provider-native GRB main-building allowlist, retaining 73, 66 and 110 source instances respectively while preserving every excluded annex in label-audit evidence. +- Tested per-instance image-edge alignment, V31 detector-consensus translation, strict SAM refinement/drop and an independent YOLO-World roof vocabulary. Every generated contact sheet remained fail-closed rejected; none entered training. + +### What was tested + +- `python -m pytest tests/test_provision_belgium_building_training_portfolio.py -q` passed (`3 passed`). +- The server confirmed CUDA execution on the RTX 4080 SUPER. +- YOLO-World model SHA-256: `9b2c17ab6124a913e9b3a5c170617920d91b0f01111a8479da69f00e2cf27792`; it returned 65 low-confidence detections across 12 tiles and failed visual precision. +- The V31 consensus route accepted only Zoersel with nine agreeing pairs and failed the other two AOIs; visual review rejected the accepted shift as well. + +### What remains open + +- An independently reviewed image-visible Flemish roof-label set is still required before the national retraining loop can honestly resume. +- Protected test/background evaluation, promotion and production redeployment remain closed. + +### Known limitations + +- Orthophoto ground displacement means current GRB ground-footprint boxes are not detector-grade roof truth at IoU 0.5. Automatic proposal models tested here do not reach the required visual precision. + +### Next recommended pass + +- Obtain or annotate image-visible roof boxes independently of the release candidate, freeze their checksums and human acceptance evidence, then rebuild and retrain the national corpus. + ## Post-V1 national coverage completion: Wallonia (2026-07-22) - Located and live-validated the stable official WALOUS 2018 GeoTIFF diff --git a/docs/TODO.md b/docs/TODO.md index 22d177e9..6ae6c410 100644 --- a/docs/TODO.md +++ b/docs/TODO.md @@ -11,6 +11,8 @@ Uitvoeringsbord: `docs/PYTORCH_TRAINING_ROADMAP_BELGIUM.md`. - [x] Verwerp de drie V64 Vlaamse kalibratiekandidaten fail-closed na gereproduceerde ruwe en SAM2-contact-sheets; verscherp de geometrische SAM2-gates. - [x] Scheid GRB-hoofdgebouwen bron-native van bijgebouwen en bewijs dat ook de hoofdgebouw/SAM-dropvariant de visuele gate nog niet haalt. - [ ] Lever onafhankelijke Vlaamse kalibratie-AOI's met aantoonbaar beeldzichtbare daklabels vóór een volgende training. + - [x] Provision en audit onafhankelijke V66-laagbouwkandidaten in Zutendaal, Zoersel en Landen; verwerp alle automatische labelvarianten na visuele QA. + - [ ] Laat beeldzichtbare Vlaamse dakboxen onafhankelijk annoteren/reviewen en freeze hun checksums. - [ ] Train en evalueer een Belgische gebouwchallenger onafhankelijk; promoveer alleen zonder achtergrondregressie. - [ ] Houd zonnepanelen en segmentatie `not_configured` tot gereviewde taaklabels en hold-outs bestaan. diff --git a/scripts/provision_belgium_building_training_portfolio.py b/scripts/provision_belgium_building_training_portfolio.py index ee0f4e58..6da265f0 100644 --- a/scripts/provision_belgium_building_training_portfolio.py +++ b/scripts/provision_belgium_building_training_portfolio.py @@ -141,6 +141,12 @@ AOIS = ( Aoi("aarschot-mixed-cal-candidate-v63", "flanders", "mixed-urban", "train", 4.837, 50.985), Aoi("beveren-ribbon-cal-candidate-v63", "flanders", "ribbon-development", "train", 4.256, 51.212), Aoi("oostkamp-suburban-cal-candidate-v63", "flanders", "suburban", "train", 3.226, 51.154), + # v66 replacement candidates after V63/V65 visual QA rejected dense, + # parallax-heavy labels. These spatially independent low-rise contexts + # intentionally reduce roof displacement and instance ambiguity. + Aoi("zutendaal-lowrise-cal-candidate-v66", "flanders", "detached-lowrise", "train", 5.573, 50.933), + Aoi("zoersel-lowrise-cal-candidate-v66", "flanders", "detached-lowrise", "train", 4.712, 51.268), + Aoi("landen-rural-cal-candidate-v66", "flanders", "rural-lowrise", "train", 5.079, 50.746), Aoi("bruges-val", "flanders", "historic-urban", "val", 3.224, 51.209), Aoi("turnhout-val", "flanders", "suburban", "val", 4.944, 51.322), Aoi("hasselt-cal", "flanders", "suburban", "calibration", 5.340, 50.930), diff --git a/tests/test_provision_belgium_building_training_portfolio.py b/tests/test_provision_belgium_building_training_portfolio.py index bd022031..8294d127 100644 --- a/tests/test_provision_belgium_building_training_portfolio.py +++ b/tests/test_provision_belgium_building_training_portfolio.py @@ -6,6 +6,11 @@ V63_CANDIDATES = { "beveren-ribbon-cal-candidate-v63", "oostkamp-suburban-cal-candidate-v63", } +V66_CANDIDATES = { + "zutendaal-lowrise-cal-candidate-v66", + "zoersel-lowrise-cal-candidate-v66", + "landen-rural-cal-candidate-v66", +} def test_portfolio_slugs_are_unique() -> None: @@ -19,3 +24,11 @@ def test_v63_calibration_candidates_are_flemish_train_role_inputs() -> None: assert all(aoi.region == "flanders" for aoi in candidates.values()) assert all(aoi.split == "train" for aoi in candidates.values()) assert all(aoi.sample_role == "positive" for aoi in candidates.values()) + + +def test_v66_lowrise_candidates_are_flemish_train_role_inputs() -> None: + candidates = {aoi.slug: aoi for aoi in AOIS if aoi.slug in V66_CANDIDATES} + assert set(candidates) == V66_CANDIDATES + assert all(aoi.region == "flanders" for aoi in candidates.values()) + assert all(aoi.split == "train" for aoi in candidates.values()) + assert all("lowrise" in aoi.context for aoi in candidates.values())