Commit Graph

15115 Commits

Author SHA1 Message Date
pulse-triage[bot] c0cb7a02db Keep System controls scoped to the composed drawer surfaces
Final-source proof source-gvq604pb passed types and 492 tests but exposed nine obsolete fixture assumptions after additive upstream composition. Scope upstream OS facts assertions to the visible facts strip and open native Details before checking the retained full System row. Preserve all value, wrapping, freshness and mounted-identity assertions; no runtime source changes.

Contract-Neutral: Integration test selectors and native disclosure setup only; production drawer bytes and behavior are unchanged.
Change-source: pulse-maintainer
2026-10-13 14:16:04 +01:00
pulse-triage[bot] 51e7cf634e Navigate the composed drawers with the shipped tab semantics
The consuming pass now confirms actual captured focus and reading guidance, then exposes the fixture's button-role selector for the semantic History tab. Use its shipped tab role for both transitions; keep the on-demand History check.

Contract-Neutral: Browser control selector correction only; product, source tests and graph are unchanged.
Change-source: pulse-maintainer
2026-10-13 14:09:55 +01:00
pulse-triage[bot] db2615f4da Reconcile published contracts and alert-first drawers with reviewed maintenance
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
2026-10-13 14:09:00 +01:00
pulse-triage[bot] cd4d23e98c Bind guidance focus measurements to the actual captured frame
Retain the pre-capture CSS measurement and exact element classes alongside the captured frame, then apply unchanged strict criteria to the rendered observation. This preserves failing pixels rather than ending with a DOM-only claim.

Contract-Neutral: Browser observation/capture ordering only; no product, threshold, regression or graph changes.
Change-source: pulse-maintainer
2026-10-13 14:06:08 +01:00
pulse-triage[bot] 59c240a5e4 Carry full System evidence tests into the visible drawer facts
The combined full suite passed 23,370 tests but six inherited System tests still queried the removed table row. Keep every OS/name/version/update/liveness case, asserting the actual visible wrapping facts outside closed Details instead of reintroducing a duplicate row.

Contract-Neutral: Test consumer selectors follow the composed facts strip; all existing evidence and visibility obligations remain.
Change-source: pulse-maintainer
2026-10-13 14:02:31 +01:00
pulse-triage[bot] ba71784cef Observe a drawn trend threshold through its visible SVG
A horizontal SVG line has a zero-height box even when its enclosing chart is visible. Require the threshold node and the visible chart without treating Playwright's line-box visibility test as a product failure; pixel inspection remains required.

