Description
Follow-up from #6661 (fixed in PR #6665). When PromptChannelGuard::drop restores the receiver after the enclosing task is aborted/cancelled mid-drain_agent_events, the receiver is restored as-is — any LoopbackEvents the still-alive agent loop had already queued into it (including a legitimate Flush sent right around the time of the abort) are not drained first.
The next session/prompt call on that session will call acquire_prompt_channels, get this same receiver back, and drain_agent_events's first rx.recv() will return one of these stale, leftover events from the previous, aborted turn — potentially producing a spurious immediate EndTurn/stop for the new prompt before the new turn has actually produced anything.
This is strictly better than the pre-#6661 state (a permanently wedged session), but it's a real correctness gap in the recovery path introduced by #6661's abort-handling fix.
Reproduction Steps
- Start a prompt whose agent loop will (eventually) send a
Flush event.
- Abort the
do_prompt task shortly after input_tx.send succeeds but before the Flush arrives, such that the Flush is queued into the channel after the abort.
- Send a new prompt on the same session.
- Observe: the new prompt's
drain_agent_events may consume the stale Flush (or other stale event) from the aborted turn instead of an event genuinely produced by the new turn.
Expected Behavior
Either drain and discard any events queued on the receiver before restoring it after an abort/cancel (e.g. while rx.try_recv().is_ok() {}), or otherwise ensure a restored-after-abort receiver cannot leak stale events into a subsequent unrelated prompt turn.
Environment
Logs / Evidence
Found during independent adversarial critique of PR #6665 (finding M3). See PR #6665 review discussion for the full analysis.
Description
Follow-up from #6661 (fixed in PR #6665). When
PromptChannelGuard::droprestores the receiver after the enclosing task is aborted/cancelled mid-drain_agent_events, the receiver is restored as-is — anyLoopbackEvents the still-alive agent loop had already queued into it (including a legitimateFlushsent right around the time of the abort) are not drained first.The next
session/promptcall on that session will callacquire_prompt_channels, get this same receiver back, anddrain_agent_events's firstrx.recv()will return one of these stale, leftover events from the previous, aborted turn — potentially producing a spurious immediateEndTurn/stop for the new prompt before the new turn has actually produced anything.This is strictly better than the pre-#6661 state (a permanently wedged session), but it's a real correctness gap in the recovery path introduced by #6661's abort-handling fix.
Reproduction Steps
Flushevent.do_prompttask shortly afterinput_tx.sendsucceeds but before theFlusharrives, such that theFlushis queued into the channel after the abort.drain_agent_eventsmay consume the staleFlush(or other stale event) from the aborted turn instead of an event genuinely produced by the new turn.Expected Behavior
Either drain and discard any events queued on the receiver before restoring it after an abort/cancel (e.g.
while rx.try_recv().is_ok() {}), or otherwise ensure a restored-after-abort receiver cannot leak stale events into a subsequent unrelated prompt turn.Environment
Logs / Evidence
Found during independent adversarial critique of PR #6665 (finding M3). See PR #6665 review discussion for the full analysis.