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
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
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
Preserve the exact Product Intelligence commits and retained deadline and identity controls without adding a product surface.
Change-source: pulse-maintainer
Retain the reviewed Core candidate exactly, including its contributor provenance repair and same-tree proof attribution.
Change-source: pulse-maintainer
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
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
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
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
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
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
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
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
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
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
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
Compose the unchanged memory recipe repair with notification privacy guidance, preserving original commits and retained deadline controls.
Change-source: pulse-maintainer
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
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
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
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
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.
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
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.
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.
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
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
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
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
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
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
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
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
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
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.
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.
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.
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.
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.
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
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