Repository navigation
fix(server): discard queued updates when pull request watches end - #30894
OleKristianH wants to merge 1 commit into
Conversation
|
A real-world case that matches this teardown path, on 0.1.7 with the Claude provider: one busy thread watched about 25 PRs, the agent unwatched all of them between 12:58 and 15:58 UTC, and 115 unstamped PR-watch notices stayed queued afterwards. The agent cancelled them by hand, one With this PR, the legacy rule would have cleared all 115 at the last unwatch. Notices stamped after the upgrade would go at each PR's own unwatch, which is the better case: in this thread the unwatches were spread over three hours. Notices that are accepted while the watch is ending, and a newer head for a watch that stays on, still need the delivery check from #21239, as the description says. Per-PR coalescing (10 to 13 queued notices per PR here) is #26987. Written by Claude Opus 5.5 in T3 Code for the reporter. |
| }; | ||
| } | ||
| })(); | ||
| if (command.type.startsWith("thread.pull-request")) { |
There was a problem hiding this comment.
This gate only runs for thread.pull-request* commands, which matches the unwatch / merge-via-link.sync / unlink cases in the new tests. The next test in this file is "settling ends every pull request watch" — if settlement (or thread.stop) clears watches without going through a pull-request command, would queued message:pr-watch:* wakes still replay the way they do on main today?
If settlement already ends watches by dispatching thread.pull-request.watch with watching: false, this is fine and the docs are complete. If it mutates watch state some other way, the 115-notice case genesiscz described on a busy thread could still happen when the thread settles rather than when each PR is unwatched. Happy to treat that as follow-up either way; just wanted to check the boundary before this lands next to #21239.
Problem
PR-watch updates already queued behind an active turn survive unwatch, merge, and unlink. In an installed Linux desktop nightly (
0.1.8-nightly.20261104.4165, source8b44f42b), 19 such updates replayed after the watched PR had merged and the watch had ended, repeatedly waking completed work.Reproduce by keeping a turn active, letting several watched-PR updates queue, ending the watch before the turn finishes, then allowing the queue to drain. The old updates should no longer start provider turns.
Change
Persist the PR key and watch start time on generated monitor notifications. When a PR-link command ends a watch, cancel only its queued runs through the existing run/attempt/node cancellation path. Preserve active work, user messages, other monitor notifications, and other watched PRs. For legacy notifications without a stamp, discard only server-created
message:pr-watch:*entries after every watch in that thread has ended. The cancellation events survive projection rebuild.The optional shared-contract field decodes existing notifications; this changes shared server behavior for every client and provider, without a UI change. The user guide explains the cancellation behavior.
Scope and approval
Refs #21009, confirmed by a maintainer.
Related implementation: #21239 is already open. This is a narrower alternative that cancels at watch teardown and also retires existing untagged queued updates. It does not implement newer-head supersession or queue coalescing, and should not close the whole issue. This PR is submitted for comparison rather than as a request to land both overlapping approaches.
Verification
pnpm exec vp test run apps/server/src/orchestration-v2/runtimeLayer.test.ts -t 'discards queued PR updates when the watch ends'(3 passed).9e855385,pnpm exec vp run check:changed --concurrency 1 --timeout 900passed format, lint, the first unused-code scan, GraphQL generation checks, typechecks for all 36 affected packages, and all 147 tests across the five selected files (including the full runtime test file).check:changed(overall exit 1). The subsequent mandatory commit hooks completed successfully, including the fullvp run knip:check, format, and lint. No check or hook was bypassed.Runtime observation (UTC, read-only live-state inspection):
Limitations:
check:changedwas not rerun after the full unused-code scan passed in the commit hook. CI still owns the repository-wide suite, build, and release smoke. No live installation/database was modified, no real provider turn was launched, and no UI/platform-specific pass was performed.Implemented with GPT-6.1-Sol through the Codex harness in T3 Code.