Skip to content

zeph-acp: agent loop from a closed/superseded session can keep running and corrupt the reloaded session's turn #6674

Description

@bug-ops

Description

Follow-up from PR #6672 (fix for #6666/#6667), noted by impl-critic during review (M3, out of scope for that PR).

do_close_session/do_delete_session (crates/zeph-acp/src/agent/session.rs) remove a session's map entry without waiting for or aborting any turn still in flight on it — they only call notify_one() (session.rs:303, :343). If the session is then reloaded/resumed (do_load_session/do_resume_session) under the same SessionId, the old agent loop task is never joined or aborted; it can keep running and emit LoopbackEvents during the new session generation's turn.

PR #6672 already closes the narrower race where the old turn's guard would clobber the new entry's output_rx on Drop (via the generation stamp), and closes the inter-turn stale-event leak via draining in acquire_prompt_channels. But if the old agent loop is still actively producing events while a new turn on the reloaded session is in progress (not just in the gap between turns), those events can still interleave with and corrupt the new turn's drain_agent_events — the generation check and the drains only guard the channel handoff, not the fact that two agent loops can be alive for one SessionId at once.

Expected Behavior

do_close_session/do_delete_session should join or abort any turn in flight on the session before (or as part of) removing its entry, so a reload/resume can never have a stale agent loop still producing events for a SessionId it no longer owns.

Suggested Fix Direction

Track the in-flight turn's JoinHandle/abort mechanism on SessionEntry (or via the existing cancel-signal path used by do_cancel) and have close/delete abort it and await completion (with a bounded timeout) before the entry is removed, rather than firing a bare notify_one().

Environment

Logs / Evidence

Found during independent adversarial critique of PR #6672. See PR #6672 review discussion for the full analysis (finding M3).

Metadata

Metadata

Assignees

Labels

P3Research — medium-high complexitybugSomething isn't working

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions