- log the worker thread's exception when a workspace op raises during
caller cancellation, so a persistently failing setup surfaces instead
of being buried behind CancelledError.
- raise on a timed-out (124) git symbolic-ref probe in the repo-exists
path, matching the rev-parse probes, instead of silently accepting the
caller-supplied branch.
- assert the subprocess timeout is passed in the two _chown_workspace
test fakes so a refactor cannot silently drop the bound.
Op: correct
Restores: spec:indeterminate-git-probes-raise-not-silently-proceed
Workspace setup/teardown (git clone/fetch, worktree add/remove, chown)
ran synchronously on the asyncio dispatcher loop, so one stalled
subprocess froze the entire process.
- Offload every ensure_workspace/remove_workspace call to a worker thread
via a new _run_workspace_op helper that drains the thread to completion
on cancellation, so a cancelled event cannot reap/release a slot the
setup thread still owns.
- Serialize same-repo setup with a per-repo threading.RLock while letting
distinct repos run concurrently.
- Bound the direct git/chown subprocesses with a 120s timeout
(returncode 124); treat a timed-out branch probe as an error rather
than "branch absent" to avoid silently rebasing a follow-up onto the
default branch and losing the PR's commits.
- When a timed-out worktree remove leaves the checkout behind, rmtree it
and run `git worktree prune` so the pool's dangling registration cannot
trip a later worktree add for the same path.
Adds regression tests for event-loop liveness, cancellation-safe offload,
per-repo lock serialization, subprocess timeout mapping, the branch-probe
timeout guard, and worktree-prune after a failed remove.
Op: correct
Restores: spec:dispatcher-event-loop-never-blocks-on-workspace-io