Commit Graph

6246 Commits

Author SHA1 Message Date
pulse-triage[bot] f2b5080bcc Require complete source-selected API shard execution evidence
Fail empty, malformed, truncated or substituted test streams even when the producer exits zero. Bind each existing CI shard to its source-derived selected names and package, retaining skips, diagnostics and bounded missing coverage alongside the unchanged timings. Preserve required checks, race/vet execution and timing weights; exercise real Go race JSON and parent failure controls.

Change-source: pulse-maintainer
2026-10-07 06:28:16 +01:00
pulse-triage[bot] 31eccb559e Integrate reviewed bounded general incident-help path
Change-source: pulse-maintainer
2026-10-07 05:50:51 +01:00
pulse-triage[bot] c352e86009 Integrate reviewed native frontend graph admission
Change-source: pulse-maintainer
2026-10-07 05:50:49 +01:00
pulse-triage[bot] d688aad7d0 Integrate reviewed alert incident-action guidance
Preserve the exact reviewed docs and test commits, retaining current bounded diagnostic guidance. Acknowledge and snooze are notification holds, not workload recovery.

Change-source: pulse-maintainer
2026-10-07 05:43:01 +01:00
pulse-triage[bot] f331ab4fe1 Route general incident help through bounded log readers
The general help checklist bypassed the deadline and failure-handling recipes already on the same page. Link that existing path without requiring a request ID or repeated action, and exercise its actual copied readers.

Contract-Neutral: Documentation and regression checks only; no runtime, API, setting, or service-lifecycle change.
Change-source: pulse-maintainer
2026-10-07 05:42:43 +01:00
pulse-triage[bot] bd3432ab22 Integrate reviewed bounded performance diagnostic recipes
Preserve the exact Product Intelligence commits and retained deadline and identity controls without adding a product surface.

Change-source: pulse-maintainer
2026-10-07 05:29:29 +01:00
pulse-triage[bot] d82dde586c Integrate reviewed email identity and silent-source History repair
Retain the reviewed Core candidate exactly, including its contributor provenance repair and same-tree proof attribution.

Change-source: pulse-maintainer
2026-10-07 05:29:27 +01:00
pulse-triage[bot] 2155dfba7e Verify frontend graph changes on the native agent platforms
The native matrix consumes the frontend manifests on every platform and uses their test runtime for Windows PowerShell command acceptance, but its event filters omit graph-only changes. Admit those two exact inputs on both PR and main while leaving UI-only changes and all existing native steps unchanged. Regression controls independently remove each input/event and exclude the graph.

Contract-Neutral: Native CI admission coverage only; installer inputs, runtime behaviour, service authority and recovery contracts are unchanged.
Change-source: pulse-maintainer
2026-10-07 05:28:32 +01:00
pulse-triage[bot] 50173e6a59 Repair email identity and compose silent-source History
Preserve the exact source tree validated at 5989d928108acf80dc38b99cef40935fe17e6e32 while repairing the rejected isolated candidate's integration provenance. Apply rcourtman's original PR2628 proposal daa44ab26c alongside the bounded host-identifiable email repair and current-policy fixture corrections. Original contributor history remains untouched; this new commit records the maintainer's source integration, not a contributor identity change or a new runtime change.

Original-Proposal: daa44ab26c
Change-source: pulse-maintainer
2026-10-07 05:18:52 +01:00
pulse-triage[bot] 6987eaddae Explain alert acknowledgement and snooze without implying recovery
Document existing incident holds, hidden active alerts, bulk scope and the local-calendar snooze preset. Link delivery troubleshooting to the controls and verify the rendered help and acknowledgement readback.

Contract-Neutral: Existing help and verification only; no alert runtime, API, schema or frontend control changes.
Change-source: pulse-maintainer
2026-10-07 05:16:48 +01:00
pulse-triage[bot] 5b15a6f946 Keep bounded process readers at the collector's privilege
Read counters directly under an already authorised account instead of elevating a child reader inside an unprivileged timeout. A denied read remains unavailable; no sudoers, service permissions or credential change is suggested. Preserve the original sudo recipe only as synthetic parent-control evidence.

