Commit Graph

9728 Commits

Author SHA1 Message Date
rcourtman 3d4c43162a feat(alerts): add recurring scoped maintenance 2026-08-27 18:20:03 +01:00
rcourtman ce555ee09d Converge resource drawer detail layout
Contract-Neutral: Implements the existing responsive DetailSectionTable contract for the remaining unified-resource drawer; no contract surface changes.
2026-08-27 18:06:39 +01:00
pulse-triage[bot] d48e70da15 docs(governance): record launchd mode invariant
Change-source: pulse-maintainer
2026-08-27 18:00:28 +01:00
pulse-triage[bot] ec25ab4c13 fix(dev): preserve executable launchd wrapper mode 2026-08-27 17:54:10 +01:00
pulse-triage[bot] 811c299cae test(e2e): restore offline Proxmox qualification
Recognize the overview request by its defining workload resource types so additive query families do not route the canonical offline-node fixture to an empty response.
2026-08-27 17:32:39 +01:00
rcourtman ff507a6e44 feat(alerts): add per-alert snooze 2026-08-27 17:20:32 +01:00
pulse-triage[bot] 553592d2bd fix(governance): align pre-push guard with CI 2026-08-27 17:07:58 +01:00
pulse-triage[bot] 5ead2f8748 security(deps): update OpenTelemetry to 1.44.0 2026-08-27 16:55:46 +01:00
pulse-triage[bot] 735acbb05a fix(dockeragent): bound image storage computation
Keep live image identity fresh without recomputing shared layer sizes on every report. Reuse the throttled storage snapshot and qualify the reported Synology inventory shape.

Change-source: pulse-maintainer
2026-08-27 16:33:14 +01:00
rcourtman f4e1e47e74 feat(alerts): add external dead-man monitoring 2026-08-27 16:27:46 +01:00
pulse-triage[bot] 30b4fbd95e test(notifications): isolate terminal recovery paths 2026-08-27 16:08:53 +01:00
pulse-triage[bot] 947a26b72f fix(alerts): stop mutating resolved snapshots
Contract-Neutral: resolved-alert alias lookup no longer mutates shared alert snapshots; canonical identity and public alert behavior are unchanged
2026-08-27 15:56:23 +01:00
pulse-triage[bot] d4deb26a27 test(proxmox): scope backups table guard 2026-08-27 15:34:40 +01:00
rcourtman f6773f262a fix(alerts): make active restart state durable
Contract-Neutral: monitor construction only moves alerts-owned durable-store initialization before alert workers; monitoring and host-agent behavior are unchanged
2026-08-27 15:21:18 +01:00
pulse-triage[bot] 6bbf814548 fix(proxmox): govern overview PBS health 2026-08-27 15:15:35 +01:00
pulse-triage[bot] 699143b7b8 feat(proxmox): surface PBS hosts on overview 2026-08-27 14:59:41 +01:00
rcourtman b6babd0b4b fix(alerts): make incident timelines lifecycle-driven
Contract-Neutral: monitor startup wiring changes only alert lifecycle projection behavior; agent-lifecycle deletion and reenrollment contracts are unchanged
2026-08-27 14:45:36 +01:00
rcourtman 1e75423116 fix(release): enforce plain changelog punctuation 2026-08-27 13:56:35 +01:00
rcourtman 9e17122713 fix(release): keep changelog synthesis model-led 2026-08-27 13:39:16 +01:00
pulse-triage[bot] 9622f89fe6 feat(alerts): configure SMART disk thresholds
Expose host disk SMART health, counter, endurance, spare, and CRC-growth rules in alert settings while preserving existing defaults and supporting explicit disable values.

Change-source: pulse-maintainer
2026-08-27 13:20:36 +01:00
pulse-triage[bot] 3d91709eba docs(proxmox): govern PBS host history correlation
Record the unique PBS-to-Agent presentation boundary and the desktop and phone browser proof for Agent-backed host History.