Contract-Neutral: Browser SVG observation correction only; no source behaviour, chart assertion, regression or graph is changed.
Change-source: pulse-maintainer
2026-10-13 13:58:09 +01:00
rcourtman 0a44d276db Consolidate shared contracts and retire obsolete obligations (#2904)
Shared rules were repeated across subsystem contracts, and some still
required the deleted Discovery scanner or superseded proofs. Keep each
shared rule at its canonical owner with scoped consumer links, retain
local differences, and remove obligations whose runtime or verification
path no longer exists.

Correct the stale temperature-padding expectation, trusted-command
producer description, telemetry adoption fields and proof names against
current source. Qualification stays with the existing customer-journey
document. Assistant, all four Patrol modes, paid entitlements, VM backup
precautions and installer/native qualification limits are preserved.
Runtime code, registry ownership and proof routing are unchanged.

Validation: focused monitoring, API, identity, telemetry and server
tests, contract/registry/status audits, scoped-link and ownership
checks, and normal commit hooks. The two slices remove 466 net lines
across 13 contracts and consolidate 16 shared rule families without
moving the bulk into another catalog.
2026-10-13 13:57:02 +01:00
pulse-triage[bot] 1ed2b3a0d2 Observe settled trend and focus state in the composed browser journey
Paired native-tab controls with and without the clock show the expected outline on unchanged source. Resolve the actual loaded trend and focused pseudo-state before sampling CSS; retain the same focus assertions and both adverse passes, without inventing a product colour or clock fault.

Contract-Neutral: Browser observation protocol only; production, acceptance criteria, regressions and graph remain unchanged.
Change-source: pulse-maintainer
2026-10-13 13:53:29 +01:00
pulse-triage[bot] 6e541d04cc Record consuming desktop and phone agent-help verification
The new source-bound static fixture exercises the actual Docs fetch, renderer, keyboard and touch links with eight natively inspected captures. All producer, consumer and served bytes match; this completes help qualification, not native QNAP recovery or release availability.

Contract-Neutral: Browser receipt only; production source and subsystem contracts are unchanged.
Change-source: pulse-maintainer
2026-10-13 13:50:29 +01:00
pulse-triage[bot] 28574fa4b5 Observe composed guidance focus after the rendered frame
Retain the initial zero-width outline observed immediately after native tab input. Wait for fonts and two rendered frames before applying the unchanged focus criterion, as the established consuming guidance harness does.

Contract-Neutral: Browser observation timing only; no production, criterion, regression or dependency change.
Change-source: pulse-maintainer
2026-10-13 13:45:09 +01:00
rcourtman 420f34a41d Consolidate shared contracts and retire obsolete obligations
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.
2026-10-13 13:44:50 +01:00
pulse-triage[bot] 3b9b151578 Bind composed trends to the consuming History API fixture
The second pass reached real guest guidance and retained disks but supplied a reply to the wrong history endpoint. Match the actual metrics-store request, use native tab traversal for the guidance, and consume the node help link through its shipped Docs renderer.

Contract-Neutral: Browser fixture response and interaction correction only; production, source regressions and dependency graph remain unchanged.
Change-source: pulse-maintainer
2026-10-13 13:40:10 +01:00
rcourtman a7bbd0ee2a Consolidate installer and settings contract ownership (#2903)
The same removal and settings-preservation rules were maintained in
several subsystem contracts. Keep removal safety in agent lifecycle and
settings compatibility in the API contract, with scoped links from
consumers.

Preserves legacy Assistant preferences, paid entitlement checks,
installer recovery rules and native qualification limits. Runtime code
and ownership/proof routing are unchanged.

Validation: contract, registry and status audits, normal commit-hook
governance tests, four installer removal controls, Assistant mode-echo
and Patrol default handler tests, and settings initialization tests.
2026-10-13 13:37:58 +01:00
pulse-triage[bot] 25f76ecc2f Drive the composed drawer through its actual row keyboard control
The first consuming pass timed out before opening the desktop drawer: the fixture driver focused a name span instead of the row action. Use the shipped disclosure control and retain that failed pass; no runtime or assertion is weakened.

Contract-Neutral: Browser fixture input correction only; production and regression bytes are unchanged.
Change-source: pulse-maintainer
2026-10-13 13:35:33 +01:00
pulse-triage[bot] 012b5cbdae Bind the Docs preview to the installed browser target
The original prepared fixture failed esbuild lowering before producing an artifact. Keep that complete adverse receipt. Use the same current-engine target as the existing consuming previews; this does not change the production target or claim legacy-browser qualification.

Contract-Neutral: Correct test-only preview compilation for the installed current browser; production source, tool limits and runtime contracts are unchanged.
Change-source: pulse-maintainer
2026-10-13 13:30:27 +01:00
pulse-triage[bot] 32a4fc10c1 Qualify drawer composition through reading and access consumers
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
2026-10-13 13:29:26 +01:00
pulse-triage[bot] 1205f276e2 Prepare agent-command Docs proof outside the browser compiler tree
Keep the original output-bound attempt stopped. Compile the existing Docs fetch, renderer, router and shipped help in the offline source VM, then exercise exact static bytes at desktop and phone with a small bounded browser process and native captures. No runtime or tool-boundary change.

Contract-Neutral: Test-only consuming Docs fixture and source-bound preview preparation; production code, routes, installer/runtime contracts and enforced browser limits are unchanged.
Change-source: pulse-maintainer
2026-10-13 13:26:14 +01:00
rcourtman 2dfbbe4f9f Consolidate installer and settings contract ownership
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.
2026-10-13 13:25:37 +01:00
pulse-triage[bot] d841465640 Compose agent-command help for consuming browser proof
Preserve the original guidance candidate and existing source history; this isolated composition is not canonical integration or publication.

Change-source: pulse-maintainer
2026-10-13 13:24:12 +01:00
pulse-triage[bot] a11f031fd1 Compose alert-first drawers without losing reading and access guidance
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
2026-10-13 13:23:27 +01:00
pulse-triage[bot] d636bfdaea Set exact initial modes in NAS executable controls
The chosen source proof runs with umask 077. Explicitly chmod the inert pre-update binaries so failure controls can require exact preservation of a 0755 executable rather than assuming WriteFile overrides the caller's mask. This changes only fixture setup; production permission, trust and recovery assertions are retained.

Change-source: pulse-maintainer
2026-10-13 13:22:11 +01:00
pulse-triage[bot] 45669119cc Compose reviewed notice accessibility with the assigned Web base
Change-source: pulse-maintainer
2026-10-13 13:21:38 +01:00
pulse-triage[bot] a38ef3734d Keep NAS agent update copies executable
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
2026-10-13 13:18:15 +01:00
rcourtman 2cc29dcbd0 Honour recurring and descendant maintenance in Patrol findings (#2902)
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.
2026-10-13 13:16:52 +01:00
pulse-triage[bot] 340a832faa Integrate reviewed cached DNS address fallback
Change-source: pulse-maintainer
2026-10-13 13:07:45 +01:00
rcourtman 49b7abc860 Honour recurring and descendant maintenance in Patrol findings
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.
2026-10-13 12:58:17 +01:00
pulse-triage[bot] ee700b62eb Integrate reviewed early NAS removal-safety preflight
Retain the exact Delivery commit and its complete source-el4dto5p proof. The CI-only partition preserves all checks and deadlines; native recovery and upstream drawer reconciliation remain separate owning-lane work.

Change-source: pulse-maintainer
2026-10-13 12:13:00 +01:00
pulse-triage[bot] ed2107bee0 Explain stopped agent commands without credential or state churn
Distinguish private prompt preparation, preflight and read-only profile inspection from installation and destructive removal. Keep existing unavailable-agent and automatic-update investigations separate, and route FAQ and troubleshooting readers to the existing private-file and recovery guides.

Contract-Neutral: Help copy and rendered-document regression checks only; installer, credential, lifecycle and monitoring contracts are unchanged.
Change-source: pulse-maintainer
2026-10-13 12:07:59 +01:00
pulse-triage[bot] 4295476940 Try reachable alternatives in the cached infrastructure DNS answer
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
2026-10-13 12:03:15 +01:00
pulse-triage[bot] e241788c38 Integrate reviewed cancellable Proxmox certificate probes
Change-source: pulse-maintainer
2026-10-13 11:50:07 +01:00
pulse-triage[bot] 75afc9f1a9 Record shared notice keyboard and phone browser proof
Bind actual canonical guest, both drawer warnings, shipped Docs and RBAC recovery consumers to the containing source. Parent controls and final passes cover both themes and desktop/phone input. All 24 captures were natively inspected; native recovery and full source suites remain separate.

Contract-Neutral: Own-parent browser receipt only; no runtime or contract change.
Change-source: pulse-maintainer
2026-10-13 11:49:58 +01:00
pulse-triage[bot] 10bca28cc3 Keep the notice fixture on the declared History target
The canonical drawer requires an explicit metricsTarget to offer History; the connected fixture now supplies that real producer field rather than assuming the workload drawer fallback. This was found by source inspection before browser execution. Production and regression bytes remain unchanged.

Contract-Neutral: Synthetic browser fixture metadata only; no product or wire-contract change.
Change-source: pulse-maintainer
2026-10-13 11:35:16 +01:00
rcourtman 5996dc1a25 Lead the guest and node drawers with alerts and 24h trends (#2900)
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/`.
2026-10-13 11:29:27 +01:00
pulse-triage[bot] 074aeec6e9 Merge published Manage guidance into reviewed maintenance
Preserve reviewed dd2dbeab8f and exact published aa0c25de4c additively after upstream advanced at the publication boundary.

Change-source: pulse-maintainer
2026-10-13 11:28:36 +01:00
pulse-triage[bot] e583557b61 Make safety-notice actions touch-sized and keyboard-visible
Give existing shared notice links and callback actions a 44px phone target and a tone-matched, explicit keyboard outline. Keep desktop actions compact and underline them without requiring hover. Preserve warning copy, destinations, callbacks and native button/link semantics. Supply the existing drawer context in the connected fixture; its parent variant uses only the exact original primitive input.

Contract-Neutral: Shared notice action styling and connected fixture correction only; no API, navigation, safety-message, guest-operation or callback contract delta.
Change-source: pulse-maintainer
2026-10-13 11:22:36 +01:00
rcourtman aa0c25de4c Say what each Manage control does in plain words (#2901)
The Manage tab's operator overrides explained themselves in
implementation terms ("one persisted resource policy", "the action
broker logs every refused dispatch as a Failed audit record", "Pulse's
canonical inventory hierarchy"). This rewrites them to say what each
control does, keeping each consequence beside its control. Each sentence
was checked against the runtime:

| Control | Now reads | Why |
|---|---|---|
| Section | How Pulse alerts on, prioritizes and acts on this resource.
| — |
| Maintenance window | Silence alerts and dismiss new Patrol findings
during planned work, such as upgrades or reboots. | An active window
suppresses alert activation and auto-dismisses new findings (kept in
history); the old text named findings only. |
| Applies to (descendants) | With descendants, alerts on everything
under this resource are silenced too, including resources added later. |
Alerts follow live ancestry; Patrol reads only the exact resource, so
the help claims alerts only. |
| Never auto-remediate | Block every automated fix on this resource,
including approved ones. Blocked runs are logged as failed actions. |
Approved runs recheck the lock; refused runs become Failed records.
Assistant planning refusals create no record, so the copy says "runs". |
| Lock confirmation | Pulse will block every automated fix on this
resource, including ones already approved in Patrol or the Assistant,
until this is turned off. | — |

"Never auto-remediate" keeps its name: the help pages and the
Assistant's refusal message refer to it. The Manage section drops from
about 172 words to 119.

A source-pin test keeps the implementation vocabulary out of
user-visible copy and pins the consequence sentences. It fails against
the old copy and passes on the new. Contract note in
`unified-resources`. Browser receipt covers 1280 and 390px.

Found while checking the copy and filed separately: Patrol's
operator-state projection dereferences one-shot maintenance dates that
are nil during an active recurring window.
2026-10-13 11:20:34 +01:00
pulse-triage[bot] 9bffac048b Cover safety-notice actions through their consuming surfaces
Add a connected canonical guest/drawer/Docs and read-only RBAC recovery fixture, with explicit parent accessibility controls. The new primitive regression exposes the absent phone sizing, persistent action affordance and deterministic keyboard focus. The following repair completes the candidate; no native recovery is simulated.

Contract-Neutral: Test and browser fixture coverage only; production interfaces, safety advice and actions are unchanged.
Change-source: pulse-maintainer
2026-10-13 11:20:09 +01:00
pulse-triage[bot] 768065b0db Stop cancelled Proxmox first-use certificate probes
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
2026-10-13 11:15:48 +01:00
pulse-triage[bot] 254d7762a2 Observe NAS removal controls before native frontend preparation
Move the existing generated watchdog and collector contract to an early, fail-closed native CI phase. Discover the complete inventory in both phases, execute every check exactly once, and preserve the remaining group assignments, native runtime tools and safety deadlines. Exercise phase admission, omission, duplicate and failure controls.

Contract-Neutral: Native CI phase ordering and inventory partition only; production installers, runtime behaviour, required checks and safety deadlines are unchanged.
Change-source: pulse-maintainer
2026-10-13 11:14:52 +01:00
pulse-triage[bot] c093006f1d Merge commit '68662e8eec6e64226efb76d1b6e412af0fea1177' into maintainer-async/20261013T100016Z-delivery-trust/pulse
Change-source: pulse-maintainer
2026-10-13 11:08:45 +01:00
pulse-triage[bot] dd2dbeab8f Integrate reviewed preserved-state v6 migration help
Change-source: pulse-maintainer
2026-10-13 11:03:12 +01:00
pulse-triage[bot] 51c226769b Integrate reviewed guest filesystem guidance accessibility
Change-source: pulse-maintainer
2026-10-13 11:03:09 +01:00
pulse-triage[bot] 3cf68322f6 Reconcile batch-start upstream before reviewed accessibility and migration help
Change-source: pulse-maintainer
2026-10-13 11:03:07 +01:00
rcourtman a59f6eb97a Open drawer Details in the hybrid memory browser spec
The guest drawer now keeps its Memory section inside a Details
disclosure that is closed by default, so the spec scrolled to hidden
rows and its in-viewport check failed. It opens Details once, as a
reader would, before judging the recovered rows.
2026-10-13 10:58:00 +01:00
rcourtman 669fcc1003 Say what each Manage control does in plain words
The Manage tab's operator overrides explained themselves in
implementation terms: "one persisted resource policy", "the action broker
logs every refused dispatch as a Failed audit record", "Pulse's canonical
inventory hierarchy". A homelab user reads those to learn what a control
will do, and the jargon hid the answer.

Each control keeps its consequence beside it, in shorter words, checked
against the runtime. The maintenance window now says it silences alerts
and dismisses new Patrol findings; the old text named findings only,
though an active window also suppresses alert activation. The descendant
scope help claims only alerts for descendants, because Patrol reads the
exact resource's own state. Never auto-remediate keeps its name, because
the help pages and the Assistant's refusal message refer to it, and now
reads "Block every automated fix on this resource, including approved
ones. Blocked runs are logged as failed actions."
2026-10-13 10:55:14 +01:00
rcourtman 68662e8eec Stop timing the route normaliser rows that flip with layout (#2899)
The advisory Benchmarks check failed #2884 on NormalizeRoute/with_uuid
alone, +12.25% (p=0.000), though that PR changed only AI handler code.
It was not the only one. Since the bounded route scanner landed on
9 October (01788459f1), normalizeRoute takes 30-180ns a path on CI
runners. In 72
paired CI comparisons that measured internal/api from then until 13
October, the BenchmarkNormalizeRoute rows and their parallel variant
failed the gate 17 times. None of those PRs touched route code, and 6
of the 17 failures did not involve with_uuid: deep_path_truncated,
with_query_params, metrics_history, with_numeric_id and Parallel each
crossed 10% too. with_uuid moved past 10% in 21 of the 72 comparisons,
in both directions.

This is the same layout effect that retired the "/" fast path (#2255)
and NormalizeSegment (#2258). Go aligns functions to 32 bytes, so code
added earlier in the package moves normalizeRoute between the halves of
a 64-byte block. That changes its loops by a cycle per iteration. Every
path shares those loops, so retiring with_uuid alone would leave the
other rows failing. Summed over all six paths, a mixed-path row would
still have moved up to 10%.

BenchmarkNormalizeRoute and BenchmarkNormalizeRoute_Parallel are
removed. Their allocation columns never varied, and they are now pinned
by TestNormalizeRoute_LabelAllocationProfile. For each former path it
requires exactly one allocation, of the same size as a fresh copy of the
label. It runs in the existing isolated child process and takes the
lowest of three windows, so one stray runtime allocation cannot fail it.
BenchmarkFullMiddlewarePath still times the normaliser inside the
request path, with a CI maximum of +8.4% over those 72 runs, and
BenchmarkNormalizeRoute_DiscardedSuffix still times a long discarded
suffix. Gross classification slowdowns are left to those rows: a
doubled UUID scan has no deterministic signal, and the retired row
could not separate one from layout.

Proofs, on pulse-dev with the CI runner narrowed to ./internal/api/ at
30 samples. The probe is an unrelated init-time function in a file
sorted before http_metrics.go. It moves normalizeRoute from 32 to 0 mod
64 in the test binary without changing its size:

- old tree vs old tree plus probe: with_uuid -14.70% (p=0.001). Read the
  other way, as a PR that removes the probe, the gate exits 1 on
  NormalizeRoute/with_uuid alone, +17.23% (p=0.001). That is #2884's
  shape.
- new tree vs new tree plus probe: gate exits 0 in both directions. On
  a first run under load 9-15, three millisecond-scale rows that run no
  route code flagged at p=0.025-0.046 with spreads of 15-38%. The
  repeat came back clean in both directions.
- mutation controls on the final test: sizing the label buffer at twice
  the label fails only the new test. The existing at-most-one-allocation
  test passes it. Joining the label through an intermediate fails both.
- the route tests pass 20 times plain and 10 times under -race.
2026-10-13 10:47:37 +01:00
rcourtman 3d334dbff3 Lead the guest and node drawers with alerts and 24h trends
The Proxmox guest and node drawer Overview had grown into a grid of
equal-weight inventory cards (coverage, platform, hardware, telemetry,
thermals, observation paths), 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 active alerts, or one "No active alerts" line,
then 24h trend cards for the metrics the row shows: CPU, memory and disk
for guests; CPU, memory, CPU temperature and root disk for nodes. An
active alert on a card's metric colours it and draws the alert's own
trigger. Any warning- or danger-toned detail row moves into a "Worth
checking" section in front, so demoting inventory 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 fresh and healthy
stay visible; a facts strip carries OS, address, a healthy last completed
backup and tags. Everything else sits in a closed Details disclosure that
keeps its rows mounted for find-in-page.

The trend cards and the History tab share one query and cache key, and
each polls only while its tab shows: the node drawer's History no longer
stays mounted and polling while hidden. Node cards read only the node's
own alerts, which the Proxmox node table now passes by identity (the
drawer's list also carries its guests' alerts by node name), and withhold live values
when the node is offline or its Proxmox readings are stale. Ranges use
bucket extremes, so an averaged-away spike still shows.

This deliberately amends the frontend-primitives rule that curated drawer
facts must not need another tap, for these two drawers only, as a named
bet in the demand ledger (pulse-pro#419) to grade at +30 days.
2026-10-13 10:39:49 +01:00
rcourtman e9083fdf80 Scope Patrol's expected-offline silence to availability (#2898)
Expected offline is availability-specific everywhere else: the canonical
ResourceOperatorState doc says it "suppresses availability noise", the
alert runtime suppresses only offline and availability signals, and both
monitoring-policy controls tell the operator it hides availability noise
only, with Mute all as the way to stop Alerts and Patrol. Patrol was the
outlier. Its projection returned a suppression cause for
expected_offline
(and the legacy IntentionallyOffline flag) regardless of the finding, so
a disk, memory, backup or security finding on an expected-offline
resource was auto-acknowledged exactly as if the resource were muted.

The suppression decision is now per finding. Retired and muted still
silence every finding; expected_offline and the legacy flag (when no
MonitoringMode is projected, as in the alert runtime) silence only
findings in the shared down condition class that alert mirroring already
uses. The wake path judges the re-detected finding with the same helper,
so findings auto-acknowledged under the old behaviour wake on their next
detection.

That classifier matched "offline" in any reliability title, which would
have read a SMART "offline uncorrectable sectors" report as the resource
being down and hidden a failing disk. SMART findings now fall outside
the
down class, which also stops them mirroring an offline alert.

A new test pins the split (availability silenced; disk, memory and SMART
findings visible) with muted as the negative control, plus a muted to
expected-offline transition that wakes only non-availability findings.
Each test fails when the old behaviour, the wake-path scoping or the
SMART guard is reverted.
2026-10-13 10:27:24 +01:00
rcourtman 3d322ff3a8 Stop timing the route normaliser rows that flip with layout
The advisory Benchmarks check failed #2884 on NormalizeRoute/with_uuid
alone, +12.25% (p=0.000), though that PR changed only AI handler code.
It was not the only one. Since the bounded route scanner landed on
9 October (01788459f1), normalizeRoute takes 30-180ns a path on CI runners. In 72
paired CI comparisons that measured internal/api from then until 13
October, the BenchmarkNormalizeRoute rows and their parallel variant
failed the gate 17 times. None of those PRs touched route code, and 6
of the 17 failures did not involve with_uuid: deep_path_truncated,
with_query_params, metrics_history, with_numeric_id and Parallel each
crossed 10% too. with_uuid moved past 10% in 21 of the 72 comparisons,
in both directions.

This is the same layout effect that retired the "/" fast path (#2255)
and NormalizeSegment (#2258). Go aligns functions to 32 bytes, so code
added earlier in the package moves normalizeRoute between the halves of
a 64-byte block. That changes its loops by a cycle per iteration. Every
path shares those loops, so retiring with_uuid alone would leave the
other rows failing. Summed over all six paths, a mixed-path row would
still have moved up to 10%.

BenchmarkNormalizeRoute and BenchmarkNormalizeRoute_Parallel are
removed. Their allocation columns never varied, and they are now pinned
by TestNormalizeRoute_LabelAllocationProfile. For each former path it
requires exactly one allocation, of the same size as a fresh copy of the
label. It runs in the existing isolated child process and takes the
lowest of three windows, so one stray runtime allocation cannot fail it.
BenchmarkFullMiddlewarePath still times the normaliser inside the
request path, with a CI maximum of +8.4% over those 72 runs, and
BenchmarkNormalizeRoute_DiscardedSuffix still times a long discarded
suffix. Gross classification slowdowns are left to those rows: a
doubled UUID scan has no deterministic signal, and the retired row
could not separate one from layout.

Proofs, on pulse-dev with the CI runner narrowed to ./internal/api/ at
30 samples. The probe is an unrelated init-time function in a file
sorted before http_metrics.go. It moves normalizeRoute from 32 to 0 mod
64 in the test binary without changing its size:

- old tree vs old tree plus probe: with_uuid -14.70% (p=0.001). Read the
  other way, as a PR that removes the probe, the gate exits 1 on
  NormalizeRoute/with_uuid alone, +17.23% (p=0.001). That is #2884's
  shape.
- new tree vs new tree plus probe: gate exits 0 in both directions. On
  a first run under load 9-15, three millisecond-scale rows that run no
  route code flagged at p=0.025-0.046 with spreads of 15-38%. The
  repeat came back clean in both directions.
- mutation controls on the final test: sizing the label buffer at twice
  the label fails only the new test. The existing at-most-one-allocation
  test passes it. Joining the label through an intermediate fails both.
- the route tests pass 20 times plain and 10 times under -race.
2026-10-13 10:25:33 +01:00
pulse-triage[bot] 1e6c30600a Integrate reviewed guest-memory expiry fixture repair
Preserve the exact Core candidate and its source proof. Age both original evidence owners; keep runtime retention, guest-read admission and History policy unchanged.

Change-source: pulse-maintainer
2026-10-13 10:18:22 +01:00