Contract-Neutral: Existing passive diagnostic instructions and their synthetic controls only; no runtime, API, permission or frontend behaviour changes.
Change-source: pulse-maintainer
2026-10-07 04:48:09 +01:00
pulse-triage[bot] 21cd03540d Stop performance reader descendants at the collection deadline
The exact-source TERM-ignoring control returned 124, not the intended kill result. Use GNU timeout's whole-group KILL deadline for these read-only collectors and verify that the owned synthetic reader is no longer running. Retain the adverse initial proof rather than relaxing its assertion.

Contract-Neutral: Diagnostic recipes and their synthetic deadline controls only; no runtime, API, permissions or frontend behaviour delta.
Change-source: pulse-maintainer
2026-10-07 04:40:27 +01:00
pulse-triage[bot] 07afe19ff8 Explain metric alert thresholds without mistaking Off for recovery
Document saved metric Off values, override inheritance, inclusive hysteresis boundaries, pending saves and separate delivery verification. Bind the copied CPU example to actual metric evaluation and test the rendered bundled guidance.

Contract-Neutral: Existing help and example verification only; no alert runtime, API, schema or editor behaviour changes.
Change-source: pulse-maintainer
2026-10-07 04:34:03 +01:00
pulse-triage[bot] b621549e69 Make performance sample pairs bounded and identity-safe
Withhold incomplete write/container counter pairs, reject reader and identity failures, and pin Docker stats to the full running container ID. Preserve the 60-second passive window and data-safety guidance without changing monitoring or permissions.

Contract-Neutral: Existing diagnostic documentation and synthetic recipe tests only; no runtime, API, permission or UI behaviour changes.
Change-source: pulse-maintainer
2026-10-07 04:33:27 +01:00
pulse-triage[bot] 679ac5c3a3 Integrate reviewed webhook close-outcome guidance
Retain exact Web commits b0f7a63181 and f6e8a3c9f4. The existing guide and copied PSA template preserve member close reasons and successor identity, with an explicit v6.5.0 applicability warning. Retained sender and rendered-source proof is adequate; no runtime or browser-source resolution is needed.

Contract-Neutral: Existing public and bundled webhook help and regression tests only; no runtime, API, delivery-policy, navigation or permissions contract change.
Change-source: pulse-maintainer
2026-10-07 04:30:09 +01:00
pulse-triage[bot] f6e8a3c9f4 Bind the extended webhook example to supporting software
The actual v6.5.0 source lacks NotRecovered and member Resolution. Warn against pasting the newer example into that version or blindly retrying failed renders; a web guide is not evidence that containing software has shipped.

Contract-Neutral: Version-applicability guidance and rendered regression coverage only; no runtime or delivery contract change.
Change-source: pulse-maintainer
2026-10-07 04:09:56 +01:00
pulse-triage[bot] e95e53cf9e Withhold incomplete diagnostic logs and bound copied readers
Capture both local log streams before presenting notification excerpts or request-ID matches. A reader error or deadline reports unavailability without a partial excerpt; missing GNU timeout has no unbounded fallback. Exercise copied recipes with successful, empty, partial-failure, missing-tool and hung readers, including termination grace.

Contract-Neutral: Existing read-only troubleshooting recipes and shipped mirror only; no runtime, API, permissions, settings or navigation contract changes.
Change-source: pulse-maintainer
2026-10-07 04:04:08 +01:00
pulse-triage[bot] b0f7a63181 Keep copied webhook close outcomes distinct from recovery
The sender already carries moved_to_agent reasons, but the public PSA template discarded them and described every resolved occurrence as recovered. Preserve each member's reason and successor, explain mixed and unknown outcomes, and exercise copied templates through the real sender plus the shipped Markdown renderer.

