Files
pulse/internal
rcourtman 8b36dec0a2 Keep a source's own offline verdict through the stale pass (#2643)
## Problem

The unified registry's stale pass recomputed a resource's status from
its source sightings, and read a sighting that had *delivered recently*
as *online*. A sighting only says the source delivered, not what it
reported:

- A Proxmox node the cluster reports offline on a live poll came back
`online` once its linked host agent went silent, which is exactly what a
powered-off machine's agent does (the #1441 / discussion #1135 symptom
for users with an agent on the node). The Proxmox nodes table showed an
amber dot next to its own "Offline" label while the drawer led with a
critical "Node is offline" alert.
- A node `preserveOrExpireNodes` expired after failed polls read
`warning` ("Degraded"), and the stopped guests on it were counted under
"Attention".

Node alerts were not affected: `CheckNode` reads the poller's own
`models.Node`. Everything that reads the projection was
(`/api/resources`, websocket state, `NodesSnapshot`, Patrol and AI
tools, connections grouping, reporting, charts).

## Fix

Each sighting records the status its source reported (an unexported
verdict that replaces the narrower lease marker from #2634), and
`aggregateStatus` reads it:

- While any source with a verdict is current, only the current sources
decide, in the priority order the merge uses (agent, then Proxmox or
vSphere, then Docker), so a live agent still keeps a node online when
the Proxmox API path to it fails.
- Once every source is quiet, an `offline` verdict survives and anything
else reads `warning`, as before.
- Sightings still report delivery, so health keeps its `telemetry_stale`
reason.

Availability checks projected onto a target keep counting by delivery,
exactly as on main. Giving them a verdict needs each check's own
freshness, and that is left to a follow-up (documented in
unified-resources.md).

## Verification

- Registry tests in `registry_merge_policy_test.go`: live poll reports
offline with a silent agent (inside and past its lease), poller-expired
node alone and with its agent, stopped and running guests on a quiet
poll, JSON round trip, in-memory copy keeping a facet without a verdict,
and an aggregation table. The node, poller-expired, guest and round-trip
tests fail on main with the bug's exact symptoms; all of #2634's lease
tests still pass.
- Private mock stack (demo estate, one node held offline on a fresh poll
with its agent silent): before, both offline nodes showed amber
("Offline"/"Degraded" pills) and 44 stopped guests counted as Attention;
after, both read Offline and the guests moved to Stopped. A full status
diff of ~1,780 resources showed no other systematic change.
- `go test` for unifiedresources, monitoring, ai, alerts, mock, api,
api/resourceapi and api/chartapi passes.
2026-10-07 10:56:28 +01:00
..