feat(web): say what reconciliation did, and never claim a second opinion that was not there
CI / Lint / Test / Vet (pull_request) Successful in 21s
CI / Build & Import (pull_request) Skipped
CI / Deploy via GitOps (pull_request) Skipped

Reconciled: the two engines, the deciding model and the exact counts; the contested
spots (changed or uncertain) listed with a minute mark and both readings, the first
50 shown and the rest counted from the exact totals. Single-engine and
model-unavailable results say why. A nil reconciliation renders nothing. Readings are
escaped. Mutation-checked: the cap, the minute rounding and the 'more' count.

uploads.go and the templ pair are one commit: the helpers and the template need each other.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-01 23:23:39 +02:00
co-authored by Claude Sonnet 5.5
parent d6ba11d288
commit 6fb7a52980
3 changed files with 390 additions and 18 deletions
+25
View File
@@ -3,7 +3,9 @@ package web
import (
"context"
"errors"
"fmt"
"io"
"math"
"net/http"
"path/filepath"
"strings"
@@ -271,3 +273,26 @@ func (a *App) uploadChatView(u domain.UploadedTranscript, model string, history
Subject: "recording",
}
}
// maxSpotsShown is how many contested spots the page lists. The stored list holds up to
// 200 and the counts are exact; a page of two hundred "check this" items is not a page
// anyone reads, so the rest are counted, not listed.
const maxSpotsShown = 50
// minuteMark renders where in the recording a spot is, as the nearest minute.
func minuteMark(seconds float64) string {
return fmt.Sprintf("~%d min", int(math.Round(seconds/60)))
}
// shownSpots is the part of the contested list the page renders.
func shownSpots(r *domain.Reconciliation) []domain.ContestedSpot {
if len(r.Contested) > maxSpotsShown {
return r.Contested[:maxSpotsShown]
}
return r.Contested
}
// moreSpots is how many spots to check are not listed, from the exact counts.
func moreSpots(r *domain.Reconciliation) int {
return max(0, r.Changed+r.Unsure-len(shownSpots(r)))
}