Stale MultiAgentV2 branch in legacy completion watcher obscures the active completion path

Open 💬 2 comments Opened Jul 16, 2026 by StatPan

Summary

The legacy subagent completion watcher still contains a MultiAgentV2 delivery branch, even though normal V2 spawn/resume paths intentionally do not start that watcher. The active V2 completion path now lives in the session terminal-turn lifecycle instead.

This leaves a semantically stale branch and a direct unit test that can make changes appear correct without exercising production V2 routing.

Current behavior on main

  • AgentControl::maybe_start_completion_watcher contains a child_uses_multi_agent_v2 branch that sends an InterAgentCommunication message.
  • Normal V2 spawn and resume paths skip maybe_start_completion_watcher.
  • V2 child completion is actually forwarded by the session terminal-turn path (maybe_notify_parent_of_terminal_turn / forward_child_completion_to_parent).
  • multi_agent_v2_completion_queues_message_for_direct_parent calls the private watcher directly, so it covers a synthetic path rather than the normal V2 lifecycle.

I confirmed the mismatch by changing only the watcher's V2 trigger_turn behavior: the direct watcher unit test passed, while an integration test that spawned a real V2 child and completed its turn did not observe the corresponding automatic parent turn. The integration path only changed behavior when the session terminal-turn forwarding path was changed.

The watcher itself is not dead code: V1 still uses it. The concern is specifically the V2 branch inside the legacy watcher and the misleading V2 unit coverage around it.

Why this matters

  • It is easy to patch the wrong completion path when investigating V2 notification or wake-up bugs.
  • The watcher and session implementations can drift in delivery semantics such as trigger_turn.
  • A passing direct unit test can give false confidence while the production V2 path remains unchanged.
  • This obscures work on #15723, where the desired wake-up behavior needs to be implemented on the active path.

Related history and issues

  • #15570 introduced the custom MultiAgent V2 watcher.
  • #16308 added one-shot end-of-turn forwarding in the session lifecycle, which is now the active V2 completion path.
  • #15723 requests durable completion notification and wake-up behavior.
  • #33061 reports the opposite failure mode: a late subagent completion causing an extra user-visible response even with trigger_turn: false.

Proposed direction

  1. Make maybe_start_completion_watcher explicitly V1-only and remove its V2-specific branch, arguments, imports, and direct V2 watcher test where they are no longer needed.
  2. Replace the synthetic V2 watcher test with integration coverage that exercises spawn -> child terminal turn -> parent delivery through the session path.
  3. If V1 and V2 need shared code, share construction of a bounded, idempotent completion receipt rather than duplicating lifecycle ownership.
  4. Treat wake-up policy as a separate decision from this cleanup. A possible policy is:
  • enqueue one durable terminal receipt;
  • wake only when the parent is idle and has expressed that it is waiting for child work;
  • defer or coalesce while the parent is busy;
  • avoid unconditional trigger_turn: true, given the duplicate-response scenario in #33061.

Design questions

  • Should completion wake-up depend on explicit parent wait/join state rather than a fixed trigger_turn value?
  • Should V1 watcher delivery and V2 session delivery share a CompletionReceipt abstraction while keeping their lifecycle triggers separate?

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