fix(desktop): isolate process notifications by session - #64043
fix(desktop): isolate process notifications by session#64043xscale-team wants to merge 4 commits into
Conversation
tonydwb
left a comment
There was a problem hiding this comment.
Code Review Summary
Verdict: Comment
30 PRs reviewed (batch: 64044-63999). See aggregate summary at PR 64044.
Reviewed by Hermes Agent
Related: this is part of the ownership-filter-on-drain cluster with #63317, #61719, #54785 (and issue #62548). All isolate cross-session background-process completion notifications; #63317 in particular extends the ownership filter to every notification type (the same superset mechanism as this PR). Cross-linking for maintainer to pick the canonical landing. |
|
Live reproduction after the patch was committed but before restarting the desktop backend: a foreign terminal completion (proc_e9f0e5521efb, model-router security review, exit 1) was injected into this unrelated context-repair chat as a synthetic user turn, followed by that foreign turn's memory context. This confirms the affected runtime was still executing the old process-global notification routing and demonstrates the exact cross-session context contamination fixed by this PR. The foreign review output and its embedded question were ignored. |
tonydwb
left a comment
There was a problem hiding this comment.
Code Review Summary
Verdict: Comment
This PR isolates process notifications by session in desktop. Small, targeted fix.
Please verify:
- Notifications are correctly scoped to their session
- No cross-session notification leakage
Reviewed by Hermes Agent
tonydwb
left a comment
There was a problem hiding this comment.
Code Review Summary
Verdict: Comment
Changes
test_notification_poller regression: completion event now carries session_key for matching instead of relying on ownerless notification events being adopted by whichever poller wakes first.
Assessment
- Correctness fix: ownerless notification events now fail closed instead of being silently adopted by the wrong poller. More robust test isolation.
Reviewed by Hermes Agent
|
Thanks for addressing a real cross-session notification leak. Current main still limits Problems
Suggested changes
Automated hermes-sweeper review. |
|
Closing as superseded in substance. The two real leak paths this targeted are now fixed on main: ordinary addressed completions route by positive ownership at both the poller and the post-turn drain (#65419), and durable-restored/legacy events fail closed on unfiltered drains (#64593). Creation-side stamping also exists — terminal_tool persists session_key on background dispatch. What we're NOT taking is the hard-reject of ownerless work at creation: internal events (watch_overflow_*, etc.) are deliberately ownerless, and delivery handles ownerless-legacy events by design (global delivery in single-session contexts). Rejecting them at the boundary is a policy change that fights that design and would break single-session CLI flows where ownerless is normal. One idea here may still have legs: the zero-duration completion race (notification flags armed after process start, so very short commands can finish before registration). If you can demonstrate that on current main, a small focused PR for just that is welcome. Thanks @xscale-team — thorough work, most of it just landed via parallel routes. |
Summary
AIAgent.session_idwhen worker context is unavailableRoot cause
ProcessRegistry.drain_notifications(session_key=..., owns_event=...)previously applied ownership checks only to async-delegation events. Ordinary terminal completions share the same process-global queue and also become synthetic user turns, so another desktop chat could consume a stale completion first.A second creation-side gap made the issue possible:
terminal_tool()received an explicitsession_idfrom tool dispatch but ignored it when worker-thread context andtask_idwere empty. That produced ownerless processes. Notification flags were also armed after process start, allowing very short commands to finish before registration or notification setup.This PR now enforces ownership at both boundaries:
Losing an invalid legacy notification is safer than guessing an owner and contaminating another session. Legitimate terminal output remains available through the process registry, and delegation records remain queryable.
Incident evidence
At 2026-07-13 18:43, the desktop transport emitted terminal output for
proc_af1041e85102with an empty session ID. Its completion was persisted as a synthetic user turn in session20260713_162533_199471, which had no matching process-launch record. That unrelated Scribe chat consequently began responding to a Fleet Model Router audit.Verification
python -m pytest -q tests/tools/test_process_registry.py-> 108 passedpython -m pytest -q tests/tools/test_async_delegation.py tests/tools/test_delegate.py-> 186 passedtests/test_tui_gateway_server.py-> 319 passed, 3 unrelated existing failures around staletuiversusdesktopexpectationspy_compile, andgit diff --checkpassed