todo: a commander's watcher does not survive a reboot
the 2026.08.25.01 tag was pushed and nothing picked it up. commander 40's loop-pid held 291464, dead; its last state file was written 2026-08-24 03:50, and the machine came up at 12:40 the same day. no cron, and deploy-watch.sh was not running either. commander 54 says "watching" only because it was armed after that boot. the watcher is a bare background process — not pm2, not systemd, parented to whichever agent turn armed it. so a reboot ends it silently, and the only signal is the absence of a word on a card. that breaks the one promise that makes a commander worth having, quietly. ranked by what it buys: SAY IT (a row that claims armed with a dead pid is already detectable — router.ts computes watcherArmed and watcherRunning separately for exactly this reason, so notify once and nothing else on the list matters), then re-arm on boot, then stop it being a bare process at all. interim: re-arm by hand after a reboot, and trust watcherRunning over yesterday. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Officer-Session: 656f5c85-e49a-4f1f-b9f3-042a04b4d043
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
---
|
||||
id: agent-coordination/a-commander-s-watcher-does-not-survive-a-reboot
|
||||
title: "A commander's watcher does not survive a reboot, and nothing says so"
|
||||
theme: agent-coordination
|
||||
status: open
|
||||
priority: urgent
|
||||
created: 2026-08-25
|
||||
date_source: stated
|
||||
order: 3
|
||||
---
|
||||
|
||||
**A commander's watcher loop is a bare background process, so a reboot ends it and nothing brings it
|
||||
back or mentions it.** Found 2026-08-25 while trying to deploy `2026.08.25.01`: the tag was pushed and
|
||||
nothing picked it up.
|
||||
|
||||
## What was verified
|
||||
|
||||
- `commanders/40/state/loop-pid` held **291464, dead**. Its last state file was written 2026-08-24
|
||||
03:50 — the `2026.08.24.02` rollout.
|
||||
- `uptime -s` says the machine came up **2026-08-24 12:40:11**.
|
||||
- `commanders/54` (Voice Memos) was armed after that boot and its pid is alive, which is why one card
|
||||
reads "watching" and the other does not.
|
||||
- Nothing else was watching either: no cron entry, and `data/deploy-watch.sh` was not running.
|
||||
|
||||
So a release sat on the remote with nobody looking at it, and the only signal was the absence of a word
|
||||
on a card. `watcher_armed` in `command_hq_sessions` was already `false` for both rows, so even the
|
||||
database did not think it was armed — the UI is honest, it just says nothing.
|
||||
|
||||
## Why it is worse than an ordinary crash
|
||||
|
||||
The commander doctrine is that you arm it and walk away for months. A watcher that dies on reboot
|
||||
breaks exactly the promise that makes a commander worth having, and it breaks it **quietly** — no
|
||||
notification, no failed run, no error anywhere. The owner discovers it by noticing that something which
|
||||
should have happened did not, which is the failure mode `docs/agent-coordination.md` exists to avoid.
|
||||
|
||||
Note it is not only reboots. Anything that kills the process tree the loop was spawned under does the
|
||||
same thing, and the loop's parentage is an accident of which agent turn armed it.
|
||||
|
||||
## What to build, in order of how much it buys
|
||||
|
||||
1. **Say it out loud.** The cheapest fix and most of the value: a commander whose row says it was armed
|
||||
and whose pid is dead is a **detectable** state — `liveLoopPid()` already answers it, and
|
||||
`router.ts` already computes `watcherArmed` and `watcherRunning` separately for exactly this reason.
|
||||
Notify the owner once when a watcher that was armed is found not running. Nothing else on this list
|
||||
matters if the owner is told.
|
||||
|
||||
2. **Bring it back on boot.** A loop that records its pid can record its command line beside it, and
|
||||
something at platform start can re-arm every commander whose row says armed and whose pid is gone.
|
||||
The awkward part is that the loop is authored by the commander itself, per commander — so what gets
|
||||
restarted has to be recorded when it is armed, not reconstructed afterwards.
|
||||
|
||||
3. **Stop it being a bare process at all.** `docs/commander-directory.md` already argues a commander is
|
||||
a directory rather than a session. A watcher belongs to that directory and could be supervised the
|
||||
way sidecars are, rather than inheriting whichever agent turn happened to spawn it.
|
||||
|
||||
## Interim, until any of it exists
|
||||
|
||||
**After a reboot, re-arm every commander by hand.** `watcherRunning` on the Command HQ grid is the
|
||||
truthful field — a card that does not say "watching" is not watching, whatever it did yesterday.
|
||||
|
||||
Related: [[agent-coordination]] docs, and `data/deploy-watch.sh`, which is the deploy commander's own
|
||||
loop script and equally unsupervised.
|
||||
Reference in New Issue
Block a user