The finalized-issue boilerplate promises "reopen and I'll triage again from
scratch," but github_events.route() dropped issues.reopened to the ignored
skip branch (only opened/closed handled), while pull_request.reopened was
already routed. A user following the instruction got silence.
Route issues.reopened like issues.opened (submitter-attributable triage_issue,
same per-user rate budget) and dispatch it in queue._dispatch(). triage_issue
now tears down a stale finalized workspace (merged/closed/abandoned) before
re-provisioning, mirroring the maintainer directive-reopen teardown so the
re-triage branches afresh from default instead of a merged/deleted branch.
Fixes#5891
A diff-scoped review of the event-loop-hang fixes surfaced gaps in the new
timeout/error-handling code and its tests. All at/above the medium floor,
each mutation-verified.
- remove_workspace: prune on any nonzero `git worktree remove` (not just a
present checkout) and RAISE on a failed prune, so a killed remove that
leaves a dangling pool registration is cleared or retried instead of
recording success over stale metadata. Gate git ops on the pool being a
real clone (ensure_clone mkdir's the dir before cloning, so a failed first
clone leaves a non-git dir where `git worktree prune` would error), and
only speculatively prune a missing checkout when ws_root still exists.
- _worktree_add: new helper wrapping the three worktree-add sites; on a
failed add (incl. the new 124 timeout) it removes the partial checkout and
prunes the pool before re-raising, so the event retry starts clean. Raises
a failed prune chained from the add error.
- _reset_origin_url: a timed-out (124) `git remote get-url origin` probe is
indeterminate; raise before fetch instead of silently skipping the rewrite,
so a legacy credentialed origin cannot persist and be reused.
- tests: assert the subprocess timeout is passed in the _safe_run/_run
timeout fakes; add a real-`git worktree prune` integration test; make the
cancel-drain test deterministic (loop-turn pump, no wall-clock sleep) and
cover the repeated-cancel branch; add regressions for the prune-failure,
checkout-gone-on-entry, non-git-pool, and repeat-close cleanup paths.
Op: correct
Restores: spec:pool-cleanup-clears-or-retries-dangling-registration
Restores: spec:indeterminate-git-probes-raise-not-silently-proceed
- 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