fix: polish measured map quality output
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:10:22 +02:00
parent d22abe8e7b
commit 2a9b48d2b5
6 changed files with 33 additions and 4 deletions
+3
View File
@@ -29,6 +29,9 @@
envelopes, bounded evidence access and the map QA threshold.
- Passed the complete readiness gate with 592 backend tests, 88 documented API
routes, one Alembic head and a green frontend typecheck/production build.
- Live browser validation caught and fixed cramped map-result metric cells;
quality values now use a readable two-column layout and the map legend calls
unverified model output `AI-kandidaten`.
## Sprint 196 Map-driven official orthophoto analysis (2026-07-15)
@@ -248,6 +248,7 @@ def test_map_detection_qa_uses_documented_footprint_threshold_and_honest_labels(
assert "kandidaten" in hook
assert "precision" in hook.lower()
assert "false, iouThreshold" in app_source
assert "AI-kandidaten" in (ROOT / "frontend" / "src" / "components" / "map" / "MapWorkspace.tsx").read_text(encoding="utf-8")
assert "VectorFeature.id.in_(uuid_identifiers)" in evidence_service
assert "VectorFeature.source_feature_id.in_(identifiers)" in evidence_service
assert "for row in db.query(VectorFeature).filter(VectorFeature.dataset_id" not in evidence_service
+20
View File
@@ -8168,6 +8168,26 @@ Validation before deployment:
- Focused review/evidence regressions passed and the production bundle retained
separate React, application and MapLibre chunks.
Live operational proof:
- Tower deployed commit `d22abe8` with AI extras enabled. The all-in-one
runtime became healthy, PostGIS 3.6 passed, Alembic reached `202607150001`,
and the new table exposed 13 columns plus six expected indexes.
- Quality check `acaca138-dbb9-4498-ae53-d0732b6270e3` returned 206 persisted
evidence geometries in 338 ms with zero unresolved ids. All 72 reviewable
false-positive/false-negative features were explicitly `unreviewed`.
- A new browser-driven 35.57 ha Mol rectangle acquired the official orthophoto,
ran the configured local YOLO model and persisted analysis run
`14f3b856-1ff0-4939-892a-3c8347a669f1` plus quality check
`087d2b6a-6d3c-4508-ab1e-da49734097c2` at IoU `0.25`.
- The live run produced 100 candidates, 73 matches, precision `0.73`, recall
`0.4965986395`, F1 `0.5910931174`, mean IoU `0.5361610234`, 27 false
positives and 74 false negatives. The UI showed these values as measured
candidates and retained the explicit `controle vereist` source warning.
- Browser audits at 1280x720 and 3440x1440 had no console warnings/errors or
horizontal overflow. The review queue rendered 50 paginated rows; the
ultrawide map used about 2,410 px. A final compact-metric fix was queued after
the 1280 px screenshot exposed cramped six-column labels.
Next:
- Deploy the migration and UI, verify one live review queue and map QA result,
then complete representative manual decisions before constructing any new
+1 -1
View File
@@ -1140,7 +1140,7 @@ export function MapWorkspace({
<span><i className="geo-legend-area" /> Werkgebied</span>
{analysisOverlayActive ? (
<>
<span><i className="geo-legend-layer geo-legend-layer-buildings" /> Gevonden gebouwen</span>
<span><i className="geo-legend-layer geo-legend-layer-buildings" /> AI-kandidaten</span>
<span><i className="geo-legend-selection" /> Selectie</span>
</>
) : analysisMode === 'evolution' && temporalComparison?.object_changes.available ? (
@@ -46,6 +46,10 @@ function qualityMetricValue(metric: MetricRead | undefined): string {
return Number.isInteger(value) ? String(value) : value.toFixed(3)
}
function qualityScoreValue(value: number | null | undefined): string {
return typeof value === 'number' && Number.isFinite(value) ? value.toFixed(3) : 'n/a'
}
function qualityStatusLabel(status: string | null | undefined): string {
if (!status || status === 'waiting') return 'nog niet uitgevoerd'
if (status === 'completed' || status === 'ok') return 'afgerond'
@@ -173,7 +177,7 @@ export function QualityResultsPanel({
</div>
<div>
<span>Laatste score</span>
<strong>{latestCheck?.score ?? 'n/a'}</strong>
<strong>{qualityScoreValue(latestCheck?.score)}</strong>
</div>
<div>
<span>Laatste status</span>
@@ -272,7 +276,7 @@ export function QualityResultsPanel({
<div>
<span>Status</span>
<strong>{selectedQualityCheck.status}</strong>
<p>Score: {selectedQualityCheck.score ?? 'n/a'}</p>
<p>Score: {qualityScoreValue(selectedQualityCheck.score)}</p>
</div>
<div>
<span>Afgerond</span>
@@ -508,7 +512,7 @@ export function QualityResultsPanel({
<div className="quality-score-row">
<div>
<span>Score</span>
<strong>{check.score ?? 'n/a'}</strong>
<strong>{qualityScoreValue(check.score)}</strong>
</div>
<div>
<span>Meetwaarden</span>
+1
View File
@@ -1872,6 +1872,7 @@ details.ai-lab-model-surface > summary strong {
.geo-image-quality-metrics {
grid-column: 1 / -1;
grid-template-columns: repeat(2, minmax(0, 1fr));
margin-top: 0.35rem;
border-top: 1px solid var(--line);
padding-top: 0.65rem;