Skip to content

feat(daemon): durable health state, divergence escalation, staleness checks, watcher pre-filter - #188

Merged
chrisleekr merged 1 commit into
mainfrom
feat/daemon-reliability
Jun 20, 2026
Merged

feat(daemon): durable health state, divergence escalation, staleness checks, watcher pre-filter#188
chrisleekr merged 1 commit into
mainfrom
feat/daemon-reliability

Conversation

@chrisleekr

Copy link
Copy Markdown
Owner

Why

For a backup daemon, the worst failure is a silent one. Today the daemon's failure state lived only in memory (lost on restart), there was no notification or staleness signal, a vault divergence made it retry a doomed push on every keystroke forever, and high-churn agent dirs (sessions/history) woke pushes that snapshot nothing. A user could go weeks with zero successful backups and no signal.

Fifth PR in the series (follows #184, #185, #186, #187).

What

  • Durable health state — the daemon persists daemon-state.json (last success, last error, consecutive failures, stuck flag) and updates it on every success/failure, so health survives a crash/restart.
  • daemon status now reports last-successful-sync age, failures, and a stuck flag, and falls back to the durable file when the daemon is down — you can still see when sync last worked.
  • doctor gains a Daemon sync health row: fails when stuck, warns when installed but the last success is >24h old (or never), passes on a recent success. A silent backup failure is now loud.
  • Divergence escalation — on DIVERGED_HISTORY the daemon latches stuck, fires one desktop notification (osascript/notify-send, best-effort), and backs off watcher retries to once per 5 min instead of hammering. A manual agentsync push is never throttled; the next success clears it.
  • Watcher pre-filter — never-sync paths are filtered at the watch layer, so a noisy config dir no longer resets the debounce or wakes a no-op push.

Review fixes (caught in senior review)

Atomic temp+rename for the state file (no torn write on crash); ISO-datetime() validation on stored timestamps (a corrupt value degrades to empty instead of a misleading Date.parse NaN); isolated AGENTSYNC_DIR in the daemon test harness so tests never touch the real ~/.config/agentsync or fire real notifications.

Tests

state.test.ts (pure transitions incl. the stuck latch, persistence round-trip, corrupt-file degrade, formatAge); watcher shouldSkip filter; doctor health (stuck/never/not-installed/stale/recent); daemon status stuck-escalation, last-sync age, and offline durable-file fallback; daemon-index persistence-on-failure, startup-preserves-stuck, and health-field exposure. Full suite: 966 pass / 0 fail.

CI note

bun test exits non-zero on the per-file coverage floor; CI treats 0-fail as success.

🤖 Generated with Claude Code

…checks, watcher pre-filter

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011L7s33UCjpQkreXW7amAw2
@chrisleekr
chrisleekr merged commit ff845c8 into main Jun 20, 2026
23 checks passed
@chrisleekr
chrisleekr deleted the feat/daemon-reliability branch June 20, 2026 08:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant