Retain the actual authentication refusal and existing client when the full-timeout session cannot be constructed after a successful short probe. Cover pinned HTTPS rejection, malformed and form-refused sessions, later ordinary recovery and the monitor endpoint projection.
Change-source: pulse-maintainer
Every resource drawer now charts history on its Overview. The storage
page's pool and physical-disk details were the last to keep it behind a
History tab, and that was their only other tab, so a reader opened a
pool or disk and then had to switch tabs to see whether it was filling
up or heating.
Both now render one view with no tab strip. A pool detail leads with its
Capacity Trend card, the range picker in the card header, followed by
configuration, topology and devices. A disk detail keeps its health
verdict and SMART facts first, as the evidence behind the verdict, then
its History charts with the range picker beside the heading, then live
I/O.
The storage contract had required these charts to stay behind the
History tab; it now records the 2026-10-13 decision instead.
PR 2913 moved the Proxmox guest and node drawers' charts onto Overview
and removed their History tab. The Docker host drawer and the shared
resource-detail drawer (agent machines, containers, PBS, TrueNAS,
Kubernetes and other platform rows) still kept the charts a tab away,
so the same kind of drawer behaved two ways depending on the page.
Both now render the history charts on Overview under the attention
list, opening on 24 hours with the range picker beside them, and drop
the History tab. Charts stop polling while another tab shows, and an
active alert on a charted metric draws its trigger the same way as in
the Proxmox drawers. A resource whose metrics target drops for one
snapshot simply loses its charts until the target returns; the
selected tab is kept.
Storage page disk and pool details keep their own History tab; they
are separate components and their Overview has no charts to repeat.
E2E specs 27 and 63 no longer click History; the drawer read starts
when it opens. The manual tab-retention proof now selects Manage. Its
fixture page fails before the drawer renders (no WebSocket provider)
on main as well, so it was not run.
Drawer charts plot one average per time bucket, so a short CPU burst or
I/O spike inside a 6-minute bucket (24h) or an hourly rollup (7d) shrinks into
the average and disappears. The trend cards this Overview replaced
stated a "24h low-high" range; the charts had nothing in its place.
Each stored point already carries its bucket's min and max. A tinted,
outlined band now spans those extremes behind every line, so a spike
stands as a spire above the average. Series whose buckets never spread
draw no band. While a time is inspected, the legend names that bucket's
peak when it rises at least a tenth of the plot above the average, and
the accessible value states each reading's average and range.
Spec 86 also allows sub-pixel clipping when it checks that the drawer's
Memory rows are fully in view. With the charts on Overview, CI placed
that table on a fractional offset and the rounded table border clipped
0.4% of it (ratio 0.9956), failing an assertion of exactly 1.
Opening a Proxmox guest or node drawer showed 24-hour trend cards for
CPU, memory and disk on Overview, then a History tab with the same
metrics in a different chart style, opening on 7 days, plus network,
disk I/O and thermals. One tab was a superset of the other.
This charts history on Overview itself and removes the History tab from
the guest and node drawers (tabs are now Overview and Manage):
- Overview reads: alerts line, Worth checking, the charts (24 hours by
default, range picker beside them), disks and sensors, facts strip,
closed Details.
- Charts poll only while Overview is shown, and show the live reading
(qualified current or last known) until history is stored. An offline or
stale node says so in one line and offers no live values.
- An active alert on a charted metric tones its reading and, with a
numeric trigger, draws a dashed line. I/O triggers are converted from
the alert engine's MiB/s to the charts' B/s.
- The facts strip carries the amounts behind the percentages: guest
vCPUs and used-of-total RAM and disk; node used-of-total RAM and root
disk.
- The range picker mints its id once per instance (a guest and a node
drawer can be open together). Legend readings are larger, and the charts
use two columns at medium widths.
Docker host and resource-detail drawers keep their History tab for now.
Verification: typecheck and the Workloads, shared, Proxmox, Docker and
Infrastructure suites (305 files, 5752 tests) on pulse-dev.
Full-resolution screenshots of the built bytes at 1440, 1000 and 390px;
the receipt lists what was exercised. The dashed alert line was not seen
in the browser (no Proxmox guest or node had a metric alert in the mock
estate) and is covered by unit tests.
Opening a Proxmox guest or node drawer showed 24-hour trend cards for
CPU, memory and disk on Overview, then a History tab with the same
metrics again, in a different chart style and opening on 7 days, plus
network, disk I/O and thermals. One tab was a superset of the other,
so the reader had to reconcile two views of the same data.
The guest and node drawers now chart history on Overview itself, under
the alerts line and Worth checking, opening on 24 hours with the range
picker beside the charts. The History tab and the trend cards are gone.
The charts stop polling while Manage is shown, show the live reading
(qualified current or last known) until history is stored, and an
offline or stale node says so in one line instead of offering live
values.
What the cards carried and the charts lacked moves with them:
- An active alert on a charted metric tones its reading and, when it has
a numeric trigger, draws it as a dashed line. I/O triggers are
converted from the alert engine's MiB/s to the charts' bytes per
second, and networkIn/networkOut map to the netin/netout series.
- The facts strip states the amounts the percentages are of: guest
vCPUs and used-of-total RAM and disk, node used-of-total RAM and root
disk (capacity only while a node's readings are withheld).
The range picker now mints its id once per instance, so a guest and a
node drawer open together no longer share a label target. Legend
readings are a step larger and the timestamp quieter, and the charts
use two columns at medium widths. Docker host and resource-detail
drawers keep their History tab for now.
Give each installer and signature transfer a five-second connection and sixty-second total budget, ignore ambient curl settings and preserve HTTPS through redirects. Failed or partial downloads leave the prior install, service and identity unchanged; pinned signature admission and recovery deadlines are unchanged.
Change-source: pulse-maintainer
Separate resource-owned PBS health and identity from inventory loading/error gates. Preserve source-specific notices, unknown counts and ordinary retries; make complete optional signing environment names readable on phones without changing trust or copying.
Change-source: pulse-maintainer
The Workloads guest table put a second line under memory and disk cells
that repeated an empty cell and gave no reason: "N/A / Unavailable" and
"- / Unavailable" on every stopped guest, "Unavailable" under every
agentless VM's disk, and "May include cache" under every agentless VM's
memory bar regardless of value.
What changes:
- Memory that cannot be read renders the same dash as an unreadable
disk. Its reason stays in the cell title, the sparkline's hover title
and assistive text. Sparkline accessible values are unchanged.
- Disk shows a visible label only for a retained reading (Last known /
Prior) or a read the user can fix (No permission / Agent error, amber).
Stopped VMs, missing guest agents and lock deferrals show the dash.
- "May include cache" appears only when the guest's own memory is at its
warning or critical threshold (the figure the bar is coloured by, in
host-share mode too), the case from #2762 and #2639. Below that, the
caveat is title and assistive text.
- Unavailable memory explanations name what is known rather than
"Unknown source"; a powered-off guest reads "Unavailable while the guest
is powered off."
- `MetricMiniSparkline` gains an optional `tooltip` so the chart
covering the cell carries that reason without changing its accessible
name.
User guide: `docs/VM_DISK_MONITORING.md` (and its shipped mirror) now
describes the labels the row shows, and
`test_guest_disk_reading_docs.py` pins them. This replaces #2893, whose
docs recipe test still expected the old labels.
Contracts: `frontend-primitives.md` and `performance-and-scalability.md`
describe the new caption rules. Four browser proof scripts and
`86-hybrid-memory-browser.spec.ts` are updated to the new behaviour; the
proof scripts need their container harness and were not run here.
Verification: Workloads suites (106 files, 2160 tests),
`memoryObservation` and `MetricMiniSparkline` tests, lint, Prettier and
type check pass. Browser receipt `6e39cc0902eefe58.json` records a live
pass on a mock stack built from main, in Bars and Trends at 1900x1100
and 375x812: captions only on the cache VM at warning, dashes on stopped
and agentless rows, rows 32px / 44px, no overflow.
The Workloads table put a second line under memory and disk cells on
every stopped guest ("N/A / Unavailable", "- / Unavailable"), on every
agentless VM's disk, and "May include cache" under every agentless VM's
memory bar, even at 20%. None of them said why or what to do, and they
broke the row rhythm.
Memory that cannot be read now renders the same dash as an unreadable
disk, with its reason in the cell title, the sparkline's hover title
and assistive text. Disk shows a visible label only for a retained
reading (Last known) or a read the user can fix (No permission, Agent
error). The cache caption appears only when the guest's own memory is
at its warning or critical threshold, the figure that colours the bar
in host-share mode too, which is the case #2762 and #2639 were about;
below that the caveat stays in the title and assistive text.
An unavailable memory explanation names what is known instead of
"Unknown source": a powered-off guest reads "Unavailable while the
guest is powered off." MetricMiniSparkline gains an optional tooltip
so the chart covering the cell can carry that reason without changing
its accessible name.
Retain the exact existing safety candidate after returned final drawer proof; preserve current consuming source and mock History refinements. Native restart, every-volume History and independent thaw remain unverified.
Change-source: pulse-maintainer
Preserve main's neutral denied-access state, wrapped Details and current
node metrics while retaining permission help across reading updates.
Verify disclosure dismissal, responsive placement and shipped docs.
Refs #1802
Three rules chose a node's single CPU temperature. Node history took
CPUMax first, agent history took cpu_package first, and the node drawer
recomputed the maximum of package, CPUMax and every core in the
browser. On an agent-fed node CPUMax is built from cores alone and can
sit below the package, and elsewhere a core can run above the package,
so the drawer's CPU temperature headline could disagree with the line
drawn beneath it and with the History tab. Node alerts and the CPU
low/record tracking used yet another package-first rule.
models.PrimaryCPUTemperatureCelsius is now the one rule: the hottest
usable package, CPU-maximum or core reading, with a sensor-map form for
agents. Node and agent history, the router's live fallbacks, the
unified resource temperature, node temperature alerts and the CPU
low/record tracking all call it. The drawer reads the resource value
through a new Node.cpuTemperature field instead of recomputing it, and
getCpuTemperature is removed.
Mock mode wrote a second package reading under a cpu.package key into
every agent host, including node-linked ones, from a series unrelated
to the node's static reading. A node and its linked agent now carry one
reading, sampled from the agent's series under the agent's real keys,
and both histories seed from that series, so the current reading
continues the line.
Preserve cb778998d7 identity and its unchanged frontend runtime. Resolve duplicate drawer receipt, contract and regression assertions to the already-qualified canonical versions; neither a merged receipt nor synthetic proof is native recovery.
Change-source: pulse-maintainer
Preserve the complete accepted local tip and exact published 526fa790ae additively. Keep upstream chart attention, neutral denied-update status and wrapping together with the reviewed reading and accessible update guidance.
Change-source: pulse-maintainer
Keep compact exceptions, chart axes and neutral denied status in Details. Preserve full facts, last-known disk evidence and the persistent accessible update-help control. Resolve both source and regression/contract semantics additively; final combined bytes still need their own consuming browser receipt.
Change-source: pulse-maintainer
Preserve the exact reviewed private-input candidate and its source-bound receipts. Qualify changed drawer composition separately; no native or release acceptance is claimed.
Change-source: pulse-maintainer
Mirror the qualified Unix reader in setup, Proxmox and container producers: select one terminal tool, distinguish missing terminal/tool/mode failures, restore its complete state before installation and on cleanup, and retain silent overflow draining. Emit the isolated privileged body once without changing tokens, trust, scopes, profiles or state. Cover serialized contracts and actual consumer payloads.
Change-source: pulse-maintainer
Stacked on #2909 (its commit is the parent here and lands with either
PR).
A full-resolution visual pass of the guest and node drawers, plus a Sol
review of the same screenshots, found the charts and attention hard to
read:
- **Numeric axes.** History I/O axes read "Max / Avg / 0" with no
magnitude, and "Avg" was the scale midpoint, not a measured average
(demand ledger "Numeric axis labels on history I/O charts", #1720).
Thermals read "Max / Mid / Min". Gridline labels now state the scale
value (e.g. `5.0M/s`, `60°C`) and sit centred on their gridlines.
- **Worth checking up front, one line each.** It was a full card per
section below the charts. It is now a compact list directly under the
alerts line, using the shared detail-row tone.
- **Now vs history.** Trend card headlines say "now", and the range
reads "24h low–high", so the live number is not read as the last point
of the stored line.
- **No text wall.** The two-sentence memory-cache caveat under the
charts (repeated in Details) becomes "may include cache" on the Memory
card; the full note stays once, in Details.
- The missing-readings note is one line, and the Details summary uses
readable text.
Tests: the full frontend suite passes (15,467). New proofs: Worth
checking renders above the trend cards with the shared tone, and the
guardrail pins that the list reuses `detailValueToneClass`. Browser
receipt: full-resolution screenshots of every drawer tab at 1440 and
390px, reviewed.
Follow-ups not in this PR (from the same review): threshold lines on
History charts, a crosshair shared across panels, taller History plots,
a Manage tab layout pass, and status text beside the drawer's status
dot.
Use a POSIX root/sudo prefix inside the isolated subshell rather than duplicating the long quoted reader. Synchronise PTY command entry and exit with the caller prompt, retain full terminal/privacy/overflow assertions, and follow current help rows by their labels. The browser driver now inspects the full Linux card.
Change-source: pulse-maintainer
- **Denied update check is a setting, not a fault.** The node drawer
listed "Updates: Unavailable · Update check access denied" in amber
under Worth checking. Proxmox gates the package list on `Sys.Modify`,
and `docs/TROUBLESHOOTING.md` calls keeping the narrower monitoring role
a valid choice, so `permission_denied` now reads neutral and stays in
Details. A source outage or failed check is still a warning and still
surfaces under Worth checking.
- **Node Details values wrap.** The update reason, linked agent ID and
CPU model were cut off behind an ellipsis that only a hover could
reveal. Details rows now wrap them.
Verified in headless Chromium against a mock-mode build, with
`/api/resources` rewritten to inject each update state, reviewing
full-resolution screenshots at 1440 and 390px. Tests: unit tone tests, a
drawer test that keeps the denied check in Details with a wrapped value,
and a failed-check test that keeps it under Worth checking. Putting the
tone back to warning fails two of them. 813 node, Proxmox and guardrail
tests pass.
Preserve the exact reviewed tip and incorporate current upstream History default, marker shape and readout behavior additively.
Change-source: pulse-maintainer
Mock chart history thinned each metric with LTTB on its own. LTTB keeps
value-dependent points, so the metrics of one resource ended up with
different timestamps. The public demo (6.5.0) showed this: a container's
24h history had eight ~48-point series spread over 162 distinct
timestamps, and a node's had 166. The drawer History panels break a line
wherever another series in the panel has a reading, so every mock chart
drew as dots with "Missing observations". Real poller history writes all
of a resource's metrics at the same times.
Mock series are now thinned onto an epoch-aligned grid. Each bucket
keeps its first reading, the newest reading is kept too, and every point
keeps its own timestamp. Point targets and values are unchanged.
Verification:
- `TestMockChartHistorySharesTimestampsAcrossMetrics`
(`monitor_metrics_slo_test.go`) checks a mock VM, container and node, on
synthetic and seeded history, at 1h, 4h, 24h and 7d. It fails on the
previous code (5 of 20 memory timestamps shared with cpu) and passes
now. `internal/monitoring` passes in full.
- On a mock-mode build of this branch, `/api/metrics-store/history`
returns a timestamp union equal to the per-series count for a VM, a
container, a node and an agent at 1h, 24h and 7d. The drawer History tab
draws one continuous path per series with no "Missing observations". The
unpatched build of the same estate showed 82 dots and the note on all
three panels.
A full-resolution visual pass of the guest and node drawers (and a Sol
review of the same screenshots) found the charts and attention hard to
read:
- History I/O axes read "Max / Avg / 0" with no magnitude, and "Avg"
was the scale midpoint, not a measured average; thermals read
"Max / Mid / Min". Gridline labels now state the scale value at each
line (e.g. 5.0M/s, 60°C) and sit centred on their gridlines.
- "Worth checking" was a full card per section below the charts, so a
21-day-old backup took three lines and read last. It is now a compact
label/value list directly under the alerts line.
- Trend card headlines could be read as the last point of their line.
Each now says "now", and the range reads "24h low–high".
- A two-sentence memory-cache caveat (with unrelated agent-setup advice)
sat under the charts and again in Details. The Memory card now says
"may include cache"; the full note stays once, in Details.
- The missing-readings note shrinks to one line, and the Details
summary uses readable text.
The node drawer listed "Updates: Unavailable · Update check access
denied" in amber under Worth checking. Proxmox gates the package-update
list on Sys.Modify, which is broader than monitoring needs, and
docs/TROUBLESHOOTING.md calls keeping the narrower role a valid choice.
A deliberate setting is not a fault, so that reason now reads neutral
and stays in Details. A source outage or failed check is still a
warning and still surfaces under Worth checking.
Node Details rows also wrap their values instead of truncating them.
Details is where a reader goes for the full value, yet the update
reason, the linked agent ID and the CPU model were cut off behind an
ellipsis that only a hover could reveal.
Select the BusyBox stty applet only when standalone stty is absent, fail before unsafe entry on terminal-control errors, and restore modes with the selected tool. Expose the existing private-file installation alternative on Linux/NAS alongside FreeBSD without changing issuance, TLS, removal or privilege.
Change-source: pulse-maintainer
Two drawer History presentation fixes, both reported while previewing
the drawer redesign:
- **Oval dots.** The plot stretches its viewBox to the panel
(`preserveAspectRatio="none"`), so the `<circle>` markers for single
observations and the hover cursor rendered as wide ovals. They are now
zero-length, round-capped strokes with a non-scaling stroke, so they
stay round at any width. Series lines carry `data-history-series` so
tests can tell lines from dots.
- **Jumping note.** "A dash means no stored observation at this time"
appeared and vanished as the inspected time changed, pushing the chart
up and down while scrolling past it. A missing value now reads **no
reading** in the readout itself, and the line is gone. In a pointer
sweep the chart height stayed constant (202px at 1024, 327px at 390).
Tests: History tests select lines by `path[data-history-series]` and
hover markers by `[data-history-hover-marker]`. A new guard checks the
plot has no `<circle>` and that dots are round non-scaling strokes. The
readout assertions now expect "no reading". Workloads, Infrastructure
and Docker suites pass (3,692 tests). Contract notes in
`frontend-primitives` and `performance-and-scalability`.
Mock chart history thinned each metric with LTTB on its own. LTTB keeps
the points whose values stand out, so cpu, memory and disk of one guest
kept different timestamps: on the public demo a 24h container history
had eight ~48-point series spread over 162 distinct timestamps. The
drawer History panels break a line wherever another series in the panel
has a reading this one lacks, so every mock chart drew as dots with a
"Missing observations" note. Real history does not do this because the
poller writes all of a resource's metrics at the same times.
Thin mock series onto an epoch-aligned grid instead: keep the first
reading in each bucket plus the newest reading, at their own
timestamps. Which readings survive now depends only on when they were
taken, so series sampled together keep identical timestamps, values
stay real readings, and point targets are unchanged. The synthetic
generator no longer pre-thins to 500 points, since every caller thins
onto the grid.
The History plot stretches its viewBox to the panel width
(preserveAspectRatio="none"), so the <circle> markers for single
observations and the hover cursor rendered as wide ovals. They are now
zero-length, round-capped strokes with a non-scaling stroke, drawn in
screen pixels, so they stay round at any width. Series lines carry
data-history-series so tests can tell lines from dots.
The readout explained a missing value with a separate line, "A dash
means no stored observation at this time", which appeared and vanished
as the inspected time changed and pushed the chart up and down, most
visibly while scrolling past it. A series without a reading at the
inspected time now says "no reading" in the readout itself, and the
extra line is gone.
Merge exact Web candidate f034be1854. Resolve drawer overlap to its browser-verified contents and System facts controls; retain canonical GuestDrawer assertions, newer agent help, updater repair and consolidated contracts. Retained source and browser proofs qualify presentation only, not native workload or QGA recovery.
Change-source: pulse-maintainer
The typed-reply fixture keeps the successful memory cache untouched, so the selector legitimately retains guest-agent-meminfo provenance rather than the expired-cache previous-snapshot label. Require that exact source while preserving strict last-known state, original observation time, unchanged cache and History checks.
Contract-Neutral: Fixture expectation and proof description only; runtime source selection, guest admission, observation ages, API and History semantics are unchanged.
Change-source: pulse-maintainer
Validate result/content/truncated types before shared guest-command admission is released. Scalar results must not become empty inventories, and wrongly typed file fields must not release admission before decoder failure. Preserve compatible empty/null rows and completed but unusable measurements. Add six-reader, alias/expiry and actual-state polling/broadcast/History controls with untouched healthy-read origins. Native thaw and restart recovery remain separately unverified.
Change-source: pulse-maintainer
The guest and node drawer Overview now shows 24h trend cards for CPU,
memory, disk and temperature, so a History tab that also opened on 24
hours repeated them. History now opens on 7 days for those drawers:
Overview answers "what is it doing now", History "what is normal this
week", with any range still selectable. The free plan keeps 7 days, so
the default is never locked.
The trend cards read their own 24h constant, and a 24h History
selection still reuses their cached read. Drawers without trend cards
(Docker host, resource detail) keep the 24h History default.
Preserve exact reviewed d636bfdaea and published 0a44d276db ancestry. Retain both contract additions, readable System evidence and stable accessible update help alongside upstream alert-first trends, facts and Details.
Change-source: pulse-maintainer
Keep shared tenant-store, backup association, source identity, grouping,
installer qualification and alert evidence rules at their canonical owners.
Consumer contracts retain scoped references and their distinct local rules.
Remove obligations for the deleted Discovery scanner and backfill. Replace
superseded chart-padding expectations, telemetry schema history and test
names with the current source contracts while retaining VM backup precautions,
privacy limits, paid behavior and native qualification boundaries.
Cover closed-Details OS and filesystem guidance plus stable update help across readings, relative ages and evidence changes. Add a compiled safe-observation browser fixture for the combined drawers and shipped Docs.
Contract-Neutral: Connected composition regression and browser fixtures retain existing source behaviour and document the merge outcomes.
Change-source: pulse-maintainer
Keep removal safety requirements in agent lifecycle and replace deployment
copies with scoped references. Keep legacy Assistant mode-echo compatibility
and security setup settings preservation in the API owner, so their consumers
do not maintain separate copies of the same obligations.
Runtime behavior, paid entitlement checks and native qualification limits
remain unchanged.
Keep published alert-first 24-hour trends and closed Details. Preserve phone filesystem guidance, full OS facts, and a drawer-owned update-access help dialog outside the demoted inventory. Retain both independent subsystem contract additions.
Change-source: pulse-maintainer
Avoid rewriting an already-replaced QNAP executable through an aliased persistent path. Stage split QNAP and Unraid copies in owned same-directory temporaries, set execute permissions before atomic replacement, and clean every failed stage without changing saved state or update trust. Add authenticated HTTPS and real child-exec regressions plus persistence failure and recovery controls. Native appliance and old-installed-updater recovery remain separate.
Change-source: pulse-maintainer
Patrol's operator-state projection dereferenced the one-shot
MaintenanceStartAt/EndAt whenever IsInMaintenanceAt was true. A
recurring window also reports active but leaves those fields nil, so
the first finding Patrol evaluated during a recurring occurrence
panicked the provider. The projection now takes its bounds from the
active occurrence.
Alerts already silence guests under a host window scoped to
resource_and_descendants, but Patrol read only the exact resource, so
the same planned work dismissed a guest's alerts and still raised its
Patrol findings. Both now resolve maintenance through one rule,
unifiedresources.ActiveMaintenanceCoverageAt: own window plus
descendant-scoped ancestor windows, latest active end wins. Only
maintenance is inherited; monitoring mode, lifecycle and remediation
locks stay exact-resource state. An inherited dismissal says the window
is on a parent resource and names it on the lifecycle event, and the
Manage help now says descendants' new Patrol findings are dismissed
too.
Retain the shared resolver and request authority while retrying only failed socket establishment. Usable addresses share one bounded dial budget; cancellation prevents further attempts and TLS still authenticates the original hostname and pin. Connected controls reproduce the first-address defect and cover cache reuse, families, deadlines and cancellation.
Change-source: pulse-maintainer
The Proxmox guest and node drawers' Overview was a grid of equal-weight
inventory cards, much of it repeating the table row, while the trend
that answers "is this getting worse?" sat on the History tab.
**Overview now leads with what is wrong:**
- Active alerts first (unchanged component), or one "No active alerts"
line.
- 24h trend cards for the metrics the row shows: CPU, memory and disk
for guests; CPU, memory, CPU temperature and root disk for nodes. A card
with an active alert on its metric is coloured and draws the alert's own
trigger.
- "Worth checking": any warning- or danger-toned detail row, lifted from
whichever section owns it, so demotion never hides a reason a reading
cannot be trusted.
- Guest filesystems, physical disks, RAID, node GPU/NVMe sensors, and
any availability check that is not both fresh and healthy stay visible.
- A one-line facts strip (OS, address, healthy last completed backup,
tags).
- Everything else in a closed **Details** disclosure that keeps its rows
mounted for find-in-page.
**Correctness details:**
- Trend cards and the History tab share one query and cache key
(`guestDrawerHistoryQuery.ts`); each polls only while its tab shows. The
node drawer's History no longer stays mounted and polling while hidden.
- Node cards are coloured only by the node's own alerts, which
`ProxmoxNodesTable` now passes as `ownAlerts` by identity; the drawer's
`alerts` list also carries its guests' alerts by node name.
- Offline or stale nodes, last-known or unknown memory, and unmeasured
disks show as not current or last known, never as live values or
filled-in zeros.
- Ranges use bucket min/max, so a spike averaged away inside a bucket
still shows (delly's CPU temperature reads 42–92°C, not 44–73°C).
- A failed refresh says it is showing the last loaded trend.
**Governance:** amends the `frontend-primitives` rule that curated
drawer facts must not need another tap, for these two drawers only.
Recorded as a named bet in the demand ledger (rcourtman/pulse-pro#419),
graded at +30 days. Contract notes in `frontend-primitives`,
`performance-and-scalability` and `unified-resources`.
**Verification:**
- Full frontend suite: 23,213 passed. Lint, typecheck, production build
and bundle budget pass (`useWorkloadsState` 55.88 kB of 70.23 kB).
- Six negative controls: reverting each fix fails its targeted test.
- Browser pass on the real homelab estate at 1280, 1024 and 390px. The
receipt is in `frontend-modern/browser-verification/`.
Preserve reviewed dd2dbeab8f and exact published aa0c25de4c additively after upstream advanced at the publication boundary.
Change-source: pulse-maintainer
Bind the credential-free capture handshake to the polling context under the existing five-second ceiling. Recheck cancellation before publishing a runtime pin; retain established trust, endpoint selection and ordinary declared-member first use. Add local stalled-handshake, peer-closure, no-dial and later-recovery controls.
Change-source: pulse-maintainer