Change-source: pulse-maintainer
2026-08-27 12:19:01 +01:00
pulse-triage[bot] 118c90d1f0 fix(proxmox): restore PBS host history
Change-source: pulse-maintainer
2026-08-27 12:08:12 +01:00
rcourtman 73499d7161 feat(alerts): migrate persisted alert identities 2026-08-27 12:04:49 +01:00
rcourtman ff27c3881f fix(release): make changelog ranges channel-aware 2026-08-27 11:56:06 +01:00
rcourtman 248b242034 test(alerts): automate operator qualification 2026-08-27 11:06:26 +01:00
pulse-triage[bot] 4f91232cc6 fix(proxmox): stabilize storage inventory refreshes
Sort backup-server and datastore rows deterministically so provider refresh order cannot reset expanded detail state. Exclude optical devices from PVE, legacy agent, and canonical physical-disk projections.

Fixes #1785
Fixes #1786

Contract-Neutral: Corrects refresh ordering and non-disk filtering without changing public APIs or subsystem contracts.
Change-source: pulse-maintainer
2026-08-27 11:05:14 +01:00
rcourtman 96add5d57a fix(alerts): harden event history recovery 2026-08-27 10:05:37 +01:00
rcourtman d6ff4151d1 test(alerts): widen history projection parity to every rendered field 2026-08-27 09:34:27 +01:00
pulse-triage[bot] fc55a1e3f2 Govern alert history authority changes
Record event-log history ownership, migration and tombstone semantics in the canonical alerts contract. Register the schema, migration and projection proofs so future runtime changes satisfy the explicit alerts verification policy.

Change-source: pulse-maintainer
2026-08-27 09:26:52 +01:00
rcourtman 276a9baa2b chore(release-control): release alert-lifecycle-contract-coverage claim 2026-08-27 09:24:48 +01:00
rcourtman 0d381ee24f docs(alerts): record the contract gate, history authority, and the registered identity migration 2026-08-27 09:24:35 +01:00
rcourtman fbbdb929dc feat(alerts): record fired events for reconciler and system alerts
The unified-incidents reconciler and system alerts dispatched without a
fired event, so the event log's lifecycle timeline — now the history
authority — began at their resolution. Both families record TypeFired
with a snapshot at activation, completing the log for every alert
family.
2026-08-27 09:23:22 +01:00
rcourtman 2dc2b72759 feat(alerts): make the event log the alert history authority
The retirement scoped by docs/ALERT_ENGINE_EVOLUTION.md: with an event
log enabled, GetAlertHistory and GetAlertHistorySince serve the
projection from the log's lifecycle snapshots; the JSON snapshot file
stops being written and is renamed to *.imported after a one-time
migration. The #1693 class — fire/resolve churn rewriting the JSON file
and deleting history — cannot recur against an append-only store.

Migration: on the first EnableEventLog with a JSON history file
present, every entry is written synchronously into the log as a
history_imported event (ImportEvents bypasses the droppable append
buffer — losing an entry to a full buffer would silently lose user
data), then the files retire to *.imported as backups. The file's
presence is the migration marker, so the import is idempotent and a
failed import leaves the JSON authoritative for the next attempt.
History retention (30 days) sits inside log retention (90 days), so no
entry can be pruned out from under the migration.

Clearing history keeps the log append-only: the clear is a
history_cleared tombstone and the projection ignores lifecycle events
that precede it. One deliberate difference from the JSON behavior:
still-active alerts reappear in history immediately after a clear —
they are current state, not cleared history.

The in-memory history manager remains as the fallback read model for
managers without an event log, and the parity suite now reads it
directly so it keeps characterizing the projection instead of comparing
the projection with itself.
2026-08-27 09:22:05 +01:00
rcourtman 871f2348bd feat(alerts): project alert history from the event log, in parity
The step before the event log can retire the JSON snapshot history file
(docs/ALERT_ENGINE_EVOLUTION.md): lifecycle events — fired, refired,
resolved, acknowledged, unacknowledged, escalated — now carry a full
alert snapshot in the log (new nullable snapshot column, upgraded in
place on pre-snapshot databases), and AlertHistoryFromEvents projects
the history list from those snapshots alone: one row per occurrence,
refires folded in by their restored start time, live active alerts
overlaid so open rows show current state.

