mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-26 18:31:34 +01:00
Fixes issues becoming permanently locked to a dead checkoutRunId after their owning heartbeat run terminates: activeRun appears null but every checkout returns 409. Root cause is that releaseIssueExecutionAndPromote clears the execution lock columns but never clears checkoutRunId, and the existing adoptStaleCheckoutRun helper's WHERE clause is too narrow (requires same agent + status='in_progress') to cover reassignment, monitor-driven status changes, or pickup by a different agent. - heartbeat.releaseIssueExecutionAndPromote: also clears checkoutRunId when it points at the terminating run, scoped by an idempotent WHERE on the matching run id. - issues service: new clearCheckoutRunIfTerminal helper symmetric to clearExecutionRunIfTerminal, with no assignee/status precondition since a terminal run holds no real claim. Wired into the same call sites as the execution-lock helper (checkout, assertCheckoutOwner, release). - recovery service: new sweepStaleIssueLocks pass that clears lock columns on any issue whose checkoutRunId or executionRunId references a terminal heartbeat run, with one activity_log row per cleared issue. Hooked into the startup recovery sequence and the periodic heartbeat timer alongside reconcileStrandedAssignedIssues. - Tests: route-level test for the stale-checkout self-heal on the next checkout attempt, plus service-level coverage for the sweeper across terminal-only, running-only, mixed, and idempotency cases. Co-Authored-By: Paperclip <noreply@paperclip.ing>