let an operator's adjudication reach the score
The review vocabulary already separates a model error from a reference gap, because the product's position is that official footprints are not automatically perfect ground truth. Those verdicts were only counted. An operator who inspected forty false positives and established that twelve are buildings the reference simply lacks still saw a precision counting all forty against the model — a number they had personally disproved, on the panel where they disproved it. Applying the verdicts gives an adjudicated score reported next to the raw one, so nothing is quietly improved. Not being able to judge is not evidence in the model's favour, so uncertain and obscured verdicts keep counting, as does a decision from a later release that this runtime does not recognise. Because part of the evidence is usually still unreviewed, the honest form is an interval rather than a single corrected number: pessimistic assumes every unreviewed finding is a model error, optimistic assumes none is, and the headline equals the pessimistic reading so a partly reviewed check never presents as a settled one. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -51,6 +51,10 @@ function shortId(value: string): string {
|
||||
return value.length > 18 ? `${value.slice(0, 8)}...${value.slice(-6)}` : value
|
||||
}
|
||||
|
||||
function formatScore(value: number | null | undefined): string {
|
||||
return typeof value === 'number' && Number.isFinite(value) ? value.toFixed(3) : 'n.v.t.'
|
||||
}
|
||||
|
||||
export function DetectionReviewPanel({
|
||||
projectId,
|
||||
qualityCheckId,
|
||||
@@ -132,6 +136,30 @@ export function DetectionReviewPanel({
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{queue?.summary.reviewed_metrics ? (
|
||||
<div className="detection-review-adjudicated" aria-label="Score na beoordeling">
|
||||
<div className="summary-grid">
|
||||
<div>
|
||||
<span>Precisie zoals gemeten</span>
|
||||
<strong>{formatScore(queue.summary.reviewed_metrics.raw.precision)}</strong>
|
||||
</div>
|
||||
<div>
|
||||
<span>Precisie na uw beoordeling</span>
|
||||
<strong>{formatScore(queue.summary.reviewed_metrics.adjudicated.precision)}</strong>
|
||||
</div>
|
||||
<div>
|
||||
<span>Herkenningsgraad na beoordeling</span>
|
||||
<strong>{formatScore(queue.summary.reviewed_metrics.adjudicated.recall)}</strong>
|
||||
</div>
|
||||
</div>
|
||||
<p className="geo-data-notice">
|
||||
{queue.summary.reviewed_metrics.review_complete
|
||||
? `Alle bevindingen zijn beoordeeld. ${queue.summary.reviewed_metrics.false_positive_breakdown.exonerated} onterecht gevonden objecten en ${queue.summary.reviewed_metrics.false_negative_breakdown.exonerated} gemiste objecten bleken een hiaat in de referentielaag, niet een modelfout.`
|
||||
: `Nog ${queue.summary.reviewed_metrics.false_positive_breakdown.unreviewed + queue.summary.reviewed_metrics.false_negative_breakdown.unreviewed} bevindingen onbeoordeeld. De precisie ligt tussen ${formatScore(queue.summary.reviewed_metrics.pessimistic.precision)} en ${formatScore(queue.summary.reviewed_metrics.optimistic.precision)}; de getoonde waarde rekent elke onbeoordeelde bevinding nog als modelfout.`}
|
||||
</p>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
<div className="detection-review-filters">
|
||||
<label>
|
||||
Soort
|
||||
|
||||
@@ -1747,6 +1747,38 @@ export interface DetectionReviewRead {
|
||||
updated_at?: string | null
|
||||
}
|
||||
|
||||
export interface ReviewedScore {
|
||||
matches: number
|
||||
false_positives: number
|
||||
false_negatives: number
|
||||
precision: number | null
|
||||
recall: number | null
|
||||
f1_score: number | null
|
||||
}
|
||||
|
||||
export interface ReviewedFindingBreakdown {
|
||||
total: number
|
||||
/** Findings the operator established were not the model's error. */
|
||||
exonerated: number
|
||||
confirmed_or_inconclusive: number
|
||||
unreviewed: number
|
||||
}
|
||||
|
||||
/**
|
||||
* The score with operator verdicts applied, next to the raw one. A finding
|
||||
* adjudicated as a reference gap is not the model's error; the interval covers
|
||||
* what the unreviewed remainder could still turn out to be.
|
||||
*/
|
||||
export interface ReviewedMetrics {
|
||||
raw: ReviewedScore
|
||||
adjudicated: ReviewedScore
|
||||
pessimistic: ReviewedScore
|
||||
optimistic: ReviewedScore
|
||||
review_complete: boolean
|
||||
false_positive_breakdown: ReviewedFindingBreakdown
|
||||
false_negative_breakdown: ReviewedFindingBreakdown
|
||||
}
|
||||
|
||||
export interface DetectionReviewSummary {
|
||||
total: number
|
||||
reviewed: number
|
||||
@@ -1754,6 +1786,7 @@ export interface DetectionReviewSummary {
|
||||
false_positive_total: number
|
||||
false_negative_total: number
|
||||
decision_counts: Record<string, number>
|
||||
reviewed_metrics?: ReviewedMetrics | null
|
||||
}
|
||||
|
||||
export interface DetectionReviewList {
|
||||
|
||||
Reference in New Issue
Block a user