The JSON-backed history manager stays authoritative and characterizes
the projection: history_projection_parity_test.go holds the two equal
across active, resolved, acknowledged, multi-resource, and
second-occurrence runs. Cutover follows once an import path carries
existing JSON history into the log.

Parity surfaced one real defect, fixed at the root: the JSON history
never propagated acknowledgement onto its rows, so the History view
showed an acknowledged alert as unacknowledged for its entire active
life. The live alert is authoritative; the row now follows it.
2026-08-27 09:15:38 +01:00
rcourtman 3049da030e test(alerts): pin the lifecycle contracts as a release gate
The lifecycle contract suite from docs/ALERT_ENGINE_EVOLUTION.md — the
audit's end-to-end assertions over externally observable alert behavior,
each one a recurring regression class from the issue record:

- A config save that changes nothing emits nothing (#1682: config saves
  dispatched resolved notifications for still-active alerts), and one
  that genuinely resolves an alert resolves it exactly once, with no
  fire event and no residue in the reducer core.
- An acknowledged alert does not escalate, resumes escalating when
  unacknowledged, and its recovery notification is suppressed.
- N grouped alerts render N on every delivery surface (#1683: built-in
  service payloads silently dropped N−1 of N): grouped email HTML and
  text, apprise, the generic webhook payload, a custom template, and
  every built-in service template — discord, slack, telegram, teams,
  teams-adaptive, pagerduty, pushover, gotify, ntfy, mattermost —
  driven through the real grouped send path against a capture server.
