Skip to content

fix(server): delegated children can watch their own PR, and the parent hears every result - #26704

Open
BilalIrfanContact wants to merge 2 commits into
pingdotgg:mainfrom
BilalIrfanContact:fix/delegated-pr-watch-follow-up
Open

BilalIrfanContact wants to merge 2 commits into
pingdotgg:mainfrom
BilalIrfanContact:fix/delegated-pr-watch-follow-up

Conversation

@BilalIrfanContact

Copy link
Copy Markdown

Problem

A delegated child that opens a fix PR could never follow its CI, even when its task said "watch the PR and fix CI". The injected instructions said children never watch. The server also refused the call: watch tools were hidden from children, the MCP handler and orchestrator rejected the watch, and the watch reactor ended any watch a child held. If a child had watched anyway, results from its PR-watch wake turns never reached its parent. Fixes #25764.

Change

  • Children created by delegate_task may now call watch_pull_request and unwatch_pull_request. Provider-native subagents (e.g. Claude's Agent tool) are still refused by the existing read-only guard.
  • A PR-watch wake on a delegated child now starts a follow-up task on the parent, the same path background-command wakes already use (fix(server): notify parents after delegated background runs #23542). The child's result for that turn is delivered to the parent like any other delegated result.
  • When a child finishes a turn while still watching, the result the parent sees (the completion text and task_status) ends with: "T3 Code: this child still watches . Its results after pull request updates arrive as new delegated tasks, so this one is not final." The child's own reply shown in the UI is unchanged.
  • Ways out: the child calls unwatch_pull_request, or the parent's task_cancel / Stop on the parent stops the child, which already ends its watches (now covered by the existing Stop test).
  • Instructions: "Delegated children never watch, even if the brief says babysit" becomes "A delegated child watches only when its task asks for it." The Muse replay fixtures that embed this text, the user docs, and the eval case child-babysit-calls-watch (which encoded the old rule) are updated. The eval case is now child-asked-to-babysit-watches.

Scope and approval

Issue #25764 is a maintainer-filed bug that states the decided direction: "Julius has decided that the lead that opens a fix PR owns its CI follow-up through a PR watch," and lists the three expected behaviors this PR implements. The issue gives the "child holds a PR watch" signal to the parent only as an example; the exact form here (a line appended to the result the parent receives) is this PR's choice and open to review.

Verification

Before (unchanged main 9826dbb):
vp test run apps/server/src/mcp/toolkits/pullRequests/handlers.test.ts -t 'allows a subagent thread to watch a pull request' failed with PullRequestWatchFromSubagentError at handlers.ts:275, before any watch command was dispatched.

After (51b3274), both exit 0:

  • vp test run apps/server/src/mcp/toolkits/pullRequests/handlers.test.ts -t 'lets a delegated child watch its own pull request'
  • vp test run apps/server/src/orchestration-v2/DelegatedCompletionDelivery.test.ts -t 'delivers the run a pull request watch wake starts after the original result'. With only the new follow-up call removed, this case fails: the wake run gets no delegatedTaskId, so the parent is never told.

Also passed during development: the full ThreadStop, DelegatedCompletionDelivery and pullRequestWatch test files (94 tests), handlers.test.ts with McpHttpServer.test.ts (42), and the eval harness run.test.ts (409).

vp run check:changed upstream/main (25 files: the 23 in this PR plus 2 unrelated local skill edits): all steps passed. format, lint, knip 1/2 and 2/2, graphql (apps/server), typecheck (23 packages), and tests beside the changes (9 files, 542 tests). vp test run apps/server/src/orchestration-v2/testkit/MuseReplayFixtures.integration.test.ts (the updated Muse fixtures): 8 passed. The eval --dry-run for the three child cases built every request with the new instruction and watch_pull_request offered to the child (no model calls).

Runtime transcript (real orchestrator and projections on an isolated in-memory SQLite database; provider output and the GitHub check failure are synthetic events):

1. parent thread:parent delegated task node:delegated-task:delegate -> child thread:delegated-task:delegate (delegated_task.request)
2. child thread.pull-request.watch accepted; watch recorded on the child thread (startedAt from the test clock)
3. SYNTHETIC provider: child turn 1 completed. Parent task node:delegated-task:delegate [completed] result:
   "PR https://github.com/acme/app/pull/124, head abc1234, checks pending.\n\nT3 Code: this child still watches https://github.com/acme/app/pull/124. Its results after pull request updates arrive as new delegated tasks, so this one is not final."
3b. parent receives delegated completion for node:delegated-task:delegate:
   "Delegated task node:delegated-task:delegate [completed]:\nPR https://github.com/acme/app/pull/124, head abc1234, checks pending.\n\nT3 Code: this child still watches https://github.com/acme/app/pull/124. Its results after pull request updates arrive as new delegated tasks, so this one is not final."
4. SYNTHETIC host: PR #124 checks failed -> child wake run run:thread:thread%3Adelegated-task%3Adelegate:ordinal:2 [starting] bound to new parent task node:delegated-task:synthetic-host%3Achecks-failed [running]
5. SYNTHETIC provider: child wake turn completed after unwatch. Parent task node:delegated-task:synthetic-host%3Achecks-failed [completed] delivery=claimed result:
   "Fixed lint. PR https://github.com/acme/app/pull/124, head def5678, checks green. Unwatched."
6. parent receives delegated completion for node:delegated-task:synthetic-host%3Achecks-failed:
   "Delegated task node:delegated-task:synthetic-host%3Achecks-failed (Open a fix PR, watch it, and fix CI until green.) [completed]:\nFixed lint. PR https://github.com/acme/app/pull/124, head def5678, checks green. Unwatched."

Not verified:

  • The model eval (child-asked-to-babysit-watches plus the two child controls) has not been run. The runner has no GPT-6 Luna, and no eval credentials were available.
  • No live GitHub PR or CI run was used.
  • Children running in a linked environment (remote delegation) are out of scope.
  • The "still watches" line is a snapshot from when the result was written; a later unwatch shows up only in the child's next result.

Claude Opus 5.5 in Claude Code (via T3 Code).

🤖 Generated with Claude Code

BilalIrfanContact and others added 2 commits October 29, 2026 02:53
…esult reaches the parent

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Oct 28, 2026
@macroscopeapp

macroscopeapp Bot commented Oct 28, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs Human Approval

Macroscope's review found this PR requires human approval — Delegated children gain PR-watch tools, and subsequent watch results reach their parent as follow-up tasks. This changes the default capabilities available to delegated children and requires human confirmation of the resulting monitoring behavior.

You can add or adjust custom eligibility rules. Learn more.

@coderabbitai

coderabbitai Bot commented Oct 28, 2026

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review.

Recent review info
Run configuration
Commits

Reviewing files that changed from the base of the PR and between 5b89a53 and 51b3274.

Files selected for processing: 23
  • apps/server/src/mcp/McpHttpServer.test.ts
  • apps/server/src/mcp/McpInvocationContext.ts
  • apps/server/src/mcp/toolkits/pullRequests/handlers.test.ts
  • apps/server/src/mcp/toolkits/pullRequests/handlers.ts
  • apps/server/src/mcp/toolkits/pullRequests/tools.ts
  • apps/server/src/orchestration-v2/DelegatedCompletionDelivery.test.ts
  • apps/server/src/orchestration-v2/Orchestrator.ts
  • apps/server/src/orchestration-v2/PullRequestWatchReactor.ts
  • apps/server/src/orchestration-v2/ThreadStop.test.ts
  • apps/server/src/orchestration-v2/testkit/fixtures/multi_turn/muse_transcript.ndjson
  • apps/server/src/orchestration-v2/testkit/fixtures/muse_permission/muse_transcript.ndjson
  • apps/server/src/orchestration-v2/testkit/fixtures/muse_subagent_approval/muse_transcript.ndjson
  • apps/server/src/orchestration-v2/testkit/fixtures/muse_subagent_interrupt/muse_transcript.ndjson
  • apps/server/src/orchestration-v2/testkit/fixtures/muse_workflow/muse_transcript.ndjson
  • apps/server/src/orchestration-v2/testkit/fixtures/simple/muse_transcript.ndjson
  • apps/server/src/orchestration-v2/testkit/fixtures/subagent_v2/muse_transcript.ndjson
  • apps/server/src/orchestration-v2/testkit/fixtures/turn_interrupt/muse_transcript.ndjson
  • docs/user/source-control.md
  • evals/mcp-tool-use/cases/pull-requests.ndjson
  • evals/mcp-tool-use/run.test.ts
  • evals/mcp-tool-use/run.ts
  • packages/provider-core/src/server/runtimeInstructions.test.ts
  • packages/provider-core/src/server/runtimeInstructions.ts
Files with no reviewable changes: 3
  • apps/server/src/mcp/toolkits/pullRequests/handlers.ts
  • apps/server/src/mcp/McpHttpServer.test.ts
  • evals/mcp-tool-use/run.test.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.

Walkthrough

Delegated children can watch their own pull requests when their task requests it. Pull-request-watch updates can create delegated follow-ups, and the child’s result can report active watches to the parent.

Changes: Delegated pull-request watch flow

Layer / File(s) Summary
Enable delegated pull-request watch tools
apps/server/src/mcp/McpInvocationContext.ts, apps/server/src/mcp/toolkits/pullRequests/tools.ts, apps/server/src/mcp/McpHttpServer.test.ts, evals/mcp-tool-use/*, packages/provider-core/src/server/runtimeInstructions.*
The watch and unwatch tools are no longer hidden from delegated children. The child-specific watch rejection is removed from tool execution and runtime instructions.
Allow and retain delegated watches
apps/server/src/mcp/toolkits/pullRequests/handlers.*, apps/server/src/orchestration-v2/Orchestrator.ts, apps/server/src/orchestration-v2/PullRequestWatchReactor.ts, apps/server/src/orchestration-v2/ThreadStop.test.ts
Delegated-child watch requests proceed through the existing checks and dispatch. Subagent lineage no longer ends a watch by itself.
Dispatch pull-request-watch follow-ups
apps/server/src/orchestration-v2/Orchestrator.ts, apps/server/src/orchestration-v2/DelegatedCompletionDelivery.test.ts
Pull-request-watch wakes dispatch queued messages and record eligible delegated follow-ups. Delegated results include the URLs of active watches and a notice about later updates.
Update instructions and scenario coverage
apps/server/src/orchestration-v2/testkit/fixtures/*/muse_transcript.ndjson, docs/user/source-control.md
The instructions and transcript fixtures state that delegated children watch only when their task asks them to. The documentation describes watch updates and cancellation.

Priority: Normal

Estimated code review effort: 3 (Moderate) | ~25 minutes

Change: Bug fix · Severity of issue fixed: Medium

Sequence Diagram(s)

sequenceDiagram
  participant PullRequestWatchReactor
  participant Orchestrator
  participant DelegatedChild
  participant ParentThread
  PullRequestWatchReactor->>Orchestrator: Dispatch pull-request-watch wake
  Orchestrator->>DelegatedChild: Queue follow-up message
  DelegatedChild->>Orchestrator: Return follow-up result
  Orchestrator->>ParentThread: Record delegated follow-up and request parent wake
Loading

Suggested labels: bugfix

Suggested reviewers: juliusmarminge, macroscopeapp, t3dotgg

Merge Risk: Minimal · up to 51b32

No actionable issue is established; the change is mergeable after normal checks.

Pre-merge checks: Passed 4
Check name Status Explanation
Description check Passed The description includes all required sections. It clearly explains the problem, implementation, scope approval, focused verification, limitations, and agent usage.
Title check Passed The title is concise, specific, and accurately summarizes the two primary changes: delegated children can watch their own pull requests, and the parent receives subsequent results.
Linked Issues check Passed Issue #25764 has coding requirements. The runtime instruction now says, “A delegated child watches only when its task asks for it.” The watch tools and handlers allow delegated children while the prov…
Out of Scope Changes check Passed The changes stay within issue #25764. Server changes implement child watch authorization, wake delivery, parent notification, and watch lifecycle behavior. Tests cover these paths. Runtime fixtures, u…
Full details: Linked Issues check

Explanation

Issue #25764 has coding requirements. The runtime instruction now says, “A delegated child watches only when its task asks for it.” The watch tools and handlers allow delegated children while the provider-native subagent read-only guard remains. The orchestrator dispatches pull-request-watch wakes as delegated follow-up tasks, and the parent-facing result adds the active-watch notice. The child result therefore reaches the parent. The changed tests cover child watch acceptance, follow-up delivery, and stop behavior.

Full details: Out of Scope Changes check

Explanation

The changes stay within issue #25764. Server changes implement child watch authorization, wake delivery, parent notification, and watch lifecycle behavior. Tests cover these paths. Runtime fixtures, user documentation, and the evaluation case update the same delegated-child watch policy. No unrelated production behavior is demonstrated.

Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L 100-499 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Delegated children are told never to watch their PR, so nobody follows CI on a child's fix PR

1 participant