# maintenance-thresholds.toml — every severity value the maintenance console # and the system-health-check workflow grade against, plus the shipped # curation defaults. Owned and installed by archsetup (canonical: # configs/maintenance-thresholds.toml in the archsetup repo; installed to # ~/.config/archsetup/maintenance-thresholds.toml). Both consumers read the # installed path, so severity rules can never drift between them. # # User curation and overrides live in ~/.config/maint/curation.toml and merge # over this file (scalars: user wins; [curation.*]: entries − disable + add). # Never record user marks here — an archsetup update replaces this file. # # Seed values migrated 2026-07-07 from the system-health-check workflow's # hard-won prose rules (the 2026-05-26 /home snapshot lesson, the 10 GB cache # trigger, the 35/60-day scrub bands) and the maintenance-console design doc. [storage] df_warn_pct = 80 df_crit_pct = 90 btrfs_scrub_warn_days = 35 btrfs_scrub_crit_days = 60 btrfs_unalloc_warn_gb = 10 # chunk headroom floor before ENOSPC weirdness zfs_scrub_warn_days = 35 zfs_scrub_crit_days = 60 zfs_capacity_warn_pct = 80 # ZFS performance degrades past 80 zfs_capacity_crit_pct = 90 zfs_frag_info_pct = 50 smart_wear_warn_pct = 80 # NVMe percentage_used (100 = rated life) smart_temp_warn_c = 70 fstrim_stale_days = 10 # weekly timer + slack (continuous discard exempts) hog_roots = ["/home/cjennings", "/var"] # disk top-consumers scan roots (slow-local); depth-1 of /home is just the user dir, so scan inside it hog_top = 8 # digest rows kept [snapshots] # Sane snapper TIMELINE limits — the 2026-05-26 /home pile-up fix. timeline_hourly = 6 timeline_daily = 7 timeline_weekly = 2 timeline_monthly = 2 timeline_quarterly = 0 timeline_yearly = 0 single_keep = 2 # DELETE STALE keeps the newest N singles zfs_count_warn = 1000 # runaway retention zfs_space_warn_pct = 20 # snapshot space vs pool capacity [packages] cache_warn_gb = 10 # suggest paccache beyond the weekly keep-3 keyring_warn_days = 60 # stale archlinux-keyring silently breaks updates [security] cve_min_warn = "high" # arch-audit severity floor that warns (the # constant Unknown/Low tail is background) [updates] pending_warn = 50 # "a lot" — reddens the strip border cache_stale_hours = 6 # network-tier cache older than this warns topgrade_warn_days = 14 # topgrade freshness # The live-update guard (never -Syu the graphics/wayland runtime under a # live session — the 2026-06-07 mesa+hyprland crash). fnmatch patterns # against pending package names; a hit arms UPDATE/TOPGRADE instead of # running ("press again to run anyway — or apply from a TTY"). guard_patterns = [ "mesa", "mesa-*", "lib32-mesa*", "hyprland", "hyprland-*", "aquamarine", "hyprutils", "hyprlang", "hyprcursor", "hyprgraphics", "*wayland*", "wlroots*", "vulkan-radeon", "lib32-vulkan-radeon", # ratio's GPU driver "vulkan-intel", "lib32-vulkan-intel", # velox's GPU driver ] [systemd] # The capability-derived expected set (paccache/reflector always; # btrfs-scrub@ + snapper timers on btrfs; sanoid + zfs-scrub-weekly@ on ZFS) # lives in code — this list adds host-agnostic extras on top. expected_timers_extra = [] [logs] app_log_warn_days = 7 # log-cleanup cron should hold ~7 days journal_digest_top = 10 # groups shown in the journal digest journal_disk_warn_gb = 2 # journald footprint before vacuum suggested coredump_window_days = 14 # dumps older than this age out of the count [memory] used_warn_pct = 90 # 1 - available/total (reclaimable-aware) used_crit_pct = 97 oom_window_days = 7 # kernel-journal OOM lookback [power] battery_low_pct = 15 # feeds the diagnostic state (glyph red) charge_limit_pct = 80 # the SET 80% longevity cap on velox cpu_temp_warn_c = 90 # k10temp Tctl / coretemp package gpu_temp_warn_c = 95 # amdgpu edge battery_health_warn_pct = 80 # charge_full vs design floor unclean_warn_pct = 25 # unclean-shutdown rate over recent boots unclean_boot_sample = 10 # boots assessed for the rate [network] ntp_offset_warn_ms = 100 # chrony last-offset bound (typical is sub-ms) [backups] rsyncshot_daily_crit_hours = 48 # daily backup older than this is a fire rsyncshot_hourly_warn_hours = 3 # graded only on hosts whose log shows hourly runs [services] docker_reclaim_warn_gb = 5 docker_reclaim_warn_pct = 50 # Expected crontab entries (substring match, comment lines ignored). Root # expectations apply only on backup sources (hosts with a rsyncshot log). cron_expected_root = ["rsyncshot"] cron_expected_user = ["log-cleanup"] [refresh] # Cadence knobs (seconds unless named otherwise) — spec Decision 8. live_secs = 3 fast_secs = 30 glyph_scan_mins = 30 net_scan_mins = 60 # --- shipped curation defaults (user layer adds/disables, never edits) ------ [curation.known_noise] # Journal-noise patterns bind to identifier + message snippet, never a whole # unit — a muted service's new errors still surface. entries = [ { identifier = "bluetoothd", pattern = "HFP" }, { identifier = "pixman", pattern = "Invalid glyph" }, { identifier = "xkbcomp", pattern = "Could not resolve keysym" }, ] [curation.expected_listeners] entries = ["sshd", "mpd", "tailscaled"] [curation.session_critical] # Process names KILL must never fire on (the lever renders disabled) — # systemd, the compositor and its plumbing, the audio stack, the panel # itself, and sshd (a remote session's lifeline). fnmatch patterns. entries = [ "systemd*", "Hyprland", "Xwayland", "waybar", "dbus-broker*", "dbus-daemon", "pipewire*", "wireplumber", "maint*", "sshd", ] [curation.expected_containers] entries = ["winvm"] [curation.pacnew_safe_delete] # Regenerated files whose .pacnew is safe to drop (reflector-managed / local). entries = ["/etc/pacman.d/mirrorlist", "/etc/locale.gen"] [curation.kept_orphans] # Packages pacman calls orphaned that are deliberate keeps (the rust lesson): # listed in evidence but never counted or warned on. KEEP/UNMARK levers write # the user layer; this shipped list stays empty. entries = [] [curation.qkk_known] # pacman -Qkk mismatches that are config knowledge, not integrity findings # (fnmatch patterns). Unverifiable reads and mtime-only mismatches are # already excluded in code; this covers managed symlinks, regenerated # caches, and files archsetup itself edits. entries = [ "/etc/resolv.conf", # resolver-managed symlink "/usr/lib/jvm/default", # archlinux-java symlinks "/usr/lib/jvm/default-runtime", "/usr/lib/ghc-*/lib/package.conf.d/package.cache", # regenerated by ghc-pkg "/usr/lib/vlc/plugins/plugins.dat", # regenerated plugin cache "/etc/conf.d/pacman-contrib", # archsetup sets PACCACHE_ARGS ]