Skip to content

fix(githubbot): tell a PR's sessions when it closes - #1548

Open
0xAlcibiades wants to merge 2 commits into
paradigmxyz:mainfrom
0xAlcibiades:alcibiades/stop-turn-on-pr-close
Open

fix(githubbot): tell a PR's sessions when it closes#1548
0xAlcibiades wants to merge 2 commits into
paradigmxyz:mainfrom
0xAlcibiades:alcibiades/stop-turn-on-pr-close

Conversation

@0xAlcibiades

Copy link
Copy Markdown

Closes #1547

Change

handlePullRequestEvent no longer returns early on closed. The close is
appended to the PR's sessions as durable context.

forwardToSessionApi with no executeMessage appends and returns without
starting an execution, so a close consumes no sandbox slot — which matters,
because the whole problem is a turn holding one it should not.

Three decisions

The turn is not cancelled. Cancelling matches the intent of a close but
discards unpushed work, which is the loss a close is often trying to avoid. On a
fleet where turns run for hours that trades one silent loss for another. Telling
the turn is the cheaper half and stops the duplicate-work case on its own; a
cancel or a bound is a reasonable follow-up once the notification exists.

Merged and closed-without-merging say different things. A bare close reads
to an agent as "start over", which is what produced a fresh PR re-implementing
work that had already been collapsed elsewhere. The closed message explicitly
says not to re-open or re-implement; the merged one says the work is complete.

Both PR-scoped threads are notified. The management turn driving CI and
merges and a review-response turn addressing feedback are separate sessions for
the same PR, and either may be mid-flight. Notification is per-thread
best-effort, so one failing does not stop the other being told, and a missed
notice does not fail the webhook.

Testing

Three new tests: both thread keys are notified; no /execute call is made (the
no-slot property); and the merged and closed wordings differ, with the closed
one carrying the "do not re-implement" instruction.

bun test in services/githubbot: 104 pass. bun run check:types clean.

Closing a pull request returned early with "nothing to drive once
closed/merged", so a turn already working the PR never learned. It kept
running, kept holding a sandbox slot, and kept pushing commits to a branch
whose PR no longer existed -- in one case for a further 1.6 hours on a fleet
that was refusing admissions the same night.

Worse than the wasted slot: a bare close reads to the agent as "start over"
rather than "this was superseded". One turn responded by opening a fresh pull
request re-implementing work that had already been collapsed elsewhere, which
then had to be found, understood and closed by hand.

The close is now delivered to the PR's sessions as an appended message. It is
context for whatever is already running, not new work, so no execution is
started and no sandbox slot is consumed. The turn finishes its current step
knowing the outcome rather than discovering nothing.

The turn is deliberately not cancelled. Cancelling would discard unpushed
work, which is the loss this fleet already suffers often enough.

Both PR-scoped threads are told, because a close matters to the management
turn driving CI and merges and to a review-response turn addressing feedback
on the same PR; they are separate sessions and either may be mid-flight.
Merged and closed-without-merging say different things, since that is the
distinction the duplicate PR turned on.
The close notice is appended through the session API, which mints the session
on the first append. Guarding on nothing, every closed PR in the workspace --
including ones nobody ever handed to the bot -- created a management and a
review session that held only the notice. Fetch the PR and skip when it is not
owned, matching the ownership check every other lifecycle action already does.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

A closed pull request never reaches the turn working on it

1 participant