Check pi liveness per tmux pane and add "Seen" marks to the control board (#1503)
First step-3 refinement from Jason's daily use. Liveness now lists the panes of the agent's tmux session and counts it alive only if a pane runs pi, so killed pi sessions whose tmux session still exists show offline instead of waiting. A "Seen" button on waiting and error rows stores the row's lastActivity in <dataRoot>/board/seen.json (clicks only, never rewritten by a scan, fail closed if corrupt) and drops the row from "Waiting on you" until the agent writes anything newer; "Unsee" reverses it. New POST /api/seen route: JSON only, 4 KB limit, 400 on bad input. Tests: control-board 63/63 (30 new), registry 69/69. Review APPROVED; receipt docs/plans/reviews/2026-09-12_control-board-step3-seen-marks.md. Co-Authored-By: Claude Fable 5.1 <[email protected]>
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
# Control board step 3, first refinement: real liveness and "Seen" marks
|
||||
|
||||
Date: 2026-09-12. Recorded by jarvis (Claude Code, coordinator). Tracking: #1503.
|
||||
Plan: `docs/plans/2026-09-12_control-board-mvp.md` (Step 3 log).
|
||||
|
||||
## What Jason reported
|
||||
|
||||
After using the page: "most of the sessions are actually just in a complete
|
||||
state rather than waiting on me". Also, he had terminated the darkwing and
|
||||
dewey pi sessions, and both still showed "waiting".
|
||||
|
||||
## Cause
|
||||
|
||||
1. Liveness only asked tmux whether a session by that name existed. Both
|
||||
tmux sessions still existed (now running bash and Claude), so the scanner
|
||||
read the old pi session log as live status.
|
||||
2. Pi records that the agent finished a reply, not whether that reply was a
|
||||
question or a completion report. Both landed in "waiting".
|
||||
|
||||
## What was built
|
||||
|
||||
- `tmuxIsAlive` now lists the panes of the named tmux session and reports
|
||||
alive only if one runs `pi`. A session that exists but runs something else
|
||||
is offline. The tmux check is injectable for tests.
|
||||
- "Seen" marks: `<dataRoot>/board/seen.json` maps `project/agent` to the
|
||||
`lastActivity` timestamp Jason marked. A marked row keeps its state but
|
||||
leaves "Waiting on you" until the agent writes anything newer, which
|
||||
changes the timestamp and clears the mark by itself. "Unsee" clears it by
|
||||
hand. The file is written only by clicks (atomic, mode 0600); a scan reads
|
||||
it and never rewrites it; a corrupt file refuses the scan (fail closed).
|
||||
- Server: `POST /api/seen` with a JSON body; requires
|
||||
`Content-Type: application/json` (so a page from another site cannot post
|
||||
it without a CORS preflight, which this server does not answer); body limit
|
||||
4096 bytes; 400 on bad input; 500 if the rescan fails. Other methods 405.
|
||||
- Page: Seen / Unsee button beside the state badge, "seen" tag, footer count.
|
||||
CLI `scan --print` shows `s` for seen rows and a seen count.
|
||||
|
||||
## Tests
|
||||
|
||||
`node --test packages/control-board/tests/`: 63 pass, 0 fail (30 new, written
|
||||
by a Claude Sonnet helper against the spec; no src change was needed).
|
||||
`node --test packages/mosaic/tests/`: 69 pass, 0 fail, unchanged.
|
||||
|
||||
## Live check
|
||||
|
||||
Real tmux, full fleet, Chrome via DevTools on port 7332. Before: 18 rows
|
||||
waiting on Jason including darkwing and dewey. After the liveness fix: 16,
|
||||
both now offline (their tmux sessions run bash). Clicking Seen on zane wrote
|
||||
`{"fleet/zane": "<timestamp>"}` (mode 600), the row left "Waiting on you"
|
||||
and showed a seen tag with Unsee in its project table; the API reported
|
||||
15 waiting and 1 seen. Unsee emptied the file and restored 16. Console: no
|
||||
messages. Screenshot `/tmp/control-board-seen.png` (not committed). The
|
||||
board was left with no marks.
|
||||
|
||||
## Independent review
|
||||
|
||||
Reviewer: code-review agent (Claude Sonnet), read-only. It checked the pi
|
||||
runtime source to confirm a live pi pane reports `pi` as its command (pi sets
|
||||
its process title, and tool subprocesses do not take over the pane), traced
|
||||
the CORS argument for the POST route, the escaping in the new markup, the
|
||||
single-response paths in the server, and the stale-mark fail-safe. Verdict:
|
||||
APPROVED with one finding: the README quoted the tmux command without the
|
||||
`-s -t '=<session>'` flags the code uses. Fixed in README and plan page.
|
||||
|
||||
## Boundaries kept
|
||||
|
||||
Loopback only, no auth, no daemon, no launcher changes, no new root files,
|
||||
no run records touched. `seen.json` is Jason's input, not derived data, and
|
||||
is the only board file a scan does not regenerate.
|
||||
Reference in New Issue
Block a user