feat: add measured detection review loop
GeoIntel CI / docs-smoke (push) Canceled after 0s
GeoIntel CI / contract-smoke (push) Canceled after 0s

This commit is contained in:
Codex
2026-07-15 03:00:08 +02:00
parent 94ecd377b7
commit d22abe8e7b
27 changed files with 1578 additions and 29 deletions
+15
View File
@@ -427,6 +427,21 @@ remains available as a higher-precision legacy `0.15` choice. The older
default-promotion blocker. Every production-like run still requires persisted
QA/QC against suitable reference data.
The map-driven building workflow uses canonical footprint IoU `0.25`, matching
the promotion evidence above. A July 2026 Mol-only holdout audit compared
confidence `0.10` and `0.15` over Achterbos, Gompel, Donk and Postel. Confidence
`0.15` produced the better F1 in all four positive zones; both thresholds
produced zero detections in the pure-empty Postel forest control. The active
confidence therefore remains `0.15`. This result does not claim production
perfection and does not justify another model-training run by itself.
False-positive and false-negative evidence from persisted detection QA can be
classified through `detection_reviews`. The queue derives from quality-check
evidence ids and resolves persisted Detection and reference VectorFeature rows.
`qa_alignment_mismatch`, `reference_gap_or_change`, uncertain imagery and
unreviewed items must never be exported as hard-negative or missed-positive
training labels. Canonical QA metrics remain unchanged after review.
The persisted seven-AOI evidence for this profile contains 5,568 false
positives among 13,613 candidate detections. The read-only audit command in
`scripts/README.md` reports the largest review volumes in Turnhout, Herentals
+65
View File
@@ -1300,6 +1300,71 @@ candidate evidence exposes the equivalent persisted model/source fields plus
`segmentation_id`, `mask_path` and `area_m2`. These are additive GeoJSON
properties; the canonical envelope and endpoint path are unchanged.
For detection QA, false-positive and false-negative evidence properties also
include `review_decision`, `review_notes`, `reviewed_by` and `reviewed_at`.
Missing review rows are represented as `review_decision=unreviewed`. Evidence
resolution is bounded to identifiers stored by the selected quality check.
### GET `/api/v1/projects/{project_id}/quality-checks/{quality_check_id}/reviews`
Returns the paginated operator review queue for a persisted
`detections_vs_reference` quality check. Optional query parameters are
`evidence_role=false_positive|false_negative`, `decision`, `reviewed=true|false`,
`limit` (1-200) and `offset`. Items derive only from persisted QA evidence.
```json
{
"data": {
"items": [{
"id": null,
"project_id": "uuid",
"quality_check_id": "uuid",
"analysis_run_id": "uuid",
"evidence_role": "false_positive",
"evidence_feature_id": "detection-uuid",
"detection_id": "detection-uuid",
"decision": "unreviewed",
"confidence": 0.62,
"class_name": "building"
}],
"total": 1,
"limit": 50,
"offset": 0,
"summary": {
"total": 73,
"reviewed": 0,
"remaining": 73,
"false_positive_total": 17,
"false_negative_total": 56,
"decision_counts": {"unreviewed": 73}
}
}
}
```
### POST `/api/v1/projects/{project_id}/quality-checks/{quality_check_id}/reviews`
Creates or updates one durable operator decision. The evidence id must belong
to the quality check and resolve to the persisted Detection or reference
VectorFeature. False-positive and false-negative roles accept only their
role-specific decisions.
```json
{
"evidence_role": "false_positive",
"evidence_feature_id": "detection-uuid",
"decision": "qa_alignment_mismatch",
"notes": "The detection box overlaps the irregular GRB footprint.",
"reviewed_by": "operator"
}
```
Allowed decisions are `confirmed_model_false_positive`,
`confirmed_model_false_negative`, `reference_gap_or_change`,
`qa_alignment_mismatch`, `imagery_obscured_or_uncertain`, `uncertain` and
`unreviewed`. Invalid role/decision combinations return
`INVALID_DETECTION_REVIEW_DECISION`.
## Exports
### POST `/api/v1/exports/geojson`
+37
View File
@@ -8135,3 +8135,40 @@ Next:
- Add a review workflow for accepted/rejected detections and use those audited
labels as the gate for model calibration or retraining. Do not present the
current F1 score as production-grade accuracy.
## Sprint 197 - Measured detection accuracy and durable review (2026-07-15)
Implemented:
- Added first-class `detection_reviews` persistence linked to Project,
QualityCheck, AnalysisRun, Detection and reference VectorFeature, with
role-constrained decisions and one durable row per evidence item.
- Added canonical paginated GET/POST review endpoints and a frontend review
queue with role/status filters, notes, summary counts and map handoff.
- Changed map-driven detection QA from generic UI IoU `0.50` to the documented
box-versus-footprint operational IoU `0.25`.
- Reworded map output as candidates and exposed persisted matches, precision,
recall, F1, false positives and false negatives.
- Bounded evidence lookup to persisted evidence ids; complete regional GRB
layers are no longer materialized for a small review overlay.
Live model evidence before deployment:
- Re-ran the active model at confidence `0.10` and `0.15` on Mol Achterbos,
Gompel, Donk and Postel with QA IoU `0.25`.
- Confidence `0.15` won F1 in all four positive holdouts: `0.6694`, `0.6564`,
`0.5894` and `0.4749`. Confidence `0.10` measured `0.6287`, `0.6348`,
`0.5636` and `0.4435` respectively.
- Both thresholds produced zero detections on the pure-empty Postel forest
control. The active confidence remains `0.15`; no model or asset was trained,
downloaded or promoted.
Validation before deployment:
- The complete readiness gate passed 592 backend tests, the API/document audit
for 88 implemented routes, backend compilation, one Alembic head, offline
migration SQL generation, frontend typecheck/build and shell smoke checks.
- Focused review/evidence regressions passed and the production bundle retained
separate React, application and MapLibre chunks.
Next:
- Deploy the migration and UI, verify one live review queue and map QA result,
then complete representative manual decisions before constructing any new
model-training corpus.
+22
View File
@@ -196,6 +196,28 @@ diagnostic reference-envelope comparison are persisted in the existing
`quality_checks.findings_json`; `parameters_json.coverage_policy` records the
evaluation policy used for reproducibility.
### detection_reviews
- `id uuid primary key`
- `project_id uuid references projects(id) on delete cascade`
- `quality_check_id uuid references quality_checks(id) on delete cascade`
- `analysis_run_id uuid nullable references analysis_runs(id) on delete set null`
- `evidence_role text not null` (`false_positive` or `false_negative`)
- `evidence_feature_id text not null`
- `detection_id uuid nullable references detections(id) on delete set null`
- `reference_feature_id uuid nullable references vector_features(id) on delete set null`
- `decision text not null default 'unreviewed'`
- `notes text nullable`
- `reviewed_by text not null default 'operator'`
- `created_at timestamptz`
- `updated_at timestamptz`
The unique key is `(quality_check_id, evidence_role, evidence_feature_id)`.
Indexes cover project, quality check, analysis run and decision. Reviews
classify persisted QA evidence only; they do not replace or modify Detection,
VectorFeature, QualityCheck or Metric records. Unreviewed, reference-gap,
imagery-uncertain and QA-alignment cases are not training labels.
### exports
- `id uuid primary key`
+4
View File
@@ -46,6 +46,10 @@ This file now starts with the current implementation status. Older preparation/b
- [x] Clip detection QA populations to persisted raster/tile coverage and add box-to-footprint matching diagnostics before reconsidering model training.
- [x] Add a coverage-aware Mol multi-zone benchmark report with explicit positive-zone, per-zone collapse, reference-coverage and pure-empty background gates.
- [x] Execute the refreshed coverage-aware Mol operational benchmark against the active local model and record the resulting retain/review decision.
- [x] Align map-driven building QA with footprint IoU `0.25` and show measured candidate/match/error metrics instead of calling every detection a building.
- [x] Persist paginated false-positive/false-negative operator decisions and expose them in the Quality workspace.
- [x] Bound QA evidence resolution to persisted evidence ids instead of loading complete regional reference datasets.
- [x] Compare confidence `0.10` and `0.15` over independent Mol holdouts; retain `0.15` because it wins F1 in every positive zone while both pass the empty-background control.
- [ ] Complete manual decisions for the generated 48 false-negative and 48 false-positive review cards before constructing any new training corpus.
- [x] Backend FastAPI foundation, health endpoint and service structure.
- [x] React/TypeScript frontend foundation and MapLibre workbench.