feat(dashboard): Hosts widget worst first, load against cores, one home per fact (#5251)
CI / lint (push) Successful in 2s
CI / integration (push) Successful in 1m19s
CI / unit (push) Failing after 1m31s
CI / publish (push) Skipped

The Hosts — Overview widget opens with a verdict ("VDNT-Util01: CPU high."
or "All 3 hosts healthy."), then one row per host under one header: CPU,
memory, disk / and load. Rows sort by host_glance: a down monitor, a
reading past critical, a quiet agent, a warning, then the healthy. Load
reads "16.8 / 8 cores", graded per core as Settings → Thresholds intends
(cores counted from the per-core CPU sub-resources, as on the host page).
A quiet agent's last figures are shown uncoloured, with when it last reported.

Ping and 24h uptime are gone from this widget: they belong to Monitors. So
are the unlabelled CPU sparkline and the 30-day uptime query it no longer
needs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-07 13:15:01 -04:00
co-authored by Claude Opus 5.5
parent b5fcccba5f
commit 17abe450cc
5 changed files with 170 additions and 92 deletions
+23
View File
@@ -98,6 +98,29 @@ def test_a_quiet_host_keeps_its_last_values_and_reads_stale_not_missing(app):
assert "never-" + quiet not in overview # no samples at all: absent
def test_load_is_read_against_the_hosts_cores(app):
"""#5251: cores are counted from the per-core CPU sub-resources, and load
per core is load_1m as a % of them, the figure "load" thresholds grade."""
from steward.core.alerts import record_metrics
from steward.hosts.service import agent_overview_by_host
now = datetime.now(timezone.utc)
host = "cores-" + uuid.uuid4().hex[:8]
async def go():
async with app.db_sessionmaker() as s:
async with s.begin():
await record_metrics(s, [
_sample(host, "load_1m", 3.0, now),
_sample(host + ":core0", "cpu_pct", 80.0, now),
_sample(host + ":core1", "cpu_pct", 90.0, now),
])
return await agent_overview_by_host(s, [host], 180)
h = asyncio.run(go())[host]
assert (h["cores"], h["load_per_core"]) == (2, 150)
def test_retention_drops_a_latest_value_with_its_raw_history(app):
from steward.core.alerts import record_metrics
from steward.core.metrics_retention import rollup_plugin_metrics