Contract-Neutral: Existing webhook help and copied-template regression coverage only; no runtime, endpoint, schema or delivery policy change.
Change-source: pulse-maintainer
2026-10-07 04:02:18 +01:00
pulse-triage[bot] 8ffdf54dbb Integrate reviewed bounded passive memory guidance
Compose the unchanged memory recipe repair with notification privacy guidance, preserving original commits and retained deadline controls.

Change-source: pulse-maintainer
2026-10-07 03:51:16 +01:00
pulse-triage[bot] 16c9dc71f3 Integrate reviewed notification evidence privacy guidance
Preserve exact Web commits and retained rendered/build proof; URL masking is not a guarantee that provider text is public-safe.

Change-source: pulse-maintainer
2026-10-07 03:51:14 +01:00
pulse-triage[bot] f8a52fcaf5 Bound passive resident-memory sampling without inventing readings
Keep the sampled counters and process identity behind a read-only deadline. Hanging readers and a missing timeout utility produce an unavailable result, while privacy, PID-reuse and measured-zero controls remain. Preserve the ten-second test assertion and clean up the test-owned shell on timeout.

Contract-Neutral: Documentation and copied-recipe verification only; no runtime collection, memory accounting, service lifecycle or API contract changes.
Change-source: pulse-maintainer
2026-10-07 03:42:08 +01:00
pulse-triage[bot] d10bdc6910 Integrate reviewed replication recovery and safe backup access guidance
Preserve the exact Core candidate commits with the existing main frontier. Retained source-0ipbo9gk covers ownership, cancellation, scheduler recovery and served warnings; integration validation remains separate from native recovery and publication.

Change-source: pulse-maintainer
2026-10-07 03:41:04 +01:00
pulse-triage[bot] 7a34a9adb4 Preserve reviewed monitoring repairs with current alert references
Incorporate exact published upstream while retaining starting reviewed tip 1364ee12f7 and every accepted commit. Preserve PVE disk history isolation and authoritative active-alert replacement alongside the reviewed monitoring batch. Composition does not establish browser, native or publication acceptance.

