feat: add measured detection review loop
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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`
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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`
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user