What happens
Closing a pull request does not reach the agent turn working on it.
handlePullRequestEvent returns early on closed — "nothing to drive once
closed/merged" — so the turn keeps running, keeps holding a sandbox slot, and
keeps pushing commits to a branch whose PR no longer exists.
Observed
A pull request was closed as superseded. Its turn had been running about three
hours and did not stop: roughly 1.6 hours of it continued after the close, and
the branch head moved afterwards, so it was still committing to a dead branch.
The wasted slot is the smaller half. A bare close reads to an agent as "start
over" rather than "this was superseded", and the same session went on to open a
fresh pull request re-implementing the work that had already been collapsed
into another one. That duplicate then had to be found, understood against the PR
it duplicated, and closed with an explanation.
Both costs land on a capacity-bound fleet. During the same window at least one
turn was refused admission outright, so a slot held by a turn working a closed
PR is a slot a live turn did not get.
Why a cancel is the wrong first move
Cancelling outright matches the intent of a close, but it discards whatever the
turn has not pushed — the same loss a close is often trying to avoid. On a fleet
where turns routinely run for hours, that trades one silent loss for another.
The cheaper and safer half is to tell the turn. A turn told "this PR was closed,
superseded by another" does not rebuild it, and can finish its current step and
stop on its own.
Proposed direction
Deliver the close to the PR's sessions the way a review or a CI result is
delivered — as durable context rather than as new work, so no execution is
started and no sandbox slot is consumed.
Two details worth getting right:
- Merged and closed-without-merging should say different things. That is
exactly the distinction the duplicate PR turned on.
- More than one session can be mid-flight for one PR. The management thread
driving CI and merges and a review-response thread addressing feedback are
separate sessions, and either may be running.
Cancelling the turn, or bounding it, is a reasonable follow-up once the
notification exists — but the notification is what makes the failure diagnosable
and stops the duplicate-work case on its own.
Acceptance
- A close appends context to the PR's sessions and starts no execution.
- Merged and closed-without-merging are distinguishable in what the turn sees.
- One session failing to be notified does not prevent the other being told.
What happens
Closing a pull request does not reach the agent turn working on it.
handlePullRequestEventreturns early onclosed— "nothing to drive onceclosed/merged" — so the turn keeps running, keeps holding a sandbox slot, and
keeps pushing commits to a branch whose PR no longer exists.
Observed
A pull request was closed as superseded. Its turn had been running about three
hours and did not stop: roughly 1.6 hours of it continued after the close, and
the branch head moved afterwards, so it was still committing to a dead branch.
The wasted slot is the smaller half. A bare close reads to an agent as "start
over" rather than "this was superseded", and the same session went on to open a
fresh pull request re-implementing the work that had already been collapsed
into another one. That duplicate then had to be found, understood against the PR
it duplicated, and closed with an explanation.
Both costs land on a capacity-bound fleet. During the same window at least one
turn was refused admission outright, so a slot held by a turn working a closed
PR is a slot a live turn did not get.
Why a cancel is the wrong first move
Cancelling outright matches the intent of a close, but it discards whatever the
turn has not pushed — the same loss a close is often trying to avoid. On a fleet
where turns routinely run for hours, that trades one silent loss for another.
The cheaper and safer half is to tell the turn. A turn told "this PR was closed,
superseded by another" does not rebuild it, and can finish its current step and
stop on its own.
Proposed direction
Deliver the close to the PR's sessions the way a review or a CI result is
delivered — as durable context rather than as new work, so no execution is
started and no sandbox slot is consumed.
Two details worth getting right:
exactly the distinction the duplicate PR turned on.
driving CI and merges and a review-response thread addressing feedback are
separate sessions, and either may be running.
Cancelling the turn, or bounding it, is a reasonable follow-up once the
notification exists — but the notification is what makes the failure diagnosable
and stops the duplicate-work case on its own.
Acceptance