Why
The autonomous loop has stalled silently before (a 13-hour gap where tick sessions stopped invoking the step scripts) and the cockpit currently says nothing about the loop itself — it shows workers and PRs but not whether the thing driving them is alive. Observability over the loop is the highest-value missing panel.
Change
Add a "Loop health" section to the cockpit (rendered by cockpit.sh, so it appears in both static and serve mode):
- Last tick: timestamp of the most recent tick, sourced from a tick log.
loop-tick.sh should append its one verdict line + timestamp to .claude/state/loop-ticks.jsonl (same node-built JSONL + rotation pattern as log-event.sh) so ticks become observable without parsing session transcripts.
- Current cadence: the census-computed cadence (FAST/WATCH/IDLE) from the latest tick.
- Verdict history: the last N verdict lines (action=none / advance issue=N / feedback pr=N), newest first.
- Stall banner: if now − last tick > 2× the current cadence interval, render a prominent warning ("loop stalled — last tick "). Absence of a tick log at all renders as "loop not armed", never a crash.
- Serve mode: the panel participates in the existing SSE refresh; no new endpoint needed if the data flows through the normal render.
Done when
- loop-tick.sh writes the tick record (with rotation, crash-safe atomic mv), covered by loop-tick.test.sh.
- cockpit.sh renders the panel from the log, covered by cockpit.test.sh (including missing-log and stalled cases).
- Zero agent tokens: everything is computed harness-side from the log file.
Why
The autonomous loop has stalled silently before (a 13-hour gap where tick sessions stopped invoking the step scripts) and the cockpit currently says nothing about the loop itself — it shows workers and PRs but not whether the thing driving them is alive. Observability over the loop is the highest-value missing panel.
Change
Add a "Loop health" section to the cockpit (rendered by cockpit.sh, so it appears in both static and serve mode):
loop-tick.shshould append its one verdict line + timestamp to.claude/state/loop-ticks.jsonl(same node-built JSONL + rotation pattern as log-event.sh) so ticks become observable without parsing session transcripts.Done when