Change-source: pulse-maintainer
2026-10-07 03:34:33 +01:00
pulse-triage[bot] 1364ee12f7 Integrate reviewed non-destructive historical upgrade guidance
Change-source: pulse-maintainer
2026-10-07 02:58:40 +01:00
rcourtman bea0cec8b9 Keep PVE disk alert references out of resource history (#2627)
PVE disk health and wearout alerts reference the disk by instance, node
and device path (`<instance>:<node>:disk:<device key>`). Operator mutes
resolve that reference to the disk at the path (#2112), but resource
history leaves it unbound, so a physical disk's history (facets,
timeline and intelligence APIs, Assistant resource context) does not
show its own SMART and wearout alerts.

This records why that stays the decision, and pins it with a test.

- A device path is not hardware identity. A replacement disk in the same
slot, or a reboot that reorders devices, takes over the path, and disk
alerts are evaluated before their poll's disks reach the registry, so an
event can resolve against a generation that still places another disk
there.
- A history binding belongs to the reference string and moves to its
latest target, carrying every row journaled under the reference and
every read of it. Bound, the path would put a replaced disk's alerts
into its successor's history, and the Alerts history Resource action
(which reads incidents by the alert's own reference) would show the
successor's incidents for the predecessor's alert.
- A binding guarded by the serial each disk alert records was built and
measured on a mock estate (mock mode needed a build overlay to evaluate
PVE disk alerts at all). It bound correctly while disks kept their
paths, but review found rejected events still joining the currently
bound disk, a removed retained target accepting a successor's event, no
WWN in the alert metadata, a non-atomic check and write, and retry
expiry abandoning rows. That attempt is not in this PR.

Binding these alerts needs ownership per row (each event under the disk
its recorded hardware identity names, rows without usable identity left
under the reference, and a decided read for the Resource action), not a
per-reference binding. The contract paragraph in `unified-resources.md`
says so.

Test: `TestHistoryIdentityLeavesProxmoxDiskAlertReferencesUnbound` (live
event and backfilled legacy row stay under the reference and out of the
disk's history, while `ResolveReferenceID` still resolves the reference
for mutes). It fails against the reverted binding implementation.
2026-10-07 02:58:35 +01:00
pulse-triage[bot] 6bf79efe28 Reconcile reviewed integration with batch-start upstream
Change-source: pulse-maintainer
2026-10-07 02:58:29 +01:00
pulse-triage[bot] af586eb56c Keep notification delivery evidence private before sharing
Replace the blanket sanitisation promise with the actual recognised-URL masking boundary. Explain provider free text and infrastructure identity risk at both existing troubleshooting entry points, keep the bundled guides exact, and test rendered precautions and links.

Contract-Neutral: Notification delivery, URL masking and API behaviour are unchanged; this corrects existing public guidance to match their privacy limits.
Change-source: pulse-maintainer
2026-10-07 02:57:52 +01:00
rcourtman 458ee510c1 Replace stored alerts with each payload instead of merging (#2631)
The websocket store wrote each incoming active alert with
`setActiveAlerts(id, alert)`. Solid's path setter shallow-merges into
the existing object, so any field the server stops sending kept its old
value in the browser:

- After a backend restart, threshold alerts are restored without
`metricStatus` until their next evaluation (and indefinitely while the
reading is missing). An open tab kept the pre-restart live reading, so
the node drawer's "Needs attention" row and the node table temperature
tooltip went on saying "Temperature 78°C now" for a reading the server
no longer reports.
- An unacknowledge from another session left `ackTime`/`ackUser` behind,
as did a dropped `nodeDisplayName` or `metadata`.

Changes in `frontend-modern/src/stores/websocket.ts`:

- Active and recently resolved alerts are written with `reconcile`, so
omitted keys are removed on the snapshot, keyed-delta and REST recovery
commits alike. `reconcile` diffs nested values in place, so an unchanged
alert's live status no longer re-notifies keyed-store readers on every
frame (the shallow merge swapped in a fresh nested object each time).
- `updateAlert` stores a copy of each local update, because in-place
reconciliation would otherwise rewrite the record a snooze keeps for
rollback (its optimistic record shares nested objects with it).
- The pending acknowledgement hold is unchanged.

Tests (`websocket-unified.test.ts`): omitted `metricStatus`,
`nodeDisplayName` and `metadata` clear via snapshot, keyed delta (`null`
patch) and REST recovery; a server-side unacknowledge clears
`ackTime`/`ackUser`; local acknowledge/unacknowledge still wait for
confirmation; the rollback record stays intact; an unchanged alert's
nested reader is not re-notified; recently resolved alerts clear omitted
fields. The omitted-field, unacknowledge, reactivity and resolved tests
fail on the previous store. The rollback test fails if the `updateAlert`
copy is removed. The acknowledgement-hold test passes on both and guards
the existing behaviour.

Browser verification on a private mock stack at 1280×900 and 375×812,
with a local-only overlay that pins a standalone node's evaluated
temperature and lets mock mode restore alerts across restarts. Latch at
78°C (breach 95), restart the backend with the reading missing
(`/api/alerts/active` returns the alert without `metricStatus`), then
restore the reading:

- This change: the open tab's drawer and tooltip drop to "Node
temperature at 95.0°C" within seconds of reconnecting, then show "78°C
now" again on the next delta.
- Previous store, same run: the open tab kept "Temperature 78°C now" for
the full two-minute window.
- Snooze, resume and acknowledge on the Alerts card work with no page
errors. A remote acknowledge/unacknowledge round trip updates the open
tab within 2s.

Seen during verification and not changed here (it reproduces on main):
after acknowledging from the Alerts card, an unacknowledge from another
session does not bring the card back in that tab until a reload. The
cause is the acknowledgement override in `useAlertAcknowledgementState`.
It is tracked as a separate fix.
2026-10-07 02:54:37 +01:00
rcourtman f4ddeeb0e5 Give Docker containers and services without IDs their own alert refs (#2629)
Follow-up to #2620, which documented both conflations below as
residuals.

## Problem

Two Docker alert producers wrote names into identity slots:

- A container reported without an ID alerted under its Docker host's own
reference, `docker:<host>`. Its alerts showed on the host, joined the
host's resource history (which #2620 binds to the host), were never
cleared when the container left the report (cleanup matches
`docker:<host>/`), and Patrol registered `docker:<host>` on both the
host and the container, so the host's scope alias was ambiguous.
- A Swarm service without an ID put its normalized name in the
`/service/<ID>` slot, so a name equal to another service's Swarm ID
shared that service's alerts and history. #2620's resolver had to treat
every service in such a cluster as a conflict.

Pulse's own agent always sends Docker and Swarm IDs, so this needs a
malformed or third-party report. The registry still shows those
containers and services.

## Change

- `internal/alerts`: `DockerHostResourceID`,
`DockerContainerResourceID(host, id, name)` and
`DockerServiceResourceID` are the only builders. An ID-less container
alerts under `docker:<host>/name:<name>` and an ID-less service under
`docker:<host>/service/name:<normalized name>`. Docker and Swarm IDs
never contain a colon, so neither can equal a host or ID reference. One
with neither an ID nor a name raises no alert.
- The container and service policy switches classify by the first path
segment after the host, so a container name containing `/service/` stays
a container.
- Report cleanup, host removal and the host's offline alert also clear a
pre-upgrade container alert left on exactly `docker:<host>` (recorded
host must match, container ID empty). A pending image update recorded
there keeps its age when the first report still shows it pending.
- Canonical state IDs were split at the first `::`, but colliding Docker
hosts get IDs like `<base>::<suffix>`. Every container alert of such a
host was rewritten to `docker:<base>`, the other host's reference: it
joined that host's history and missed its own host's cleanup.
`splitCanonicalStateID` now splits before the alert's recorded spec ID,
else after its resource ID, so alerts saved the old way also recover on
restore.
- Patrol registers the same builders' output as scope aliases, with the
container's name.
- History: a service slot containing `:` is a name reference (never
binds, never retried), and the cluster-wide conflict for ID-less
services is gone. A real service ID reference now binds even when its
cluster also has an ID-less service.
- Contract notes in alerts, ai-runtime, monitoring and
unified-resources.

Remaining legacy boundary (in the unified-resources contract): rows
journaled before this change keep their old reference. An ID-less
container's old rows stay in its host's history, and an ID-less
service's old rows bind only to a service whose ID equals its normalized
name.

## Proof

- `TestDockerAlertsWithoutIDsUseTheirOwnReferences` (real
`CheckDockerHost`: fired and active references, removal cleanup,
pre-upgrade leftover on report and offline, config-save
container/service switches).
- `TestDockerHostIDWithSeparatorKeepsItsAlertReferences`,
`TestDockerAlertsRestoredWithCutShortReferencesRecover` (writes
`active-alerts.json`, restores through `LoadActiveAlerts`) and
`TestDockerContainerWithoutIDKeepsPendingUpdateAgeAcrossUpgrade`.
- `TestOwnerAlertTimelinesUseCanonicalHistoryIdentity`: real producers
into the SQLite history. The ID-less container and the service named
like `web`'s Swarm ID stay out of the host's and `web`'s histories.
- `TestResolvePatrolScopeResolvesDockerAlertResourceIDs`: the host's
alias stays unambiguous, and the ID-less container's name reference
resolves to the container in the unified read state.
-
`TestHistoryIdentityMonitorAdapterResolvesDockerHostAndServiceReferences`:
the ID reference binds before and after the service leaves inventory,
and name references never bind or retry.
- Mutation check: putting back each old behavior fails at least one of
these tests. Covered: host fallback, unmarked service name, no skip for
unidentifiable containers or services, each legacy clause and its host
check, the update-age carry-over, first-`::` splitting with and without
the spec rule, substring classification, the Patrol alias without the
name, and the resolver accepting a `name:` slot.
2026-10-07 02:52:45 +01:00
pulse-triage[bot] e9924fac05 Replace presumptive backup ACL recipes with evidenced access guidance
Use observed HTTP status to distinguish authentication rejection, denial and unknown cause. Point to the actual saved connection and attempted endpoint without prescribing a role, mutating ACLs or exposing token identities or provider text. Preserve inventory and setup semantics and privilege separation; cover custom/manual identities and real-client 401/403/proxy producer paths.

Contract-Neutral: Correct existing diagnostic guidance and expose only internal HTTP-status evidence; no API shape, collection, inventory, setup permission or guest-safety contract changes.
Change-source: pulse-maintainer
2026-10-07 02:39:19 +01:00
pulse-triage[bot] 1b8f077012 Keep replication observations owned through ordinary polling recovery
Dispatch replication independently of the efficient guest path, coalesce bounded runtime-scoped reads and fence obsolete client/runtime completions. Preserve prior inventory on unavailable input or cancellation; only an explicitly complete empty read clears it. Bind scheduler, replacement and HTTP cancellation controls to this repair.

Contract-Neutral: Repair existing replication scheduling and cancellation ownership; no wire, endpoint, cadence, permission or host-agent lifecycle contract changes.
Change-source: pulse-maintainer
2026-10-07 02:30:24 +01:00
pulse-triage[bot] ef2df62f17 Make quiet-hours setup select a real notification window
Complete the existing copied schedule with explicit days, timezone and critical-category choices. Explain calendar boundaries, held delivery and safe configuration preservation, and test the example against the actual delivery policy.

Contract-Neutral: Existing quiet-hours behaviour and API are unchanged; this repairs shipped setup guidance and tests its copied configuration.
Change-source: pulse-maintainer
2026-10-07 02:26:29 +01:00
pulse-triage[bot] 2476a4e449 Keep historical upgrade recovery non-destructive
Route current upgrades to current guidance; preserve existing login and monitoring state when diagnosing missing PVE backups. Require endpoint-specific access evidence rather than blanket ACL changes or setup-token rotation.

Contract-Neutral: Documentation and regression checks only; no collector, permission, authentication or upgrade contract changes.
Change-source: pulse-maintainer
2026-10-07 02:25:19 +01:00
pulse-triage[bot] 44569ddbf0 Merge branch 'main' into fix/active-alert-store-replace 2026-10-07 02:16:55 +01:00
pulse-triage[bot] 809629954d Merge branch 'main' into fix/docker-alert-unique-refs 2026-10-07 02:16:52 +01:00
pulse-triage[bot] d4ab4a2324 Merge branch 'main' into fix/pve-disk-alert-history 2026-10-07 02:16:49 +01:00
pulse-triage[bot] c48289160d Merge branch 'main' into fix/workload-hover-hint-reflow 2026-10-07 02:16:43 +01:00
pulse-triage[bot] a249ac9d06 Integrate reviewed bounded API shard failure diagnostics
Change-source: pulse-maintainer
2026-10-07 02:08:25 +01:00
pulse-triage[bot] 03be3a1c49 Reconcile reviewed monitoring with current disk heat thresholds
Preserve all reviewed identities while incorporating the current published disk-temperature policy. Retain truthful sparse History and collected-only temperature consumers.

Change-source: pulse-maintainer
2026-10-07 02:03:50 +01:00
pulse-triage[bot] bd2a317fc5 Integrate reviewed non-destructive PVE backup troubleshooting
Preserve monitored connections, credentials, registration state and history during diagnosis. Retain the exact documentation and regression-proof commits; source guidance is not released availability or native recovery.

Change-source: pulse-maintainer
2026-10-07 01:51:46 +01:00
pulse-triage[bot] 87c13e4074 Retain bounded API shard failure identities beside timings
Publish failed and unfinished source-test names in the existing shard artifact without waiting for other workflow jobs. Keep logs, timings, test selection and failure exits unchanged; record unknown completion and omitted unsafe or excess identities explicitly. Pin privacy, bounds, pipefail and timing-refresh compatibility, and align the existing shard contract with current compile admission.

Change-source: pulse-maintainer
2026-10-07 01:47:42 +01:00
pulse-triage[bot] 8f89ba0c5e Integrate reviewed webhook retry and retained-failure guidance
Preserve exact Web candidate 8ebd62d141. Its existing-guide correction matches the current queued sender and failure classification; retained source-rqwe9_7d proves the same guide, renderer, tests and frontend manifests. No frontend runtime content is changed by this integration, and inherited browser/native/publication gaps remain open.

Change-source: pulse-maintainer
2026-10-07 01:45:28 +01:00
pulse-triage[bot] 152aacaa6a Preserve reviewed sparse history with current disk-temperature consumers
Add exact published upstream 1b6a9b45d7 without rewriting reviewed history. Retain its collected-temperature protection for AI, Patrol, reports and metric recording. Resolve the chart overlap without restoring fabricated live two-point history: no samples means no series, and a single observed sample retains its original timestamp and value. Extend the upstream regression to cover both retained and live sparse histories.

Change-source: pulse-maintainer
2026-10-07 01:23:44 +01:00
rcourtman e3e743b076 List disk heat beside TrueNAS alert text
The TrueNAS storage table's Health reasons put native TrueNAS alert text
first and used Pulse's derived summaries only when TrueNAS raised no
alert. Disk heat landed in that fallback, so a hot disk with any
incident, even an informational one, showed only the incident's text
under Attention, and nothing said the disk was hot.

Heat is Pulse's own judgement against the alert disk temperature
thresholds, not a restatement of TrueNAS state, so it is now always
listed after any native alert text.
2026-10-07 01:20:02 +01:00
rcourtman 396bb5d517 Keep a disk heat finding open without a current reading
Patrol verifies a disk-high finding as recovered once the disk's
temperature cools to its alert clear value. A disk in standby, or one
whose host agent stopped reporting, has no current reading, and a
missing reading counted as cooled. A finding raised for a SATA disk at
56C would close as soon as the disk spun down, while its temperature
alert stayed open.

When a disk has no current reading and its last known reading is still
at or above the clear value, verification now reports the recovery as
unknown instead of proven. A disk last seen cool still recovers.
2026-10-07 01:19:36 +01:00
rcourtman 35bf55af23 Colour report disk temperatures by the alert thresholds
The PDF performance report's disk table coloured a temperature amber
from 50C and red from 60C for every disk type, the last fixed disk heat
line after disk heat moved to the alert disk temperature policy. An NVMe
at 63C, well under its 70C alert trigger, printed red. A user's raised
trigger changed nothing.

Each reported disk now carries the tenant's alert thresholds for its
type (the clear value and the trigger, from
alerts.Manager.DiskTemperatureThreshold). The PDF colours the reading
amber from the clear value and red from the trigger, as the Physical
Disks Temp column does, and leaves it plain when disk temperature
alerting is off.
2026-10-07 01:19:36 +01:00
rcourtman 3fd5411ecc Judge disk heat by the alert disk temperature thresholds
Pulse decided whether a physical disk was too hot in three places with
three thresholds. Disk risk added temperature_high at a flat 60/70C for
every disk type and drove the disk status and the Physical Disks Health
verdict. Patrol flagged anything over 55C and the AI chat context listed
disks from 50C. Alerts and the Temp column used the per-type thresholds
users tune in Alerts (NVMe 70, SAS 65, SATA 55 by default). An NVMe at
63C read Running Hot beside a green Temp cell. A SATA disk at 56C read
Healthy beside a red one. A user who raised the NVMe trigger to 75 still
got a hot verdict at 70.

The alert disk temperature policy now decides disk heat.
alerts.Manager.DiskTemperatureThreshold exposes the per-type resolution
CheckHost already applies.

- Disk risk no longer judges temperature. Every registry that rebuilds
  risk lacks the alert configuration, so no rule there could honour it.
  A hot disk keeps an online status.
- The Health verdict reads Running Hot when a current reading reaches
  the disk type's trigger. It uses the thresholds object that colours
  the Temp cell, so the two cannot disagree. The amber band below the
  trigger stays a cell colour, not a verdict.
- The TrueNAS storage table lost the heat it used to get from risk. It
  now judges heat the same way: an Attention row with the reason, and a
  warning dot for phones.
- Patrol triage, its disk issue filter, finding recovery and the chat
  context's attention list judge the collected reading against the same
  trigger, including scoped runs and a provider set before Patrol
  starts.
- A switched-off agent Disk Temp default resolves to no thresholds,
  which the displays that read them now treat as off.

Per-host Disk Temp overrides do not reach these surfaces yet. TrueNAS
disk alerts, the TrueNAS disk drawer and PDF reports keep their own
fixed temperatures for now.
2026-10-07 01:19:31 +01:00
rcourtman 1b6a9b45d7 Keep retained disk temperatures out of AI, Patrol and reports (#2625)
Normalization keeps a disk's last-known temperature when the current
observation did not collect one (a disk in standby, a host agent past
its reporting lease) and marks it non-available. These readers still
took `PhysicalDisk.Temperature` at face value; each now goes through
`diskinventory.TemperatureCollected`:

- **AI chat context**: "Physical Disks Needing Attention" no longer
flags a disk for heat from a retained reading. A disk listed for another
reason shows it as `last known 52C (host agent stopped reporting)`.
- **Patrol**: the disk health-issue gate, triage flags and `disk-high`
finding verification judge only a collected reading. Both seed tables
label a retained one as last known.
- **AI tools**: `pulse_query` / `pulse_metrics` physical disks and
`pulse_storage disk_health` put a retained value in
`last_known_temperature` + `last_known_temperature_reason` instead of
`temperature`.
- **Reports**: the performance report's disk table and the reporting
runtime snapshot leave a retained value out (no reading).
- **Disk temperature charts**: a short series is padded out to now only
with a collected reading. Otherwise stored samples are returned as they
are.
- `monitor.go`'s private copy of the predicate is replaced by the shared
helper.

Each new test reproduces against the pre-change code: retained
`unavailable` temperatures (standby / silent agent) beside a collected
one.
2026-10-07 01:18:08 +01:00
pulse-triage[bot] dd4a0a4ad6 Preserve reviewed maintenance with current host and disk monitoring
Add the exact batch-start upstream history without rewriting any accepted commit; reconcile its host-offline, mock-disk, hot-disk and metric-history changes with the reviewed monitoring batch.

Change-source: pulse-maintainer
2026-10-07 01:07:43 +01:00
pulse-triage[bot] da747553d9 Keep connection liveness separate from backup freshness
Source inspection shows connection/agent status is not a dedicated PVE backup last-success control. Use existing collection timestamps where available without inventing a settings field or treating a live agent as fresh backup inventory.

Contract-Neutral: Documentation-only correction of existing PVE backup diagnostics; runtime collection and access contracts are unchanged.
Change-source: pulse-maintainer
2026-10-07 01:05:17 +01:00