diff --git a/AGENTS.md b/AGENTS.md index 228d323..9b36b18 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -116,5 +116,13 @@ The merge-redact fix covers bot-driven merges only; the prune should redact befo `agents +/-`) deleted as finished; Phase 4 deleted because spark-control has shipped this bot's tile since v0.28.0; deploy-on-a-non-static-repo dropped (no repo needs it, and the deploy step is hardcoded to the static-site publish script, so a per-repo deploy-command field would have to come first). -Remaining: onboard 3 repos, and a heartbeat so a **wedged** poll loop is distinguishable from healthy -(the tile reads container state, so it already catches a crash but not a stuck loop). +That left two items: onboard 3 repos, and a wedged-loop heartbeat. + +**Backlog adjudicated 2026-07-29:** the heartbeat is **dropped** — a healthcheck badge doesn't restart +anything here, spark-control's tile would need its own change to read it, and serial per-room polling +(a review may run 10 min) makes any staleness threshold either too loose to be timely or noisy +mid-review; no wedge has ever been observed. Reopens only on an *observed* wedge **plus** confirmation +the tile already renders Docker health. In its place ROADMAP carries a **fold-in**: bound the two +unbounded awaits in `src/bot.py` (`await proc.wait()` after the timeout kill in `ssh_run`; +`client.room_send` in `say()`) and stop the process if the poll task ever dies, so +`restart: unless-stopped` + the tile cover it. Phase 3's onboard-3-repos verify item stands. diff --git a/ROADMAP.md b/ROADMAP.md index b023dd4..9dbc900 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -12,11 +12,14 @@ Phases beyond the first milestone (threaded single-flow review + merge/reject/de task walks the rooms in turn), so "no interleaving" is trivially satisfied; the thing actually worth watching at 3+ repos is a long review **head-of-line-blocking** the next room's poll, i.e. the latency problem the deferred poll→webhook item anticipates.)* -- Emit a heartbeat the poll loop touches, so a **wedged** bot (container up, sync/poll loop silently - stuck) is distinguishable from a healthy one — today it looks identical from outside. Crash detection - is already covered by spark-control's tile, which reads the container's docker state; this is only the - gap that leaves. Lightest correct form is a heartbeat file a Docker healthcheck or any monitor can - read, **not** an HTTP status server (this repo has no HTTP surface; don't add one for a badge). + +## Fold-ins — do opportunistically, never a session of their own +- *(fold-in, not a session of its own)* Next time `src/bot.py`'s SSH or Matrix-send path is edited: + bound the two unbounded awaits (`await proc.wait()` after the timeout kill in `ssh_run`; + `client.room_send` in `say()`), and attach a done-callback to the poll task that stops the process + if it ever dies, so the existing `restart: unless-stopped` + spark-control tile cover it. No hang + has been observed; this is "unbounded is not a defensible default in a loop with no supervisor", + not a fix for a diagnosed bug. *(adjudicated 2026-07-29: fold-in only)* ## Deferred / non-goals - Not a Claude-session bot (that's matrix-bridge); not Maubot (revisit at ~6+ bots or web-UI mgmt);