diff --git a/AppImage/components/hardware.tsx b/AppImage/components/hardware.tsx index 1a6c13fa..284851fa 100644 --- a/AppImage/components/hardware.tsx +++ b/AppImage/components/hardware.tsx @@ -1194,7 +1194,7 @@ return ( {engineName} {utilizationNum.toFixed(1)}% - + ) })} diff --git a/AppImage/components/storage-overview.tsx b/AppImage/components/storage-overview.tsx index 6112b905..7a98b6c4 100644 --- a/AppImage/components/storage-overview.tsx +++ b/AppImage/components/storage-overview.tsx @@ -1450,12 +1450,11 @@ export function StorageOverview() { {lifeRemaining !== null && (
- {lifeRemaining}% - life + life
)} @@ -1466,7 +1465,7 @@ export function StorageOverview() {

Wear

{wearUsed}%

- + )}
@@ -2737,10 +2736,10 @@ ${isNvmeDisk ? `
Percentage Used - ${nvmePercentUsed}% + ${nvmePercentUsed}%
-
+
@@ -2885,10 +2884,10 @@ ${!isNvmeDisk && diskType === 'SSD' ? (() => {
Wear Level - ${lifeUsed}% + ${lifeUsed}%
-
+
@@ -3602,12 +3601,10 @@ function HistoryTab({ disk }: { disk: DiskInfo }) { if (history.length === 0) { return ( -
- -
-

No test history

-

Run a SMART test to start building history for this disk.

-
+
+ + No test history + Run a SMART test to start building history for this disk.
) } diff --git a/AppImage/scripts/health_monitor.py b/AppImage/scripts/health_monitor.py index 2e3cdd7c..24c7d97d 100644 --- a/AppImage/scripts/health_monitor.py +++ b/AppImage/scripts/health_monitor.py @@ -1462,38 +1462,15 @@ class HealthMonitor: except Exception: pass - # Check disk_observations for active (non-dismissed) warnings - # This ensures disks with persistent observations appear in Health Monitor - # even if the error is not currently in the logs - try: - all_observations = health_persistence.get_disk_observations() - for obs in all_observations: - device_name = obs.get('device_name', '').replace('/dev/', '') - if not device_name: - continue - severity = (obs.get('severity') or 'warning').upper() - # Only include if WARNING/CRITICAL and not already dismissed - if severity in ('WARNING', 'CRITICAL') and not obs.get('dismissed'): - # Check if there's a corresponding acknowledged error in the errors table - # If so, skip this observation (it was dismissed via Health Monitor) - error_key = f"disk_smart_{device_name}" - error_record = health_persistence.get_error_by_key(error_key) - if error_record and error_record.get('acknowledged'): - continue # Skip - this was dismissed - - # Add to disk_errors_by_device if not already present - if device_name not in disk_errors_by_device: - obs_reason = obs.get('raw_message', f'{device_name}: Disk observation recorded') - disk_errors_by_device[device_name] = { - 'status': severity, - 'reason': obs_reason, - 'error_type': obs.get('error_type', 'disk_observation'), - 'serial': obs.get('serial', ''), - 'model': obs.get('model', ''), - 'dismissable': True, - } - except Exception: - pass + # NOTE: disk_observations is the PERMANENT historical record of disk events + # and must NOT be used as a source for Health Monitor warnings. + # Only the `errors` table (active alerts) drives the Health Monitor view. + # Observations are visible separately in the disk detail UI, where users + # can review the full history and dismiss individual entries if desired. + # + # Previous behavior read disk_observations here and created phantom warnings + # that persisted even after the underlying error was gone — conflating the + # permanent history with the current health state. # Add consolidated disk entries (only for disks with errors) for device_name, error_info in disk_errors_by_device.items(): diff --git a/AppImage/scripts/health_persistence.py b/AppImage/scripts/health_persistence.py index 6593f053..b67a838f 100644 --- a/AppImage/scripts/health_persistence.py +++ b/AppImage/scripts/health_persistence.py @@ -343,6 +343,12 @@ class HealthPersistence: # re-processed every cycle, causing infinite notification loops. # On upgrade, clean up any stale errors that are stuck in the # active state from the old buggy behavior. + # + # IMPORTANT: Only cleans the `errors` table (health monitor state). + # The `disk_observations` table is a PERMANENT historical record + # and must NEVER be auto-modified on startup. Users dismiss + # observations manually from the disk detail UI. + # # Covers: disk I/O (smart_*, disk_*), VM/CT (vm_*, ct_*, vmct_*), # and log errors (log_*) — all journal-sourced categories. try: @@ -363,26 +369,9 @@ class HealthPersistence: ''', (cutoff,)) cleaned_errors = cursor.rowcount - # Also dismiss stale disk observations that are still active - # but haven't been updated recently — leftovers from the - # feedback loop bug where occurrence_count kept incrementing. - # Detect column names for backward compatibility - cursor.execute('PRAGMA table_info(disk_observations)') - obs_cols = [col[1] for col in cursor.fetchall()] - last_col = 'last_occurrence' if 'last_occurrence' in obs_cols else 'last_seen' - - cursor.execute(f''' - UPDATE disk_observations - SET dismissed = 1 - WHERE dismissed = 0 - AND {last_col} < ? - ''', (cutoff,)) - cleaned_obs = cursor.rowcount - - total_cleaned = cleaned_errors + cleaned_obs - if total_cleaned > 0: + if cleaned_errors > 0: conn.commit() - print(f"[HealthPersistence] Startup cleanup: removed {cleaned_errors} stale error(s), dismissed {cleaned_obs} stale observation(s)") + print(f"[HealthPersistence] Startup cleanup: removed {cleaned_errors} stale error(s) from health monitor") except Exception as e: print(f"[HealthPersistence] Startup cleanup warning: {e}")