fix(tracker-intake): keep issue claimed while a terminated worker's PR is in flight#3016
Open
illegalcall wants to merge 1 commit into
Open
fix(tracker-intake): keep issue claimed while a terminated worker's PR is in flight#3016illegalcall wants to merge 1 commit into
illegalcall wants to merge 1 commit into
Conversation
…R is in flight #2777 excluded terminated sessions from intake's seen set so a genuinely dead worker stops blocking re-spawn (#2746). But intake dedups only on live sessions and has no PR awareness, and Spawn has no issue-level guard. So when a worker opened a PR and was then killed or crashed while its issue stayed open (the PR unmerged, so `Fixes #N` had not closed the issue), the next intake tick spawned a duplicate worker — and a second PR — for the same issue (#2921). Intake now also treats an issue as claimed when a terminated session for it left an open or merged PR, via the existing per-session PR store (ListPRFactsForSession; a terminated session keeps its pr rows because kill/terminate only sets is_terminated, it does not delete the sessions row). A terminated session with no PR, or only a closed unmerged PR, still frees its issue for re-spawn, preserving #2746 and letting a rejected attempt be retried fresh. A PR-lookup error fails safe toward "claimed" so a transient read cannot cause a duplicate PR. Only terminated sessions whose issue is not already claimed by a live session are queried, so a healthy project issues no PR lookups. Tests: open/merged PR blocks re-spawn; closed-unmerged PR and lookup-failure cases; live-session-claims-without-PR-lookup. Existing #2777 tests unchanged. Fixes #2921 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Collaborator
|
Thanks for contributing to Agent Orchestrator. This PR is being picked up by the current external contributor on-call pair: If someone is already working on this, please continue as usual. For faster context or live questions, you can also join the AO Discord. Join the session here: Come by if you want to see what is being built, ask questions, or just hang around with the community. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
#2777 fixed #2746 by excluding terminated sessions from intake's
seenset, so a genuinely dead worker no longer blocks re-spawn. But that opened a new window (#2921):seenIssueIDs) and has no PR awareness — itsStoreinterface never exposed PR facts.Manager.Spawnhas no issue-level dedup.Fixes #NPR closes issue#Nonly on merge, not on open.So when a worker opens a PR and is then killed or crashes while its issue is still open (PR unmerged), the terminated session drops out of
seen, and the next 1-minute tick spawns a duplicate worker — and a second PR — for the same issue. The simplest trigger needs no crash: an operator killing a worker that already opened a PR.Fix
Intake now also treats an issue as claimed when a terminated session for it left an open or merged PR, using the existing per-session PR store (
ListPRFactsForSession). A terminated session keeps itsprrows because kill/terminate only setsis_terminated=1— it does not delete thesessionsrow (that persistence is the same basis as #2746), andpr.session_idcascades only on row delete.Behavior:
No schema/query/codegen change — reuses
ListPRFactsForSessionand adds one method to intake's localStoreinterface (satisfied by the production*sqlite.Store).Tests
Added to the
trackerintakepackage:TestPollDoesNotRespawnIssueWithOpenPRFromTerminatedSession— the tracker-intake: duplicate worker/PR spawned for an open issue whose worker was terminated after opening its PR (regression window from #2777) #2921 case.TestPollDoesNotRespawnIssueWithMergedPRFromTerminatedSession— merged work isn't redone.TestPollRespawnsIssueWhenTerminatedSessionPRClosedUnmerged— rejected attempt retried.TestPollTreatsIssueClaimedWhenPRLookupFails— fail-safe.TestPollLiveSessionClaimsWithoutPRLookup— live session claims with no PR query.All existing tests (including #2777's) pass unchanged; full package +
go build ./...+go vetclean.Scope
Only touches
trackerintake's dedup logic and its tests. Does not change the SQL layer, session lifecycle, orSpawn. Distinct from #2745 (reaper cannot terminate stuck sessions).Fixes #2921
🤖 Generated with Claude Code