Skip to content

chore(openspec): tick verification tasks for multi-agent worktree change#665

Merged
NagyVikt merged 6 commits into
mainfrom
agent/claude/autofinish-watcher-lock-ttl-orphan-sweep-2026-06-30-02-05
Jun 30, 2026
Merged

chore(openspec): tick verification tasks for multi-agent worktree change#665
NagyVikt merged 6 commits into
mainfrom
agent/claude/autofinish-watcher-lock-ttl-orphan-sweep-2026-06-30-02-05

Conversation

@NagyVikt

Copy link
Copy Markdown
Collaborator

Automated by gx branch finish (PR flow).

NagyVikt added 6 commits June 30, 2026 02:13
The SessionStart shim scripts/agent-stalled-report.sh has always wrapped
scripts/agent-autofinish-watch.sh, but that watcher was never authored, so
the hook soft-exited 0 and merged-PR worktrees (the 'retained for now' path
in agent-branch-finish.sh) were never reaped.

Write it as a thin orchestrator over the existing 'gx worktree prune'
primitive: scans agent/* worktrees, reports stalled lanes (work present, no
open PR, past idle gate) and merged-but-retained lanes, and under --auto-merge
reaps merged lanes. Resolves the primary checkout via the git common dir so it
works from inside any worktree. Healthy in-flight lanes (open PR / live
process) stay silent.
A crashed or abandoned agent worktree keeps holding its file locks forever:
claimed_at was recorded but never acted on, and (unlike a pruned worktree,
whose lock file vanishes with it) a lingering-but-idle lane stays on disk so
its locks keep blocking other agents.

Add a 'reap' subcommand that clears locks from worktrees idle past a TTL
(default 7d / GUARDEX_LOCK_TTL_HOURS / --ttl-hours) that have no live process
inside them. The caller's own worktree is always live, so reap never clears
active locks; --dry-run reports without removing. A blocked 'claim' against a
past-TTL lock now prints a hint pointing at 'gx locks reap'. now_iso() routes
through now_epoch() so GUARDEX_LOCK_NOW_EPOCH makes claim ages deterministic
in tests.
…all'

After a bulk --all finish, reap merged-but-stranded worktree dirs whose branch
merged out-of-band and was never cleaned (the post-merge 'retained for now'
gap). Gated by a pure shouldSweepOrphans predicate: only --all, only on full
success (failed===0), never on a dry run, opt-out via --no-sweep-orphans. The
sweep delegates to the existing 'gx worktree prune --include-pr-merged
--delete-branches' primitive and is best-effort (a failure warns, never fails
the finish). Guard is unit-tested directly since the full PR finish flow needs
a GitHub host unavailable in unit runs.
Fill the OpenSpec proposal/spec/tasks (validates --strict, 133 specs pass) and
correct .agent/STALLED-WORKTREE-RECOVERY.md to match the conservative watcher:
--auto-merge reaps merged lanes only (never auto-commits/pushes/PRs un-reviewed
work), real flags are --idle-minutes/--interval/--base, and 'gx locks reap'
clears locks held by abandoned lanes.
Review found that --interval/--idle-minutes/--base ran `shift 2` even when the
flag was the last argument; under `set -euo pipefail` that exits 1 and silently
kills the script (the daemon would die on startup with no output). Guard each
with `[[ $# -ge 2 ]]` and a clear error. Also correct the dynamic-scope comment
and document the 200-PR detection cap in --help.
@NagyVikt NagyVikt merged commit ae52c87 into main Jun 30, 2026
@NagyVikt NagyVikt deleted the agent/claude/autofinish-watcher-lock-ttl-orphan-sweep-2026-06-30-02-05 branch June 30, 2026 00:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant