Skip to main content

max / makenotwork

Stop reporting health for targets that do not watch it `TargetView.health` being `None` meant two different things: health is configured but no check has run, and health is not configured at all. Collapsed, the second reported `health: pending` forever. af, bb, go and sk are test-only targets, desktop apps and an SDK with no HTTP endpoint and no prospect of one, so four of astra's eight targets could never leave pending and held the source there with them. A row that can never go green is worse than no row. The panel on astra reads worst-first, and a surface where most rows are permanently unsatisfiable is one nobody looks at, which is the failure the whole surface exists to prevent. `health_configured` now carries what the config says, and a target emits a health condition only when it watches health or has a stored snapshot. Keeping the snapshot case means removing the config does not silently erase the last thing PoM knew. Three tests pin all of it: unconfigured emits nothing, a leftover snapshot still reports, and a watched target with no check yet stays pending.
Co-Authored-By
Claude Opus 5 (1M context) <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-07-30 03:07 UTC
Commit: c17ab10f785c74532f733b7066e8ccbccaefb973
Parent: f5fc981
2 files changed, +67 insertions, -1 deletion
@@ -732,6 +732,7 @@
732 732 targets.push(crate::status::TargetView {
733 733 name,
734 734 label: target_config.label.clone(),
735 + health_configured: target_config.health.is_some(),
735 736 health,
736 737 uptime_24h,
737 738 latency_avg_ms,
@@ -63,6 +63,16 @@
63 63 pub label: String,
64 64 /// The most recent health snapshot. `None` before the first check.
65 65 pub health: Option<HealthView>,
66 + /// Whether the target configures an HTTP health check at all.
67 + ///
68 + /// Distinct from `health` being `None`, which only says no snapshot has been
69 + /// stored. Without this the two collapse and a target that will never have a
70 + /// health endpoint reports `health: pending` forever: the desktop apps and the
71 + /// SDK are test-only targets, so af, bb, go and sk sat permanently pending and
72 + /// held the whole source there with them. A row that cannot ever go green is
73 + /// worse than no row, because a surface where most rows are unsatisfiable is
74 + /// one nobody reads.
75 + pub health_configured: bool,
66 76 /// Uptime percentage over the last 24 hours, if any checks fell in the window.
67 77 pub uptime_24h: Option<f64>,
68 78 /// Mean response time over the last 24 hours of operational checks, in ms.
@@ -217,7 +227,12 @@
217 227 }
218 228
219 229 fn target_node(target: &TargetView) -> Node {
220 - let mut conditions = vec![health_condition(target.health.as_ref())];
230 + // Only speak about health where health is watched. A stored snapshot still
231 + // reports even if the config was since removed, so history stays visible.
232 + let mut conditions = Vec::new();
233 + if target.health_configured || target.health.is_some() {
234 + conditions.push(health_condition(target.health.as_ref()));
235 + }
221 236 if let Some(incident) = &target.incident {
222 237 conditions.push(incident_condition(incident));
223 238 }
@@ -756,6 +771,7 @@
756 771 TargetView {
757 772 name: name.into(),
758 773 label: name.to_uppercase(),
774 + health_configured: true,
759 775 health: Some(HealthView {
760 776 status: HealthStatus::Operational,
761 777 checked_at: checked_at(),
@@ -1525,6 +1541,55 @@
1525 1541 assert_eq!(p.validate(), Ok(()));
1526 1542 }
1527 1543
1544 + #[test]
1545 + fn a_target_that_does_not_watch_health_says_nothing_about_health() {
1546 + // The test-only targets (the desktop apps, the SDK) have no HTTP endpoint
1547 + // and never will. Emitting `health: pending` for them is a row that can
1548 + // never go green, which held af/bb/go/sk pending forever and the whole
1549 + // source with them.
1550 + let mut t = healthy("af");
1551 + t.health_configured = false;
1552 + t.health = None;
1553 + let p = payload(&[t], now());
1554 + let n = node(&p, "target:af");
1555 + assert!(
1556 + n.conditions.iter().all(|c| c.condition_type != "health"),
1557 + "unconfigured health must emit no condition, got {:?}",
1558 + n.conditions
1559 + );
1560 + assert_eq!(p.validate(), Ok(()));
1561 + }
1562 +
1563 + #[test]
1564 + fn a_stored_snapshot_still_reports_after_the_config_is_removed() {
1565 + // Config is truth for whether to watch, but evidence already collected
1566 + // should not vanish: dropping the block should not silently erase the
1567 + // last thing PoM knew about that target's health.
1568 + let mut t = healthy("mnw");
1569 + t.health_configured = false;
1570 + let p = payload(&[t], now());
1571 + let n = node(&p, "target:mnw");
1572 + assert!(n.conditions.iter().any(|c| c.condition_type == "health"));
1573 + assert_eq!(p.validate(), Ok(()));
1574 + }
1575 +
1576 + #[test]
1577 + fn a_watched_target_with_no_snapshot_yet_is_still_pending() {
1578 + // The case the flag must not break: health IS configured, no check has
1579 + // run, so "evidence of nothing" is the honest answer.
1580 + let mut t = healthy("mnw");
1581 + t.health = None;
1582 + let p = payload(&[t], now());
1583 + let n = node(&p, "target:mnw");
1584 + let h = n
1585 + .conditions
1586 + .iter()
1587 + .find(|c| c.condition_type == "health")
1588 + .expect("configured health must still emit a condition");
1589 + assert_eq!(h.status, Status::Pending);
1590 + assert_eq!(p.validate(), Ok(()));
1591 + }
1592 +
1528 1593 #[test]
1529 1594 fn render_is_a_pure_function_of_state_and_clock() {
1530 1595 let a = payload(&[healthy("mnw")], now());