diff --git a/docs/release-control/v6/internal/subsystems/alerts.md b/docs/release-control/v6/internal/subsystems/alerts.md
index 4ceccdf18..63bab6578 100644
--- a/docs/release-control/v6/internal/subsystems/alerts.md
+++ b/docs/release-control/v6/internal/subsystems/alerts.md
@@ -118,6 +118,22 @@ provider-backed disk surface rather than creating a duplicate host alert.
`internal/alerts/alerts_test.go` pin the baseline, growth, reset, recovery, and
retention boundaries.
+Host SMART alert policy is configured through the resolved agent threshold
+chain, not embedded inside the disk evaluator. Missing SMART rule fields seed
+the backward-compatible policy: failed health is enabled; reallocated,
+pending, uncorrectable, media-error, and CRC-growth counters trigger at one;
+remaining-life warning/critical thresholds are 10/5 percent; and NVMe spare
+warning/critical thresholds are 20/10 percent. An explicit zero disables that
+individual rule and must survive normalization, cloning, persistence, and
+per-machine override resolution. Counter rules trigger when current evidence
+reaches the configured value, while the CRC rule applies the configured
+minimum increase to two successive reports. Endurance and spare values remain
+evidence-aware, and invalid percentage inputs clamp to 0..100 with critical no
+higher than its warning boundary. The Machines threshold surface must
+round-trip every rule without changing these defaults. Linked Proxmox host
+agents continue to defer risk alert ownership even when their resolved SMART
+policy differs.
+
Threshold sections are keyed by override identity, not by resource type. The
Virtualization Hosts section reads and writes overrides on the bare resource id,
while the Machines section resolves through the agent-derived identity
diff --git a/docs/release-control/v6/internal/subsystems/frontend-primitives.md b/docs/release-control/v6/internal/subsystems/frontend-primitives.md
index 1c1ffc4ea..83934539d 100644
--- a/docs/release-control/v6/internal/subsystems/frontend-primitives.md
+++ b/docs/release-control/v6/internal/subsystems/frontend-primitives.md
@@ -191,6 +191,18 @@ page, platform navigation, the resource drawer and the alerts threshold sections
all read it. Selecting by bare `type === 'agent'` collapses that distinction and
puts the same machine on two surfaces that do not share an identity.
+The Machines threshold tab owns one responsive SMART rules card ahead of the
+resource groups. It composes the existing threshold tab layout and native
+accessible checkbox/number controls rather than creating a second settings
+shell. Failed-health is presented as a toggle; sector, media, CRC-growth,
+remaining-life, and spare policies are integer inputs; percentage inputs are
+bounded to 0..100; and the card states that zero disables an individual numeric
+rule. Every edit uses the canonical agent-default setter and dirty-state path,
+so the shared save/discard bar owns persistence on desktop and narrow layouts.
+The single-column narrow layout must keep labels, help, values, percent suffixes,
+and the full scroll journey inside the app scroll shell without horizontal
+overflow.
+
## Canonical Files
1. `frontend-modern/src/components/shared/`
diff --git a/docs/release-control/v6/internal/subsystems/monitoring.md b/docs/release-control/v6/internal/subsystems/monitoring.md
index 0dd14d1a0..333941e7f 100644
--- a/docs/release-control/v6/internal/subsystems/monitoring.md
+++ b/docs/release-control/v6/internal/subsystems/monitoring.md
@@ -386,6 +386,16 @@ also preserve the unreported sentinel rather than collapsing an absent facet
onto the struct zero value, because `0` is a real reading meaning no endurance
remains.
+Storage health assessment accepts an explicit SMART policy from alerting for
+agent-only host disks while retaining the factory-policy entry points for all
+other consumers. The policy controls failed-health, sector, media-error,
+remaining-life, spare, and reallocated-sector classification; a zero threshold
+disables only that rule. It must not alter collection truth, device identity,
+the wearout evidence predicate, or the separate temperature classification.
+This separation keeps provider physical-disk risk deterministic while allowing
+the alert subsystem to apply resolved per-host settings without forking SMART
+parsing or risk reason codes.
+
Discovery suppression for configured connections is a fail-closed obligation,
not a best-effort optimisation. Every configured PVE, PBS and PMG host is
resolved into the discovery IP blocklist so the scanner never fingerprints a
diff --git a/frontend-modern/browser-verification.json b/frontend-modern/browser-verification.json
index feb6a786e..c271341c8 100644
--- a/frontend-modern/browser-verification.json
+++ b/frontend-modern/browser-verification.json
@@ -1,11 +1,23 @@
{
"version": 1,
- "base_sha": "118c90d1f0df2ff007a3494e25139f019a38137d",
- "verified_at": "2026-08-27T11:18:00Z",
+ "base_sha": "3d91709ebad0332858e4615d72daf8e424ab42a8",
+ "verified_at": "2026-08-27T12:19:53Z",
"result": "passed",
- "changed_paths": [],
- "content_sha256": {},
- "routes": ["/proxmox/backups"],
+ "changed_paths": [
+ "frontend-modern/src/components/Alerts/ThresholdsTableAgentsTab.tsx",
+ "frontend-modern/src/components/Alerts/ThresholdsTableSMARTDefaultsCard.tsx",
+ "frontend-modern/src/features/alerts/alertsConfigurationModel.ts",
+ "frontend-modern/src/types/alerts.ts",
+ "frontend-modern/src/utils/alertThresholdDefaults.ts"
+ ],
+ "content_sha256": {
+ "frontend-modern/src/components/Alerts/ThresholdsTableAgentsTab.tsx": "89646984deb982699d3359953ab85a2ceae15830465ccf20b5603f5a426e3193",
+ "frontend-modern/src/components/Alerts/ThresholdsTableSMARTDefaultsCard.tsx": "c1bd1947dbcbab5806e11fa905271039131cebb0a736642e73fd3652f63e6b66",
+ "frontend-modern/src/features/alerts/alertsConfigurationModel.ts": "2100da1f350cbbea386f1ae669a655d213ea710f1636eb94fe80c6d47d29313d",
+ "frontend-modern/src/types/alerts.ts": "cc8b88ec5d8de87dbb69116114e9cd889347972b59dd81bec081096ab791c693",
+ "frontend-modern/src/utils/alertThresholdDefaults.ts": "6ea4a3f99c8bd27a4fcca98f67c866d06a0f5d3e3211550a58447688cb61352a"
+ },
+ "routes": ["/alerts/thresholds/systems"],
"viewports": [
{
"width": 1440,
@@ -17,17 +29,17 @@
}
],
"states": [
- "mock-mode Proxmox Backups loaded with standalone PBS service and correlated Agent host resources",
- "backup-vault expanded into the canonical resource detail row with PBS service identity and Agent metrics target",
- "History rendered stored utilization, network, disk, and thermal samples instead of Collecting History",
- "History range changed from 24 hours to 7 days and retained populated charts",
- "backup-vault collapsed back to the originating summary row"
+ "Machines thresholds loaded with the backward-compatible SMART factory rules",
+ "failed-health disabled with pending sectors set to 4, life warning set to 15 percent, and NVMe spare critical disabled at 0",
+ "edited SMART rules persisted after Save Changes and a full route reload",
+ "factory SMART values restored and saved from the narrow layout",
+ "complete single-column SMART card inspected through the app scroll shell at 390x844"
],
"interactions": [
- "opened backup-vault from the Backup servers table and selected the shared History tab at 1440x1000",
- "confirmed the desktop drawer showed populated Agent-backed charts and the document and body scroll widths matched the viewport",
- "repeated the whole-row touch expansion and History flow at 390x844, selected the 7 day range, and confirmed every chart card remained contained",
- "collapsed the phone detail through the originating backup-vault row and confirmed focus returned to that row",
- "confirmed the browser console contained no errors during the final desktop and phone verification flows"
+ "opened Alerts, selected Thresholds, and selected the Machines platform tab at 1440x1000",
+ "toggled failed-health, edited counter and percentage rules including an explicit 0 disable value, and saved through the shared dirty-state bar",
+ "reloaded /alerts/thresholds/systems and confirmed every edited value persisted",
+ "scrolled the complete SMART rules card at 390x844, confirmed scroll width matched client width, restored factory values, and saved from the narrow layout",
+ "confirmed labels, help text, controls, percentage suffixes, focusable save actions, and the browser console remained free of errors"
]
}
diff --git a/frontend-modern/src/components/Alerts/ThresholdsTableAgentsTab.tsx b/frontend-modern/src/components/Alerts/ThresholdsTableAgentsTab.tsx
index 9769c7cf6..55eb3c016 100644
--- a/frontend-modern/src/components/Alerts/ThresholdsTableAgentsTab.tsx
+++ b/frontend-modern/src/components/Alerts/ThresholdsTableAgentsTab.tsx
@@ -1,10 +1,12 @@
import { ThresholdsTableAgentDisksSection } from './ThresholdsTableAgentDisksSection';
import { ThresholdsTableAgentsResourcesSection } from './ThresholdsTableAgentsResourcesSection';
+import { ThresholdsTableSMARTDefaultsCard } from './ThresholdsTableSMARTDefaultsCard';
import type { ThresholdsTableSectionProps } from '@/features/alerts/thresholds/thresholdsTableSectionProps';
export function ThresholdsTableAgentsTab(props: ThresholdsTableSectionProps) {
return (
<>
+
>
diff --git a/frontend-modern/src/components/Alerts/ThresholdsTableSMARTDefaultsCard.tsx b/frontend-modern/src/components/Alerts/ThresholdsTableSMARTDefaultsCard.tsx
new file mode 100644
index 000000000..ad6ec84c8
--- /dev/null
+++ b/frontend-modern/src/components/Alerts/ThresholdsTableSMARTDefaultsCard.tsx
@@ -0,0 +1,127 @@
+import { For } from 'solid-js';
+import ShieldAlert from 'lucide-solid/icons/shield-alert';
+
+import type { ThresholdsTableSectionProps } from '@/features/alerts/thresholds/thresholdsTableSectionProps';
+
+const counterRules = [
+ {
+ key: 'smartReallocated',
+ label: 'Reallocated sectors',
+ help: 'Alert when the current counter reaches this value.',
+ },
+ {
+ key: 'smartPending',
+ label: 'Pending sectors',
+ help: 'Alert when sectors are waiting to be remapped.',
+ },
+ {
+ key: 'smartUncorrectable',
+ label: 'Uncorrectable sectors',
+ help: 'Alert when offline scans find unreadable sectors.',
+ },
+ {
+ key: 'smartMediaErrors',
+ label: 'Media errors',
+ help: 'Alert when the drive reports media or data-integrity errors.',
+ },
+ {
+ key: 'smartCrcErrorDelta',
+ label: 'CRC increase',
+ help: 'Alert when the CRC counter grows by at least this much between reports.',
+ },
+] as const;
+
+const percentageRules = [
+ { key: 'smartLifeWarning', label: 'Life remaining warning', help: 'Warn below this value.' },
+ { key: 'smartLifeCritical', label: 'Life remaining critical', help: 'Critical at or below.' },
+ { key: 'smartSpareWarning', label: 'NVMe spare warning', help: 'Warn below this value.' },
+ { key: 'smartSpareCritical', label: 'NVMe spare critical', help: 'Critical at or below.' },
+] as const;
+
+export function ThresholdsTableSMARTDefaultsCard(props: ThresholdsTableSectionProps) {
+ const updateValue = (key: string, value: number) => {
+ const normalized = Number.isFinite(value) ? Math.max(0, Math.trunc(value)) : 0;
+ props.tableProps.setAgentDefaults((previous) => ({ ...previous, [key]: normalized }));
+ props.tableProps.setHasUnsavedChanges(true);
+ };
+
+ return (
+
+
+
+
+
+ SMART alert rules
+
+
+ Defaults for agent-reported disks. Set a numeric rule to 0 to disable it.
+