- Cancelling an alert still inside the grouping window reports the
  firing as never delivered, the answer the monitor uses to hold the
  recovery notification (#1553: resolves sent for suppressed firings);
  a delivered firing is never misreported as undelivered.

The engine contracts drive real metric evaluations through the public
read model (GetActiveAlerts / AcknowledgeAlert by exported ID) so they
gate the path users actually exercise.
2026-08-27 09:09:56 +01:00
pulse-triage[bot] 0fd9171ff7 Prevent host identity forks during install handoff
Allow one retiring-agent health window after a trusted replacement install token is minted, while preserving clone-safe forks for ambiguous, conflicting, or longer-lived identities. Retire superseded token bindings and document the remaining migration gap for identities already forked.

Change-source: pulse-maintainer
2026-08-27 08:47:42 +01:00
pulse-triage[bot] 8fde82b8a2 Keep LXC filesystem paths native-proof
Join Proxmox config paths with Linux semantics across native test platforms, add the regression proof, and update the canonical agent lifecycle contract for the new namespace-statfs collector.

Change-source: pulse-maintainer
v6.4.0-rc.6 helm-chart-6.4.0-rc.6
2026-08-27 06:51:36 +01:00
pulse-triage[bot] c045c0451d Align rc.6 packet with LXC filesystem fix
Include the host-agent filesystem collection correction that landed after the initial rc.6 preparation, and keep the release metadata proof aligned with the new main head.

Change-source: pulse-maintainer
2026-08-27 06:46:57 +01:00
pulse-triage[bot] 7348c17905 Stabilize mock snapshot memoization proof
Pause the automatic mock metric ticker while the test asserts same-version snapshot identity, then restore it during cleanup. This prevents the full race suite from invalidating the fixture between the two reads it is comparing.

Change-source: pulse-maintainer
2026-08-27 06:44:56 +01:00
rcourtman 8318c74687 fix(hostagent): stop pct df from starving LXC filesystem collection
pct df takes the container config lock and costs over a second per
guest, and every per-container query shared one 10-second budget with
pct list, so hosts with more than a handful of running containers only
ever reported filesystem usage for the first few (signal: killed on
the rest).

Resolve per-mount usage with statfs through /proc/<pid>/root instead:
read the config-declared mounts from /etc/pve/lxc, resolve the init
pid via lxc-info, and drop config mounts whose device identity matches
their parent directory rather than inventing the parent's numbers.
pct df remains as a per-container fallback for least-privilege
installs that cannot traverse /proc/<pid>/root, each container now
carries its own deadline inside a bounded collection window, and
exhausting that window logs how many containers were skipped instead
of failing silently at debug level.

Refs #1477
2026-08-27 06:22:10 +01:00
pulse-triage[bot] 1f28d950c3 Prepare v6.4.0-rc.6 release
Package the standalone PBS detail restoration, SMART CRC growth alerts, consolidated alert policy, bounded event queries, and Go 1.26.7 toolchain for the next prerelease.

Change-source: pulse-maintainer
2026-08-27 05:47:17 +01:00
pulse-triage[bot] aa50087c08 security(build): advance release toolchain to Go 1.26.7
Use the current supported Go 1.26 security patch across source, release, dev, and production container build surfaces. Keep the immutable official builder pin and governance proofs aligned with the exact toolchain.

Change-source: pulse-maintainer
2026-08-27 05:04:03 +01:00
pulse-triage[bot] 5859f49817 security(build): upgrade release toolchain to Go 1.26.6
Advance local, release, and container build surfaces together so reachable standard-library advisories cannot re-enter shipped binaries. Pin the official amd64 builder manifest and govern the updated floor with installability and dev-runtime proofs.

Change-source: pulse-maintainer
2026-08-27 04:24:10 +01:00
pulse-triage[bot] 1dc5ee4942 docs(alerts): govern SMART counter growth
Change-source: pulse-maintainer
2026-08-27 03:30:44 +01:00
pulse-triage[bot] 02cfd4f7b3 feat(alerts): detect SMART CRC counter growth
Change-source: pulse-maintainer
2026-08-27 03:26:21 +01:00
pulse-triage[bot] e89bca00a0 security(alerts): decouple event query allocation
Change-source: pulse-maintainer
2026-08-27 02:13:42 +01:00
pulse-triage[bot] 1b4b8ae1dc Repair standalone PBS detail governance proof
Change-source: pulse-maintainer
2026-08-27 01:42:38 +01:00
pulse-triage[bot] 325ff793c8 fix(proxmox): restore standalone PBS host details
Change-source: pulse-maintainer
2026-08-27 01:30:03 +01:00
rcourtman 479cce1d73 docs(alerts): record Phase 3 engine completion and the demand-gated UI decision 2026-08-27 01:13:04 +01:00
rcourtman 8827defb63 feat(alerts): resolve alert policy through one declarative fold
Phase 3 of docs/ALERT_ENGINE_EVOLUTION.md: the effective alert policy for
a resource — type default thresholds, the type's DisableAll switches,
custom rules, the per-resource override — is now answered by one ordered
fold (effectiveAlertPolicyNoLock in alert_policy.go), translated from the
persisted AlertConfig. The config keeps its shape; the engine stops
reading it piecemeal.

Before this, every check path read its own DisableAll* boolean and picked
its own override lookup, and the scattered reads drifted (#1738 was an
override lookup that existed on some paths and not others;
connection.go hand-rolled its own type-to-switch mapping). Now:

- resolveResourceThresholds and getGuestThresholds delegate to the fold.
- All 40+ DisableAll* reads across the check paths, the config-change
  reconciliation, and the connection detector go through
  alertPolicyTypeSwitchesNoLock — the single place those booleans are
  read on behalf of evaluation.

Characterization first: alert_policy_test.go pins the fold against the
legacy resolution paths (per-type defaults, overrides, storage aliases,
guest custom rules by priority, every type's switch pair) before any
call site moved.
2026-08-27 01:10:26 +01:00