diff --git a/.changeset/dashboard-surfaces-verdict-source.md b/.changeset/dashboard-surfaces-verdict-source.md new file mode 100644 index 0000000000..e7fa44366d --- /dev/null +++ b/.changeset/dashboard-surfaces-verdict-source.md @@ -0,0 +1,31 @@ +--- +--- + +Dashboard `/dashboard/agents` surfaces the new `verdict_source` field on the +compliance tile and a per-run "Your test / Heartbeat / Manual / Webhook" +badge in the History panel. PR 2 of the #4247 unification stack โ€” +read-side cleanup that lets owners distinguish their own on-demand +runs from scheduled heartbeat verdicts at a glance. + +**Context.** PR #4250 added `verdict_source` to +`/api/registry/agents/:url/compliance` and `triggered_by` to each row +returned by `/api/registry/agents/:url/compliance/history`. Both fields +were unrendered in the dashboard until this PR. + +**What changes.** + +- Compliance tile shows `Last checked: 3m ago (your test)` / + `(heartbeat)` / `(manual)` / `(webhook)` after the timestamp. Empty + string when `verdict_source` is null (never run). +- History panel renders a colored badge per run row: + - `Your test` (info-blue) for `triggered_by = 'owner_test'` + - `Heartbeat` (neutral) for `triggered_by = 'heartbeat'` + - `Manual` / `Webhook` (neutral) for the other enum values + +No backend changes; this is pure UI surfacing of fields the API already +emits. Pre-PR-1 rows (which only have `'heartbeat'` / `'manual'` / +`'webhook'`) render with the neutral badge โ€” no regression. + +**Out of scope** (PR 3 of #4247): dropping `agent_test_history` and +backfilling owner-triggered rows. Tracked separately so the destructive +migration soaks behind the read-only UI change. diff --git a/server/public/dashboard-agents.html b/server/public/dashboard-agents.html index 810869c513..856fab7e9d 100644 --- a/server/public/dashboard-agents.html +++ b/server/public/dashboard-agents.html @@ -1501,6 +1501,19 @@

Agents

? timeAgo(new Date(cs.last_checked_at)) : 'never'; + // Surface the verdict source so the operator knows whether the + // current status came from the scheduled heartbeat or their own + // owner-triggered test run. PR #4250 populates cs.verdict_source + // ('heartbeat' | 'owner_test' | 'manual' | 'webhook' | null when + // never run). Displayed inline with "Last checked" so the + // semantic shift on the public compliance contract is visible + // to the operator without having to read the changelog. + const verdictSourceLabel = cs.verdict_source === 'owner_test' ? ' (your test)' + : cs.verdict_source === 'heartbeat' ? ' (heartbeat)' + : cs.verdict_source === 'manual' ? ' (manual)' + : cs.verdict_source === 'webhook' ? ' (webhook)' + : ''; + const isPublic = cs.status !== 'opted_out'; return ` @@ -1527,7 +1540,7 @@

Agents

${visibilitySelectorHtml}
- Last checked: ${escapeHtml(lastChecked)} + Last checked: ${escapeHtml(lastChecked)}${escapeHtml(verdictSourceLabel)}
'; if (runTracks) { html += '
' + runTracks + '
';