[object Object]

← back to Nas Setup

backup-daemon-health: credit the user belt via its verified success log (fix false FAIL)

1256a2dd40be0d1a588aea98c54d3dab9e8c16d5 · 2026-08-17 22:58:57 -0700 · Steve Abrams

launchd runs/exit-code resets to 0 on reload/reboot and shows '(never exited)',
so the canary false-FAILed after the Aug pm2-fracture reboots even though the
user LaunchAgent wrote a verified Henry copy nightly. Now credit a belt when its
own log shows a recent '[Henry] PASS: <prefix>_' (stricter than exit code —
validates the outcome; anti-stale guard preserved via log-mtime recency).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Files touched

Diff

commit 1256a2dd40be0d1a588aea98c54d3dab9e8c16d5
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Mon Aug 17 22:58:57 2026 -0700

    backup-daemon-health: credit the user belt via its verified success log (fix false FAIL)
    
    launchd runs/exit-code resets to 0 on reload/reboot and shows '(never exited)',
    so the canary false-FAILed after the Aug pm2-fracture reboots even though the
    user LaunchAgent wrote a verified Henry copy nightly. Now credit a belt when its
    own log shows a recent '[Henry] PASS: <prefix>_' (stricter than exit code —
    validates the outcome; anti-stale guard preserved via log-mtime recency).
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
 scripts/daemon-health.sh | 26 ++++++++++++++++++++++----
 1 file changed, 22 insertions(+), 4 deletions(-)

diff --git a/scripts/daemon-health.sh b/scripts/daemon-health.sh
index 5aefb32..f7e347e 100755
--- a/scripts/daemon-health.sh
+++ b/scripts/daemon-health.sh
@@ -38,7 +38,7 @@ rows=()
 
 # check <db-name> <henry-dir> <dump-prefix> <base-label>
 check(){
-  local name="$1" dir="$2" prefix="$3" base="$4"
+  local name="$1" dir="$2" prefix="$3" base="$4" logf="${5:-}"
   local rootp userp root_ec user_ec newest age_h fresh verdict reason
   # BELT-AND-SUSPENDERS (Steve ruled 8/14 "Both", TK-10547): the Henry mirror is written by TWO
   # redundant schedulers — the -root SYSTEM LaunchDaemon (Option B: durable, survives logout, needs
@@ -65,6 +65,23 @@ check(){
   local root_ok=0 user_ok=0
   [ -n "$rootp" ] && [ "$root_json" = "0" ] && root_ok=1
   [ -n "$userp" ] && [ "$user_json" = "0" ] && user_ok=1
+  # launchd's runs/exit-code RESETS to 0 on every reload/reboot and shows "(never exited)" for a
+  # loaded-but-not-yet-refired job, so it cannot prove the USER belt landed a scheduled clean run
+  # (TK-10547 follow-up: after the Aug pm2-fracture reboots it false-FAILed while the belt wrote a
+  # VERIFIED Henry copy nightly). Ground truth = the belt's OWN success log: a recent
+  # "[Henry] PASS: <prefix>_..." line means the most recent run landed a verified copy. Recency
+  # (log mtime within the freshness window) preserves the anti-stale guard — a dead belt stops
+  # appending PASS and its dump goes stale -> still FAIL. This is STRICTER than the exit code: it
+  # validates the actual outcome, not just that launchd thinks a process exited 0.
+  local user_landed=0
+  if [ -n "$logf" ] && [ -f "$logf" ]; then
+    local lmtime lage_h
+    lmtime=$(stat -f %m "$logf" 2>/dev/null || echo 0)
+    lage_h=$(( (now - lmtime) / 3600 ))
+    if [ "$lage_h" -le "$STALE_WARN_H" ] && tail -n 25 "$logf" | grep -q "\[Henry\] PASS: ${prefix}_"; then
+      user_landed=1; user_ok=1
+    fi
+  fi
   local up=$(( root_ok + user_ok ))
 
   newest=$(ls -t "$dir/${prefix}"_*.dump 2>/dev/null | head -1)
@@ -75,6 +92,7 @@ check(){
   else age_h=-1; fresh="missing"; fi
 
   local writers="root(sys)=${root_word} user(gui)=${user_word}"
+  [ "$user_landed" = "1" ] && writers="$writers user-log=verified-PASS@${lage_h}h"
   # Henry-freshness is authoritative. Fresh via at least one healthy writer = data safe; both writers
   # healthy = PASS; exactly one down = WARN (degraded redundancy, fix the down belt); both down or
   # Henry missing/stale = FAIL (no working writer → the silent-death setup).
@@ -82,7 +100,7 @@ check(){
   elif [ "$fresh" = "stale" ]; then verdict="FAIL"; reason="Henry dump ${age_h}h old (> ${STALE_WARN_H}h) — neither writer is landing [$writers]"
   elif [ "$up" -eq 0 ]; then verdict="FAIL"; reason="Henry fresh (${age_h}h) but NO scheduled writer has landed a clean run — the mirror is only being kept fresh by manual rescue; the automated belts are not proven [$writers]"
   elif [ "$up" -eq 1 ] && [ "$REQUIRE_BOTH_BELTS" = "1" ]; then verdict="WARN"; reason="Henry fresh (${age_h}h) via one writer — redundancy DEGRADED, other belt down [$writers]"
-  elif [ "$up" -eq 1 ]; then verdict="PASS"; reason="Henry fresh (${age_h}h) via the accepted primary belt (root belt accepted-down pending FDA, Steve 8/15) [$writers]"
+  elif [ "$up" -eq 1 ]; then verdict="PASS"; reason="Henry fresh (${age_h}h) via a proven writer (verified PASS in its own log); root belt accepted-down pending FDA (TK-10547) [$writers]"
   else verdict="PASS"; reason="Henry fresh (${age_h}h), both writers healthy [$writers]"; fi
   [ "$(rank "$verdict")" -gt "$(rank "$worst")" ] && worst="$verdict"
 
@@ -94,8 +112,8 @@ check(){
 }
 
 echo "== on-prem backup daemon health ($(date -Iseconds)) =="
-check dw_unified  /Volumes/Henry/dw-backups/dw_unified  dw_unified  com.steve.nas-dwdump-mirror
-check realestate  /Volumes/Henry/dw-backups/realestate  realestate  com.steve.nas-realestate-dump-mirror
+check dw_unified  /Volumes/Henry/dw-backups/dw_unified  dw_unified  com.steve.nas-dwdump-mirror          "$HERE/../data/launchd.out.log"
+check realestate  /Volumes/Henry/dw-backups/realestate  realestate  com.steve.nas-realestate-dump-mirror  "$HERE/../data/launchd-realestate.out.log"
 echo "== overall: $worst =="
 
 # JSON heartbeat (PASS/WARN/FAIL vocab so fleet-health-rollup + meta-watchdog read it right)

← 9fc2571 daemon-health: fix jq --argjson crash on '(never exited)' —  ·  back to Nas Setup  ·  backup-repos-to-henry: cover ~/.claude and its 73 nested ski 7d6456f →