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
Retain the exact returned PBS repair and cancellation correction commits. Focused race, parent differential, ordering, vet and build evidence establish the bounded repair; native PBS recovery and the original forty-unprotected report remain separate.
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
Correct the additive upstream merge exposed by source-nj0ja4zv: the accepted unified-read-state regression requires disk metadata with an empty series for collected readings. Restore that contract without historical padding, while retaining upstream exclusion of retained-only disks with no observations and preserving original single-sample timestamps and values.
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
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
Replace node deletion, registration-state removal and blanket ACL instructions with source-aware checks of existing native evidence, ordinary API collection and the actual rejected request. Preserve credential and backup safety boundaries in the shipped guide, with regression checks against the collector and setup behaviour.
Contract-Neutral: Documentation-only correction of existing PVE backup diagnostics; runtime collection and access contracts are unchanged.
Change-source: pulse-maintainer
A host agent that stops reporting is never shown as offline in the
Machines table. Its row renders its last report as if it were current.
## Why
The monitor marks a host agent offline once its reporting lease expires,
and raises "Host is offline". The registry's stale pass marks the agent
sighting stale after 60 seconds, and `aggregateStatus` ranked stale
above offline. So the machine reached every consumer as `warning`.
On the Machines table that meant an amber dot. CPU, memory, disk,
network, disk I/O, uptime and temperature all rendered as live, with
threshold colours. Meanwhile the row's own drawer led with the critical
offline alert and read "Observed state: Degraded".
Docker hosts and Kubernetes clusters hold the same kind of lease, and
theirs is shorter than the 120-second stale threshold. A silent Docker
host therefore read offline at first, then flipped to warning once its
sighting went stale.
## What changes
- **Backend.** Each sighting records when a push reporter delivered its
machine, Docker host or cluster as offline. The reporters are the host
agent, Docker and Kubernetes. Status aggregation counts that sighting as
offline whatever its age.
- The sighting itself still reads `stale`, so health keeps its
`telemetry_stale` reason and monitored-system reasons are unchanged.
- A live source still carries a merged row. A Proxmox node whose agent
died stays online through the PVE poll.
- Pull sources, and the guests, containers, pods and disks that push
collectors report about, keep the stale-to-warning rule.
- A JSON copy re-derives the marker from its stored status.
- A manual link joining two resources from one source keeps the fresher
sighting.
- **Frontend.** Offline rows already blank CPU, memory, disk, network
and disk I/O through the danger gate.
- The Machines Uptime and Temp cells and the Docker hosts Temp cell had
no gate, and now use it.
- The drawer drops an offline resource's uptime and a silent agent's
uptime.
- The drawer marks a silent agent's non-disk Thermals rows "(last
known)" with the reason as title, as retained disk rows already are.
## Verification
- Go tests cover the agent, Docker, Kubernetes, mixed-source,
Proxmox-node, JSON round-trip and manual-link cases, plus the unchanged
late-agent and stale-PVE boundaries. Each fix's test fails without it.
The `unifiedresources` package passes.
- The `api`, `monitoring`, `ai`, `alerts` and `agentcontext` suites ran
on pulse-dev. One `internal/api` test failed there,
`TestServerInfoEndpointReportsDevelopment`, and it fails identically on
the pre-fix build in that scratch tree.
- Frontend tests cover the Machines offline row, the Docker offline Temp
cell, the drawer thermals marking and the drawer uptime rows. The
adjacent suites pass.
- Live check on a private mock stack, holding one standalone Linux agent
and one Docker host past their leases, at 1440 and 390 wide. Before:
amber row with live-looking readings. After: red row with every reading
blanked, the drawer reading "Offline", and thermals marked last known.
- The browser receipt is included. Bundle sizes are within budget:
WorkloadsSurface is unchanged, Standalone +0.04 kB, Docker +0.01 kB.
Builds on rcourtman/Pulse#2630 and updates its contract sentence, which
described the lapsed agent as reaching the table as `warning`.
Known follow-up: the drawer's Disks card still threshold-colours a
silent agent's retained filesystem usage.
`checkMockAlerts` evaluated guests, agents, nodes, storage, PBS, PMG and
Docker against the mock estate but never physical disks. The mock
generator deliberately keeps a FAILED health cohort and worn SSDs stable
across restarts, so mock and demo stacks showed failing and "Replace
Now" disks with no `disk-health` or `disk-wearout` alert, and the disk
alert lifecycle could not be exercised without real hardware.
## Change
- `checkMockAlerts` now evaluates fixture disks through
`checkMockPhysicalDiskAlerts`, applying the physical disk poller's
boundary: only disks on online nodes (matched by instance and node
name), with the linked agent's `--disk-exclude` patterns forcing a
matched device healthy.
- The poller's per-disk rule (exclusion forces healthy, else
`CheckDiskHealth`) moves into `checkPhysicalDiskAlerts`, shared by
`maybePollPhysicalDisksAsync` and the mock pass. The poller's behaviour
is unchanged; the source guardrail
`TestProxmoxDiskAlertsRunOnMergedDiskState` now pins the helper call.
- The poller's host-agent link settle deferral (#1674) is not applied in
mock mode: fixture links and exclusions are complete from the first
pass.
## Demo-facing effect
Measured on private stacks with the public demo's exact estate
(`/etc/pulse/.env`: 8 nodes, `DEMO_MODE`), baseline vs patched: the demo
estate has 12 Proxmox disks and none FAILED. The only new disk alert is
one warning-level `disk-wearout` ("SSD has less than 10% life remaining
(7% wearout)" on West Production E), whose resource ID is one of the
disk resource's canonical aliases. No `disk-health` alert opens on that
estate. The default test estate (50 nodes) raises five `disk-health` and
one `disk-wearout` alert.
## Known gaps, left out of scope
- Like the other loops in `checkMockAlerts`, the disk loop relies on the
pass's single up-front mode check, so a pass in flight when mock mode is
switched off can reopen alerts after `ClearActiveAlerts`. That race
predates this change and also involves the frontend refresh and backup
rollup paths, so it needs a monitor-wide fix rather than a lock around
this pass alone.
- `CheckDiskHealth` logs at error/warn on every evaluation of a FAILED
or worn disk, so in mock mode such a disk logs once per alert tick.
- The wearout message calls 7% life remaining "7% wearout".
## Verification
- `TestCheckMockAlertsEvaluatesPhysicalDisks` (pinned default estate)
and `TestCheckMockPhysicalDiskAlertsFollowsPollerBoundary` (offline
node, same node name on another instance, exclusion resolving existing
alerts, node departure cleanup). Mutations that drop the pass, ignore
offline nodes, ignore exclusions, or key by node name only each fail a
test.
- Full `go test ./internal/monitoring/` and the mock tests under `-race`
pass.
`useWorkloadTableMetricHistory` ran two polled estate-wide reads per
instance in Trends mode: the workloads history (`/api/charts/workloads`)
and the infrastructure summary (`/api/charts/infrastructure`). Since
#2622 removed the host metric cells from grouped workload rows, the
Workloads surface reads only guest series, and the Proxmox nodes table
never read anything but node series. Two instances never shared reads
either: each forwards its own abort signal, which skips the summary
caches' in-flight dedupe, and retained query values only seed matching
mounts and source changes without sharing requests. So every reader paid
for both routes every 30 seconds.
The hook now takes a required `series: 'guests' | 'nodes'` option. The
Workloads state passes `'guests'` and the Proxmox nodes table passes
`'nodes'` (and drops the `selectedNode` it never needed), so each reader
polls one route.
### Measured
Private demo-mode mock stack, Trends on, 95 s per page (first read +
three 30 s polls), reads per poll tick:
| Page | Viewport | Before (infra + workloads) | After (infra +
workloads) |
|---|---|---|---|
| /vmware | desktop 1440x900 | 1 + 1 | 0 + 1 |
| /vmware | phone 390x844 | 1 + 1 | 0 + 1 |
| /proxmox/overview | desktop 1440x900 | 2 + 2 | 1 + 1 |
| /proxmox/overview | phone 390x844 | 2 + 2 | 1 + 1 |
Node table sparklines on /proxmox/overview still draw for every row (36
on desktop, 18 on phone), and the guest table sparklines are unchanged.
### Tests
- `useWorkloadTableMetricHistory.test.tsx`: a `'guests'` reader polls
only the workloads route and a `'nodes'` reader only the infrastructure
route, across two polls. Both cases fail with the gating reverted.
- `ProxmoxNodesTable.test.tsx`: the table asks for node history only,
with no node scope, and enables it only in Trends.
- `WorkloadsSurface.performance.contract.test.tsx` pins both call sites
and the gating.
The performance contract claimed the two readers deduped their fetches;
it now says they do not and that each reader polls only what it renders.
The adjacent Bars-mode prose (performance and frontend-primitives
contracts) described one active-row request that leaving the row
cancels; it now describes the bounded warming window the hook has
actually run since the history lens shipped.
Stacked on #2622, whose auto-merge is already on: this branch contains
its commits and merges cleanly with main either way round.
On Physical Disks, a SMART-passed disk with good life running at 72°C
read **Replace Now** ("Disk temperature is 72C"), and **Replace** on
phones. Disk risk grades temperature (`temperature_high`, ≥70°C
critical, ≥60°C warning), and the Health verdict mapped any critical
risk to Replace Now. That tells a homelab user to buy a disk when the
fix is airflow. Alerts already keep heat separate: the SMART health and
wearout alerts skip `temperature_high`, and disk heat is raised as a
Temperature metric.
## Change
- `diskPresentation.ts` keeps each risk reason's code and severity, and
splits the reasons into heat and everything else.
- FAILED health, any other critical reason, or a critical level that no
reason explains → **Replace Now** (unchanged).
- Heat alone → **Running Hot** (phone **Hot**). Red at the critical
tier, amber at warning. The temperature reason is still the cell title
and the drawer summary.
- Other warning evidence, SMART counters or low life → **Needs
Attention** (unchanged).
- The more severe class names the verdict, and failure evidence wins a
tie. Merged risks that list heat first (`mergePhysicalDiskRisk` does not
re-sort) no longer hide pending sectors behind a temperature summary.
- Sort priority and the health filter derive from the same verdict.
Order is Replace Now, then red Running Hot, then Needs Attention, then
amber Running Hot. Hot disks stay in **Needs attention** and land in
Critical or Warning by their tier.
- Data with no reason codes keeps the old behaviour.
## Not changed
Thresholds. The tier still comes from the server's flat 60/70°C rule,
not the per-type alert thresholds that colour the Temp cell. An NVMe at
60–64°C therefore reads amber Running Hot next to a green Temp cell.
That disk read Needs Attention before this change, so the judgment is
the same and only the word is clearer. Reconciling the thresholds is
being done separately.
## Verification
- New tests in `diskPresentation.test.ts` cover heat at both tiers,
failure evidence listed after heat, heat plus wear, an unexplained
critical level, sort order and the health filter. Five of them fail on
the old code, including the sort test, whose device names make name
order alone disagree. `DiskList.test.tsx` checks the full and compact
words, tone, title and row order.
- Targeted suites (storageBackups, Storage, GuestPhysicalDisks,
frontendResourceTypeBoundaries): 89 files, 1513 tests pass. tsc and
eslint are clean, and the canonical platform audit is clean.
- Browser check on a private mock stack (local, uncommitted generator
overlay pinning pve3 disks at 72°C, 63°C, and 72°C with 2 pending
sectors), at 1440×900 and 390×844. The rows read Replace Now / Running
Hot / Needs Attention / Running Hot (phone: Replace / Hot / Attention /
Hot) with the expected tones and titles. The drawer reads "Running Hot ·
Disk temperature is 72C". The `status=attention|critical|warning`
filters list the expected rows. A same-session control with the old file
showed the 72°C disk as Replace Now. The receipt is
`frontend-modern/browser-verification/259ae9ced29e073f.json`.
Explain terminal failure classes, transient HTTP exceptions and the inclusive attempt budget without promising enhanced transport retries. Keep saved-destination, duplicate and safe batch-recovery constraints at both existing help entry points; verify rendered content and links.
Contract-Neutral: Documentation-only clarification of existing webhook retry behaviour; no runtime or subsystem contract delta.
Change-source: pulse-maintainer
Stage successful fetch times until raw state publication, preserving expired cache on every enumeration abort. Check cancellation after running-task correlation too, so an interrupted final read cannot publish incomplete artifacts or renew their cache. The next ordinary poll then refetches lost verification changes rather than reusing an old verified row.
Contract-Neutral: Repairs existing PBS cancellation, cache-publication and collection-quality semantics; no wire, schema, policy, freshness window, route or guest-probe contract change.
Change-source: pulse-maintainer
The first control exposed two fixture setup errors: the never-reached datastore and namespace incorrectly advertised another baseline snapshot. Only the archive root contains data; cancellation trigger and next-boundary sentinels now enumerate empty inventories. Retain the original adverse control, and guard failed recovery cardinality before inspecting identity.
Contract-Neutral: Repairs only the cancellation test fixture; no runtime or contract changes.
Change-source: pulse-maintainer
Preserve the exact specialist commit and retained policy and mirror proof; improve the existing bug forms without requiring diagnostics or adding a product surface.
Change-source: pulse-maintainer
Exercise datastore, namespace, completed enumeration and task-correlation aborts, then recover without flushing cache and inspect raw, mapped, persisted and subject-linked posture.
Contract-Neutral: Adds discriminating regression proof for existing PBS cancellation and cache semantics; no runtime or contract delta.
Change-source: pulse-maintainer
Preserve Web candidate 62b7e47f45 exactly. Independent diff and retained rendered-help controls confirm deployment-aware links, independent thaw/every-covered-filesystem writes/liveness, failed-check pauses, prior-active restoration and outage coverage. No runtime, native recovery, full build or publication acceptance is claimed.
Contract-Neutral: Integrates an existing Troubleshooting guide, matching public mirror and regression tests; no product runtime, interface, dependency, route or backup-safety policy change.
Change-source: pulse-maintainer
Preserve Delivery's exact a8271238e1 and b17d23665f commits. Independent diff and retained source-ydvltcos review confirm unchanged checks, budgets and workflow settings with type/build/size checks ahead of the full unit suite. No frontend runtime source changes or native-recovery acceptance are claimed.
Contract-Neutral: Merge reviewed frontend CI step ordering and its regression test; no product interface, dependency graph, bundle budget or required-check change.
Change-source: pulse-maintainer
Replace the thaw-only restart shortcut with independent post-backup thaw, writes to every covered filesystem and workload liveness. Route affected systemd and Docker/Compose users to the shared precaution, preserving in-flight uncertainty, failed-check pauses, prior-active restoration and outage coverage. Check the rendered entry point against its exact parent.
Contract-Neutral: Existing help and regression checks only; guest operations, backup safety policy, APIs, frontend runtime and dependencies are unchanged.
Change-source: pulse-maintainer
Ask for optional existing platform-release and API/agent context in both bug forms. Keep the Pulse deployment separate, accept unavailable details, and forbid active diagnostics or connection changes just to report. Preserve all required core report fields and the matching triage and contributor guidance, including shipped mirrors.
Contract-Neutral: Issue-form context, contributor guidance and regression checks only; no runtime, API, permission or canonical subsystem shape changes.
Change-source: pulse-maintainer
A host agent past its reporting lease is offline: the monitor marks it
so and raises "Host is offline". The registry's stale pass ranked the
agent's stale sighting above offline, though, so the machine reached
every consumer as a warning. The Machines table showed it amber and
rendered its last CPU, memory, disk and temperature as current readings,
while its own drawer led with the critical offline alert. A Docker host
was offline only until its sighting crossed the 120-second stale
threshold, then flipped to warning, and Kubernetes clusters likewise.
Each sighting now records when a push reporter (host agent, Docker,
Kubernetes) delivered its machine, Docker host or cluster as offline,
and status aggregation counts that as offline whatever the sighting's
age. The sighting itself still reads stale, and a live source still
carries a merged row, so a Proxmox node with a dead agent stays online.
A copy that went through JSON re-derives the marker from its stored
status, and a manual link joining two resources from one source keeps
the fresher sighting, so a retired agent cannot pull a live one down.
Offline rows then take the existing danger gate. The Machines Uptime
and Temp cells and the Docker hosts Temp cell had no gate and now
follow it. The drawer drops a silent agent's uptime and marks its
non-disk Thermals rows "(last known)", as retained disk rows already
are.
Run the same forty-target ordinary-poll identity, empty, unavailable, denied, recovery and instance-isolation lifecycle for containers, matching the visible LXC rows in issue 2621. This distinguishes raw artifacts from persisted canonical protection without claiming the original report is reproduced.
Contract-Neutral: Adds container coverage to existing PBS polling regression proofs; no runtime or contract changes.
Change-source: pulse-maintainer
Close the token-response fence that swallowed the Audit Log heading and first endpoint, and route migration recovery's safe-reporting link to the existing Getting Help section. Check actual rendered fragment destinations across all shipped guides, including nested documents, rather than accepting headings that only exist inside code blocks.
Contract-Neutral: Documentation rendering inputs and navigation regression tests only; frontend runtime, API behaviour, guest operations, storage, permissions and delivery controls are unchanged.
Change-source: pulse-maintainer
The omitted-unit-suite control raised ValueError instead of an assertion. Require each step exactly once before checking positions so the control reports the intended missing-check failure.
Contract-Neutral: Regression-test diagnostic only; the frontend workflow and all product contracts are unchanged.
Change-source: pulse-maintainer
Carry snapshot and partial-namespace failures into provider history evidence, do not renew failed cache reads, and reconcile absent points only after complete enumeration. Preserve ingest ordering across partial polls and prove ordinary root-namespace identity, withdrawal, failure and recovery.
Contract-Neutral: Repairs existing PBS completeness, permission and authoritative-reconciliation semantics; no wire, policy, schema, route or guest-probe contract changes.
Change-source: pulse-maintainer
PR2624 spent 8m45s on successful unit tests before its deterministic bundle-size rejection; PR2626 and PR2627 now fail at that same gate. Type-check, build the real embedded assets and apply the unchanged size budgets before spending that test time. Passing source still runs every existing check.
Contract-Neutral: Reorder existing frontend CI commands only; no product interface, dependency graph, bundle budget or required-check change.
Change-source: pulse-maintainer
Preserve the exact reviewed help candidate and the current PBS reconciliation link. Require independent thaw, writes to every covered filesystem, workload liveness and prior-active restoration without changing runtime or guest operations.
Change-source: pulse-maintainer
Retain exact candidate 66b828c938 and its source-bound focused race, vet and library-build proof. This guest-only repair needs no held SMART changes. Native recovery and full production build remain separate evidence gaps.
Change-source: pulse-maintainer
The exact PI candidate overlaps the already integrated Web PBS guide. Keep that authoritative guide byte-identical, route Recovery and Troubleshooting to it, and focus the added tests on mirrors and rendered navigation rather than maintaining duplicate safety text.
Contract-Neutral: Existing backup help and renderer navigation tests only; no posture, API, permissions or collection contract changes.
Change-source: pulse-maintainer
Preserve the exact Product Intelligence candidate and retained docs proof. A following additive integration correction will consolidate its overlap with the already-reviewed PBS guide.
Change-source: pulse-maintainer
Preserve the exact published upstream history alongside previously reviewed local integrations. This turn does not select or publish a release.
Change-source: pulse-maintainer
The Recovery guide allowed monitoring to restart after thaw alone. Require independent post-backup thaw, writes to every covered filesystem and workload liveness; preserve prior-active restoration and the in-flight request boundary. Keep the planned pause distinct from incident recovery and verify the rendered guide against its exact parent.
Contract-Neutral: Existing help and its regression checks only; recovery APIs, runtime, backup safety policy, frontend behaviour and dependency graph are unchanged.
Change-source: pulse-maintainer
checkMockAlerts evaluated guests, agents, nodes, storage, PBS, PMG and
Docker against the mock estate but never physical disks. The fixture
keeps a FAILED cohort and worn SSDs stable on purpose, so mock and demo
stacks showed failing and "Replace Now" disks with no disk-health or
disk-wearout alert, and the disk alert lifecycle could not be exercised
without real hardware.
The pass applies the physical disk poller's boundary: only disks on
online nodes, matched by instance and node name, with the linked
agent's --disk-exclude patterns forcing a matched device healthy. The
per-disk evaluation moves into checkPhysicalDiskAlerts so the poller
and the mock pass share one rule. The poller's agent-link settle
deferral is not applied, because fixture links and exclusions are
complete from the first pass.
Like the other loops in checkMockAlerts, the disk loop runs after the
pass's single mode check, so the existing race with leaving mock mode
now covers disk alerts too. That race also involves other fixture
evaluation paths and is left for a monitor-wide fix.
On the public demo's estate (8 nodes) this adds one warning-level
disk-wearout alert and no disk-health alert: that estate has no FAILED
Proxmox disk.
Both production mounts of the Workloads surface, the Proxmox and vSphere
overviews, set `compactGroupHeaders` unconditionally. The non-compact
branch in `WorkloadPanel` (per-column node CPU, memory, disk and I/O
bars or sparklines, uptime, version, temperature) and the
`NodeGroupHeader` column mode and inline host facts that only it reached
never rendered. They were left over from the retired standalone
Workloads page.
This removes the option, the dead renderers and the `NodeGroupHeader`
props that only served them. Grouped host rows keep the shape both pages
already render: one spanning cell with status, linked name, cluster and
agent badges. Host stats stay in each page's own hosts table.
Verification
- No other production consumer: `WorkloadsSurface` → `WorkloadsTable` →
`WorkloadPanel` is entered only from `ProxmoxPageSurface` and
`VmwarePageSurface`; no references in pulse-pro, pulse-enterprise or
pulse-mobile.
- Browser pass on a production build embedded in a private mock backend,
`/proxmox/overview` and `/vmware` at 1440x900 and 390x844, Bars and
Trends modes: every grouped host row is one cell spanning the guest
table's visible columns, with no metric cells or host facts; group-row
clicks open nothing; guest drawers still open; no page errors.
- The rewritten `NodeGroupHeader` test fails against the old component
(its default facts render `PVE 9.1.9`).
- `tsc`, full `npm run lint`, vitest over Workloads, shared, features,
hooks, utils, Storage and app tests (only the Mac-only
`agentInstallCommand` failures, unrelated), bundle budgets, and all
release-control guards pass.
useWorkloadTableMetricHistory ran two polled estate-wide reads per
instance in Trends mode: the workloads history and the infrastructure
summary. Since grouped workload rows lost their host metric cells, the
Workloads surface reads only guest series, and the Proxmox nodes table
never read anything but node series. Each reader passes its own abort
signal, which skips the summary caches' in-flight dedupe, so every
instance paid for both routes every 30 seconds.
A required series option now names the rows a caller draws. The
Workloads state passes 'guests' and the Proxmox nodes table passes
'nodes', so each polls one route. On the demo estate in Trends this
takes the vSphere overview from one infrastructure and one workloads
read per poll to one workloads read, and the Proxmox overview from two
of each to one of each. Node table sparklines are unchanged.
The performance contract claimed the two readers deduped their reads;
it now states that they do not and that each reader polls only what it
renders. The adjacent Bars-mode prose in the performance and
frontend-primitives contracts described one active-row request that
leaving the row cancels; it now describes the bounded warming window
the hook has run since the history lens shipped.
Accept the exact four-file Web candidate with retained rendered-help and exact-parent controls. This is safe existing-guide maintenance, not runtime recovery or published availability.
Change-source: pulse-maintainer
Recompose the exact guest-only source from 8c25205d8544083e2ed873cab7b5593e0e0105a1 and its fixture correction 174f315e26132f167ea3d7ae9818d608b86f0eb0 on assigned main. The rejected combined candidate and its original evidence remain intact; no commit is cherry-picked, re-parented or amended. SMART changes are not required by guest views, transfer, builder or transport. Preserve newer main temperature and resource-boundary repairs.
Contract-Neutral: Internal transfer of existing linked-agent disk inventory; no public model, identity, expiry, guest command or safety policy change.
Change-source: pulse-maintainer
When a host agent passes its reporting lease, its collected SMART
temperatures keep their values with collection.temperature unavailable
(#2593), and #2603 taught the Storage disk surfaces to show such a value as
last known. The frontend HostDiskSMART type never carried `collection`, so
the agent's own surfaces kept presenting the retained readings as current:
- The Machines temperature cell fell back to the hottest SMART reading and
coloured it against the disk thresholds. On a live mock stack a silent,
SMART-only agent read 52°C in threshold green.
- Its tooltip, the machine drawer's Thermals rows and the guest drawer's
Physical Disks card listed the retained disks as plain readings.
The row does not make this obvious. By the time the lease expires the
registry has marked a standalone agent's source stale, which outranks
offline, so a silent agent reaches the table as `warning` with
`agent.stale`, not `offline`. The offline metric fallback never blanks its
cells, and the temperature cell has no such gate.
Now `HostDiskSMART.collection` is typed and every reader decides through
`isPhysicalDiskTemperatureCurrent`:
- A retained disk reading never stands for the machine while another disk is
current. When no non-standby disk is current and the machine has no
positive direct or temperatureCelsius reading, the cell shows the hottest
retained non-standby value muted with a dotted underline and screen-reader
"last known", without threshold colour.
- Tooltip and Thermals rows read "(last known)", the Thermals row with the
collection reason as its title. A disk with a zero or negative reading no
longer shows a temperature row there.
- The guest Physical Disks card uses the Storage table's last-known
treatment.
The temperature helpers move to diskTemperaturePresentation.ts, which
diskPresentation.ts re-exports. On the earlier base, importing
diskPresentation from the Machines page and the drawer mapper folded the
whole Storage presenter into the shared chunk (+4.9 kB gzip) and renamed its
tracked budget entry, failing the bundle check. With the small module,
Standalone grows 0.22 kB, the shared chunk 0.20 kB, and Workloads is flat
against a build of main. The guest card still loads diskPresentation for
extraction and health.
Direct and temperatureCelsius readings carry no collection state and still
lead the cell. A stale agent's CPU, memory, disk and sensor values still
render as current. That is a row-wide decision, left for a separate change.
Distinguish listed artifacts and verification from workload posture, link one-row passive checks from existing help, and preserve native identity, privacy and backup-safety boundaries. Add shipped-renderer and navigation regression checks.
Contract-Neutral: Existing backup help and tests only; no posture, API, permissions or collection contract changes.
Change-source: pulse-maintainer
The Proxmox node drawer's **CPU low** and **CPU record** rows repeated
the current temperature for every node without a host agent.
`nodeFromResource` never read `proxmox.temperatureDetails`, which is
where the resource API publishes the poller's full reading, including
its low and record values. For those nodes it fell back to the scalar
`proxmox.temperature` and copied that one value into both fields. On the
dev stack, `delly` and `minipc` showed CPU low = CPU record = current.
- The adapter now takes the first source with a usable reading.
`temperatureDetails` comes after the platform record and the agent
facet, so agent-linked nodes render exactly as before.
- The bare-reading fallback leaves low and record unset, so the drawer
omits those rows rather than inventing them.
The poller also reset those values to the current reading every poll.
That is a separate backend fix to the previous-node projection, landing
in its own PR. Until it lands, PVE-only nodes will still show low =
record = current, now because that is what the backend reports.
### Verification
- Unit tests pin the API's real payload shape (scalar
`proxmox.temperature` plus `proxmox.temperatureDetails`), the no-record
fallback, and agent-facet precedence. The new test fails against main's
adapter, which returns `cpuMin` 58 = current.
- Browser pass on a private mock stack at `/proxmox`, 1440x900 and
390x844, with REST and websocket payloads rewritten to make one node
PVE-only:
- main's adapter showed CPU low 82°C / CPU record 82°C;
- this change shows no rows without a record, and 39°C / 91°C with one;
- agent-linked nodes and the table TEMP column are unchanged.
- `vitest` over `src/utils`, `src/components/Workloads`,
`src/features/proxmox` and `src/features/platformPage` passes, apart
from `agentInstallCommand.test.ts`, which fails on macOS regardless of
this change.
Separate matched and verified artifacts from subject-linked protection and independent recovery. Give the existing PBS guide a passive Coverage check, preserve private identities and backup safety, and validate rendered guidance and exact shipped content.
Change-source: pulse-maintainer
GuestDrawerOverview statically imported GuestPhysicalDisks, which pulled
all of diskPresentation.ts into the WorkloadsSurface table chunk. With the
Running Hot verdict that chunk measured 70.64 kB gzip against its
70.23 kB cap, so the Frontend bundle check would fail.
The card renders only inside an open drawer for a guest with a Pulse
agent, so the overview now lazy-loads it under a local Suspense, the same
pattern as the bulk web-link editor. WorkloadsSurface drops to 64.31 kB
and the disk presentation builds as its own chunk. The contract test pins
the dynamic import.
Accept exact Web candidate 7da8c65397 with retained source-0t9a7bbo. Preserve existing guidance and upstream contracts alongside the already-present Machines alternative, same-guest identity, observation age and independent backup-safety boundaries. This is guide maintenance, not native recovery, browser acceptance or publication.
Change-source: pulse-maintainer
Accept exact Delivery candidate c6c7babd50 with retained source-mr82f4uj and parent/kind-only rejection controls. Preserve the upstream removal of the never-mounted resource table. This changes test assertions only and makes no rendered or native acceptance claim.
Change-source: pulse-maintainer
Preserve canonical 42d045fd81 and the exact published disk-state repair d9ffb39ce8 fetched by host preparation. No candidate re-parenting or frontend content correction.
Change-source: pulse-maintainer