feat: built-in read-only dashboard at /ui + GET /runs
Build & push image / build-and-push (push) Successful in 26s
CI / test (push) Successful in 10m24s

Serves a self-contained vanilla-JS dashboard (embedded via go:embed): a per-model performance table — runs, minutes, findings, confirmed/false-positive/ungraded, points, points-per-minute, points-per-run, by-severity — with drill-down filters (date range, repo, provider, model, lens, grade/severity), free-text search, and a click-to-scope findings detail table.

Scoring stays client-side: the page has an editable points curve and computes points + value-per-minute in the browser, so the store remains point-free. Adds GET /runs (lists all runs, incl. zero-finding ones) so minutes/runs are filterable. The /ui shell is public (carries no data); data endpoints stay token-gated and the JS sends the token.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-27 00:22:39 -04:00
parent 9458528b40
commit 35ebc53561
6 changed files with 460 additions and 12 deletions
+39
View File
@@ -137,6 +137,7 @@ type Run struct {
InputTokens *int64 `json:"input_tokens,omitempty"`
OutputTokens *int64 `json:"output_tokens,omitempty"`
CostUSD *float64 `json:"cost_usd,omitempty"`
CreatedAt string `json:"created_at,omitempty"` // set on read by ListRuns; ignored by AddRun
}
// AddRun upserts a run by run_id (a re-posted run overwrites timing/tokens).
@@ -156,6 +157,44 @@ ON CONFLICT(run_id) DO UPDATE SET
return err
}
// ListRuns returns every run (oldest first), including runs that produced no
// findings — so a dashboard can charge a model for all the time it spent, not
// just the runs that surfaced something. Read-only.
func (s *Store) ListRuns() ([]Run, error) {
rows, err := s.db.Query(`
SELECT run_id, repo, pr, model, provider, lenses, duration_secs, input_tokens, output_tokens, cost_usd, created_at
FROM runs ORDER BY created_at, run_id`)
if err != nil {
return nil, err
}
defer rows.Close()
var out []Run
for rows.Next() {
var r Run
var in, outTok sql.NullInt64
var cost sql.NullFloat64
if err := rows.Scan(&r.RunID, &r.Repo, &r.PR, &r.Model, &r.Provider, &r.Lenses,
&r.DurationSecs, &in, &outTok, &cost, &r.CreatedAt); err != nil {
return nil, err
}
if in.Valid {
v := in.Int64
r.InputTokens = &v
}
if outTok.Valid {
v := outTok.Int64
r.OutputTokens = &v
}
if cost.Valid {
v := cost.Float64
r.CostUSD = &v
}
out = append(out, r)
}
return out, rows.Err()
}
// ReportIn is one finding as a single model reported it.
type ReportIn struct {
Repo string `json:"repo"`