8 Commits

Author SHA1 Message Date
josh 017c3c38fe feat(ui): 15-point UX overhaul — affordances, feedback, and navigation
CI / Lint + build + test (push) Successful in 1m43s
Release / detect (push) Successful in 6s
Release / build-live-image (push) Has been skipped
Release / bundle (push) Successful in 52s
Address friction points identified in a full interface audit:
- Re-add status badge to dashboard tiles so run state is visible at a glance
- Add active nav indicator and SSE connection health monitor (live/stale)
- Show manual registration form by default instead of hiding behind <details>
- Add copy-to-clipboard buttons on SSH hold command and quick-register one-liner
- Replace tooltip-only profile descriptions with inline visible text
- Clarify non-destructive toggle with explicit stage impact description
- Replace disabled "Start vetting" button with actionable offline guidance
- Swap browser confirm() dialogs for styled inline confirmations
- Add colored badge to spec diffs summary visible when collapsed
- Add distinct "cancelled" mood for cancelled runs (vs idle)
- Add match count to log search and aria-label for accessibility
- Add styled 404 page rendered inside the app shell

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-23 20:08:07 -04:00
josh c11573eeeb feat(ui): slim dashboard tile to hostname + online/offline only
CI / Lint + build + test (push) Successful in 1m33s
Release / detect (push) Successful in 5s
Release / build-live-image (push) Has been skipped
Release / bundle (push) Successful in 53s
Run status, Start/Cancel/View controls, and non-destructive toggle all
live on /hosts/{id} — duplicating them on the dashboard tile clogged
the grid and wouldn't scale past a handful of hosts.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-20 22:56:05 -04:00
josh 599fd156d0 feat(ui): distinguish cancel-from-hold as "Failed (cancelled)"
CI / Lint + build + test (push) Successful in 1m33s
Release / release (push) Successful in 12m41s
Before, a run that failed, held for operator review, and was then
cancelled showed up on the tile and run header as plain "Cancelled"
with an idle-grey mood — indistinguishable from a mid-stage cancel of
a healthy run. That hides the actual failure from the dashboard.

Now: when State=Cancelled with FailedStage still set (the hold-cancel
signature the heartbeat handler already uses to pick reboot vs
cancel_stage), the badge reads "Failed (cancelled)" with a fail-
colored mood. Mid-stage cancels keep reading as plain "Cancelled".
2026-04-20 18:54:04 -04:00
josh 19608bef1b ui: split /hosts/{id} into host page + /runs/{runID} run page
CI / Lint + build + test (push) Successful in 1m35s
Release / release (push) Successful in 23m47s
Host page owns host metadata, full runs table with per-row stage strip,
in-flight banner, and empty-state CTA. Run page owns pipeline, active
step, logs, sub-steps, spec diffs, and hold banner with a breadcrumb
back to the host. Dashboard tile reverts to host-only.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-18 20:37:57 -04:00
josh f79fe0f0db ui: GitHub-Actions-style detail page, sub-steps, mini-tile run-view
CI / Lint + build + test (push) Successful in 1m26s
Release / release (push) Successful in 6m47s
Reshapes the detail page into a run-view: hybrid horizontal pipeline
+ expanded active-step pane with sub-steps, a per-step log pane with
line-numbered permalinks and client-side search, and a runs-history
sidebar that navigates via ?run=N. Default step is server-picked
(running → failed → Reporting) so the operator lands on the thing
that's moving.

Adds a sub_steps table + SSE topic (substep-{run}-{stage}-{ordinal})
so per-disk and per-pass work (SMART, CPUStress CPU/RAM, Storage,
GPU) is visible in the UI instead of buried in stage summary JSON.
Agent emits sub-step reports from existing per-iteration loops.

Dashboard tiles become a mini run-view with a 9-dot step strip so
the operator reads run health across the whole grid at a glance.
Register page gets the same card shell + button styling.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-18 19:00:11 -04:00
josh d0bfae14c8 Heartbeat-first dispatch: retire WoL-as-default, add WaitingReboot
CI / Lint + build + test (push) Has been cancelled
Every supported host runs vetting-reporter in-OS and heartbeats every
30s. WoL was never the thing that started vetting — the heartbeat
response's reboot_for_vetting command was. Firing WoL first only
crowded the run log with misleading diagnostics when the real failure
mode is "reporter isn't installed."

- StartRun 409s if the host hasn't heartbeated within 60s, pointing
  the operator at /register/quick.sh.
- Dispatcher re-checks LastSeenAt at dispatch time (run may sit in
  Queued long enough for the host to go offline); stale hosts mark
  the run Failed with failed_stage=dispatch instead of looping.
- New StateWaitingReboot + TriggerRebootCommanded capture the actual
  semantics. StateWaitingWoL kept as the hook point for a future
  manual-override button.
- Tile disables the Start button with a quick.sh tooltip when the
  host is offline, matching the server-side 409.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-18 01:10:34 -04:00
josh bb658a8435 Host detail page + pipeline timeline
CI / Lint + build + test (push) Has been cancelled
Click a tile to open /hosts/{id} — the canonical control surface per
host. Timeline renders every pre-stage, stage, and terminal node in
order, with the current one pulsing, failed ones flagged, and
downstream ones dimmed as skipped. Detail page shows summary, hold
card (when holding), all action buttons, spec diffs, a full-height
log pane, and a collapsed expected-spec YAML.

Tile slims to name, last-seen, status, and one primary action; a
CSS-overlay <a> makes the whole card clickable while buttons stay
receptive via z-index.

Runner.publishTileUpdate now also emits pipeline-{runID} fragments,
and CompleteStage wraps Stages.CompleteByName so stage completions
advance the timeline live — without this the dots only moved on
state transitions.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-17 23:59:43 -04:00
josh a0c0fb114f Add host-mode heartbeat: vetting-agent host + last-seen badge
CI / Lint + build + test (push) Has been cancelled
vetting-agent gains a `host` subcommand that runs as a systemd service
installed by the quick-register one-liner, POSTing every 30s to
/api/v1/hosts/{mac}/heartbeat so the dashboard tile shows "online" or
"Nm ago" without waiting on WoL. Ships dormant client code for the
Phase 2 reboot_for_vetting command so the server can flip it on later
without a binary redeploy.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-17 23:34:15 -04:00