From 84c2e1e5185020382ecdd5ed6da456958a8f256a Mon Sep 17 00:00:00 2001 From: Matthew Valancy Date: Fri, 19 Jun 2026 03:16:36 -0700 Subject: [PATCH] fix(dashboard): headline the newest available run, not a dead re-stamp The dashboard set `latest` to merged[0] unconditionally, so when the newest run is a cached re-stamp with no report.json on disk (available:false) the headline pointed at a run whose drill-down 404s. Add a pure pickLatest() helper that prefers the newest available run, falling back to newest overall. Co-Authored-By: Claude Opus 4.8 (1M context) --- tests/lib/dashboard/dashboard.test.mjs | 9 ++++++++- tests/lib/dashboard/history.mjs | 12 ++++++++++++ tests/lib/dashboard/server.mjs | 4 ++-- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/tests/lib/dashboard/dashboard.test.mjs b/tests/lib/dashboard/dashboard.test.mjs index 6b47c671..6221bcaf 100644 --- a/tests/lib/dashboard/dashboard.test.mjs +++ b/tests/lib/dashboard/dashboard.test.mjs @@ -8,7 +8,7 @@ import { rollupStatus, fmtDuration, fmtBytes, pct, decodeMungedName, esc, STATUS import { niceMax, bounds, lineChart, statusBar, sparkline } from './charts.mjs'; import { isUnifiedReport, runIdFor, summarize, mediaCount, safeId } from './ingest.mjs'; import { reportMetrics, scaleSweepMetrics, largeGraphMetrics, physicsMetrics, vlmMetrics, pointKey } from './metrics.mjs'; -import { mergeRuns, mergeMetrics, readJsonl, appendJsonl, snapshotRun, pruneSnapshots } from './history.mjs'; +import { mergeRuns, mergeMetrics, readJsonl, appendJsonl, snapshotRun, pruneSnapshots, pickLatest } from './history.mjs'; // ── format ──────────────────────────────────────────────────────────────── test('rollupStatus: worst-of precedence', () => { @@ -186,6 +186,13 @@ test('mergeRuns tie-breaks equal finishedAt deterministically by runId', () => { const { merged } = mergeRuns([], [{ runId: 'b', finishedAt: 5 }, { runId: 'a', finishedAt: 5 }]); assert.deepEqual(merged.map((r) => r.runId), ['a', 'b']); }); +test('pickLatest prefers newest available run, skips re-stamped/unavailable headline', () => { + assert.equal(pickLatest([]), null); + assert.equal(pickLatest(null), null); + assert.equal(pickLatest([{ runId: 'r2', available: false }, { runId: 'r1', available: true }]), 'r1'); + assert.equal(pickLatest([{ runId: 'r2', available: true }, { runId: 'r1', available: true }]), 'r2'); + assert.equal(pickLatest([{ runId: 'r2', available: false }, { runId: 'r1', available: false }]), 'r2'); +}); test('mergeMetrics dedupes by key', () => { const { merged, added } = mergeMetrics([{ key: 'a' }], [{ key: 'a' }, { key: 'b' }, { key: 'b' }]); assert.equal(merged.length, 2); diff --git a/tests/lib/dashboard/history.mjs b/tests/lib/dashboard/history.mjs index c5fa89bf..707f256c 100644 --- a/tests/lib/dashboard/history.mjs +++ b/tests/lib/dashboard/history.mjs @@ -24,6 +24,18 @@ export function mergeRuns(existing, incoming) { return { merged, added }; } +/** + * Pick the headline "latest" run for the dashboard. Runs come in newest-first + * (as mergeRuns sorts them). Prefer the newest run whose report is actually on + * disk (available) so the headline never points at a re-stamped/cached entry + * that 404s on drill-down; fall back to the newest run overall, else null. + */ +export function pickLatest(runs) { + if (!Array.isArray(runs) || !runs.length) return null; + const available = runs.find((r) => r && r.available); + return (available || runs[0]).runId; +} + export function mergeMetrics(existing, incoming) { const seen = new Set(existing.map((m) => m.key)); const added = []; diff --git a/tests/lib/dashboard/server.mjs b/tests/lib/dashboard/server.mjs index c6255222..ee970c82 100644 --- a/tests/lib/dashboard/server.mjs +++ b/tests/lib/dashboard/server.mjs @@ -16,7 +16,7 @@ import { resolve, join, sep, extname } from 'node:path'; import { spawn } from 'node:child_process'; import { discover, signature, safeId, summarize } from './ingest.mjs'; import { reportMetrics, scanPerfArtifacts } from './metrics.mjs'; -import { mergeRuns, mergeMetrics, readJsonl, appendJsonl, snapshotRun, pruneSnapshots } from './history.mjs'; +import { mergeRuns, mergeMetrics, readJsonl, appendJsonl, snapshotRun, pruneSnapshots, pickLatest } from './history.mjs'; import { renderShell } from './page.mjs'; const args = process.argv.slice(2); @@ -104,7 +104,7 @@ function reindex() { const allMetrics = readJsonl(METRICS_JSONL); state = { generatedAt: Date.now(), - latest: merged[0] ? merged[0].runId : null, + latest: pickLatest(merged), runs: merged, metrics: allMetrics.slice(-6000), roots: ROOTS.map((r) => ({ name: r.name, label: r.label, mode: r.mode, exists: existsSync(r.path), count: discovered.filter((d) => d.source === r.name).length })),