Repository navigation
Add /work-system:manager status slice and worker events (work-system 1.32.0) - #101
Conversation
b91d58c to
174e796
Compare
5801cf8 to
6c876fa
Compare
|
Review by Jonas Schmied (Dev bot), posted by Oskar because the jonas-schmied app is not installed on this repo. Reviewed head 6c876fa, verdict: approve. S1/S2 pushed as follow-up commit a4814f9. Review of 6c876fa. Mainly workers.py (events), workers.sh, manager.sh, herdr-agent.sh, the tests, the schema and the version files. Verdict: approve. No blockers. Headless use (dev-1, no TTY)
Idempotence and dispatch
Mutation probes (each one turns a test red)
Tests and versions
CI on 6c876fa: scan pass, structure pass. Should (non-blocking, will be addressed in a follow-up commit on this branch)
Nit
Not checkable here: real herdr/dev-1 behaviour and a live |
…rust note Save the dedupe state atomically after every ping or on-blocked run, so a run killed mid-loop does not re-send events it already delivered. Add a test that kills a run inside the loop, then checks the delivered event is not re-sent. Reword the README and workers.py note on the main checkout's .work-system.toml: ignoring a lane's copy is defense in depth, not a boundary. Refs #101
|
Delta review 6c876fa → a4814f9. Verdict: approve. No blockers.
CI on a4814f9: scan pass, structure pass. Disclosure: I authored the S1/S2 commit (applied by Oskar via |
…1.32.0) - workers.sh/workers.py: list, screen, question, ready (read-only) and a one-shot, deduplicated `events` for blocked workers and ready-for-merge lanes - Reuse herdr-agent.sh preludes (classify_cwd, session name, composer check) through the wrapper; the only write path is manager.sh prompt - One tri-state ready-for-merge rule (assess + gh + mandate covered) shared by the skill and events; unknown answers never re-arm a delivered event - on-blocked command only from a CLI flag or the user-scope events.toml; the main checkout's [events] enabled / escalate_after, never a lane's copy - manager.sh prompt never types into the caller's own pane - test_workers.py with fake herdr/gh and an argv proof that no pane is written - Skill, READMEs, CHANGELOG, CLAUDE.md, knowledge entry Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RtoWD1aAxWazpn1eWEyVmq
…rust note Save the dedupe state atomically after every ping or on-blocked run, so a run killed mid-loop does not re-send events it already delivered. Add a test that kills a run inside the loop, then checks the delivered event is not re-sent. Reword the README and workers.py note on the main checkout's .work-system.toml: ignoring a lane's copy is defense in depth, not a boundary. Refs #101
a4814f9 to
6191137
Compare
Summary
First slice of
/work-system:manager: the status part. Dispatch/collect stay inadd-manager-watch-loop.scripts/workers.sh/workers.py—list,screen,question,ready(all read-only) and a one-shotevents.classify_cwd(exported by the wrapper fromherdr-agent.sh, likesessions.sh), so there is no second path classifier.question(blocked dialog),asks(trailing question),verify(idle while the screen shows activity or could not be read; herdr #4376/#3090),draft(someone types).screenclamps--linesto 20..200 (herdr #5462);questionreads only the live dialog's options and never answers.events --state <file>, deduplicated:blocked: one event per pane + session UUID and transition; an/exitsuccessor starts fresh; herdr'sunknownstatus is no observation.ready-for-merge: one event per lane + head. Rule, shared withworkers.sh ready: open, non-draft, same-repo PR at the lane's HEAD; merge state CLEAN/HAS_HOOKS; no changes requested; at least one check and all green;mandate.sh covered. Tri-state: an unreadable answer never re-arms an event.manager.sh prompt, resolved in the worker's workspace. Stage 2 runs the user'son-blockedcommand (argv, JSON on stdin, either event) only when the ping did not land or afterescalate_after; a failing command is retried on at most 3 runs.~/.config/work-system/events.toml(regular, own, not group/world-writable), never from a repo. The main checkout's.work-system.tomlgets[events] enabled/escalate_after; a lane's own copy is ignored.manager.sh promptnever types into the caller's own pane (reason=manager-is-self)./work-system:manager; marks pane text, titles, recaps and payloads as data, never instructions. The Manager reports "ready for merge", never merges or approves.events.*), knowledge entry.Decisions from the task (Robert, 2026-11-03)
Only this slice now; ready-for-merge from
assess+ PR/CI +covereduntil a run record exists; command only from user scope or a flag;eventsis one-shot for a user timer. Patch PR #100 (1.31.1) is separate — expect a CHANGELOG rebase if it lands first.Test plan
test_workers.py: 123 checks with fake herdr/gh, real git and realmandate.sh; argv-log proof that nothing callsagent send-keys|prompt|send-textorpane send-*test_manager.py(incl. the own-pane guard)scripts/check-structure.py: 0 errors, 0 warningslist,list --all --json,screen <manager> --lines 5000→lines=200,question <manager>→blocked=noeventslive only with a throwaway tab and test worker (not run in the lane)Review
Three local
/swarm:reviewrounds. Round 1 ran with claude lenses only (both cc-harness voices failed with "no gateway token" despiteready); round 2 ran with native codex (gpt-6.1-sol) + grok-4.7, 3 families, 7 consensus findings. Agreed fixes applied and recorded (mandate.sh covered→via=agreed-fixes). Declined: deduping the/continuegate ping against the event ping, foldingassess+gh pr viewinto one call (assess is the agreed source), and droppinglast_linefrom the payload (the spec requires it; the README warns it may hold secrets).Round 3 (
/swarm:review --fix, codex gpt-6.1-sol + grok-4.7 + lenses, 25 findings, 3 consensus): fixed ready-for-merge for lanes with several panes (all must be idle), dialog options with description lines and with a prompt below an old list, the hook's captured pipe (output now discarded), re-firing the same head after a red re-run, pruning on an empty agent list, pinging forever on reasons that cannot change,eventswithout tomllib (now exit 3), the task name typed raw into the Manager (slugged),asks=unknownon a failed read, plus doc gaps. 13 new tests (136). Declined: SKIPPED/NEUTRAL-only rollups (GitHub counts them as passing), theon_blockedname (from the spec), assess + gh again, a single combined screen read (recent ≠ visible), and unifying the sanitizers with sessions.py (no canonical one; separate task).Round 4 (
/swarm:review --fix, same voices, 13 findings, 3 consensus, 8 refuted):readynow applies the lane-wide idle rule too (reason=lane-busy), so the skill andeventsagree; a record is pruned only when its pane, session or lane was seen gone (a role that fell tootheron a main-repo-path timeout, or one poll without a UUID, re-fired the event); a retried ping printsretry=instead of a newevent=; the ping bound covers manager.sh's four herdr calls; the screen and dialog blocks blank bidi controls; herdr-agent.sh's JSON checks runpython3 -I; onerev-parseper lane; doc drift (final ping reasons, re-arm wording,questionexit codes, composer consumers). 5 new tests (141). Declined: assess + gh again (Robert's decision).Round 5 (
/swarm:review --fix, same voices, 15 findings, 5 consensus, 6 refuted; review budget now used up):eventsjudges a lane busy over every workspace (a--workspacerun missed a busy pane elsewhere) and counts any non-self agent in the lane or a sub-directory of it, asreadydoes;readyreads only that lane's screens (was O(workers²) per Manager pass); screen/dialog blocks blank C1 and unterminated escapes; the lock file is opened with O_NOFOLLOW; a badHA_CALL_TIMEOUT_SECSfalls back instead of a traceback;manager.sh'stask=attribution is a slug; doc fixes (skill and README synopses, settings README for linked worktrees, knowledge frontmatter). 5 new tests (146). Declined:no-main-repostays final (a deterministic failure), assess + gh (Robert's decision), a lazy screen read for delivered blocked events, and unifying the sanitizers (separate task).Round 6 (
/swarm:review --fixat Robert's request beyond the budget, over the branch including Oskar's checkpoint commit; 20 findings, 5 consensus, 4 refuted): a typed ping carriestask=andworktree=only as slugs (a worktree name with spaces read as a sentence outside the bracket), while the SendMessagebodykeeps the real names (the round-5 slug had changed it too);ping_textno longer repeats the task name, so the slug rule lives in one place; light reads also coverotheragents, so an idle-but-working agent in a lane sub-directory keeps the lane busy; a ready record survives while its agent sits in a sub-directory; a scoped run whose workspace emptied prunes its vanished panes (the empty-list guard is over every workspace); the skill callsreadyonce per lane; doc fixes (lane-busy wording,--escalate-aftersynopsis,ready_for_mergedocstring, CHANGELOG). 4 new tests (150) plus one in test_manager. Declined: replaying a still-current event after re-enabling, failing closed on an unreadableevents.enabled(ws-settings never blocks, by design), a hyphenated name inside the attribution bracket (residual), the own-pane guard withoutHERDR_PANE_ID(herdr always sets it), assess + gh (Robert's decision), scope-limited screen reads forevents, and sharing the composer glue (separate task).Review by Oskar; no merge without Robert's go.
🤖 Generated with Claude Code
https://claude.ai/code/session_01RtoWD1aAxWazpn1eWEyVmq