7619564fbd
Plain type=completion events built in _run_process_watcher carried only session_key (chat/thread routing) with no spawning-session stamp, so after /new (or a session switch) a completion notification from the OLD session was injected into the chat's NEW session. Main already solved this exact class for async delegations via the _classify_completion_target pre-flight (_USER_BOUNDARY_END_REASONS drop on user-closed sessions, deliver on idle-ends, follow the compression-tip chain), but the gate only ran for type=async_delegation events. Kernel salvage of #16455: - Stamp the spawning conversation's session-db id (HERMES_SESSION_ID via session-scoped env) on the ProcessSession and the pending_watchers entry at spawn time in tools/terminal_tool.py; persist it through the process registry checkpoint/restore so recovered watchers keep the stamp. - Thread the stamp into the completion_evt built by _run_process_watcher (watcher entry first, ProcessSession fallback for recovered watchers). - In _deliver_completion_notification, run the SAME pre-flight classifier for stamped type=completion events: terminal -> drop with a log (output stays available via process(action='log')), retry -> False so the watcher re-polls, deliver -> proceed. The policy has exactly one owner (_classify_completion_target); nothing is forked. Unstamped legacy events keep today's deliver-always behavior, and the async-delegation path is untouched. Based on the session-boundary approach from #16455 by @Tosko4 (original PR was over-scoped across adapters/slash-commands/cron; this lands the kernel only). Tests: completion from a /new-closed session is dropped; completion after an idle-end still delivers; unstamped legacy event delivers; retry verdict returns retryable False without adapter injection; async_delegation gate unchanged; stamp survives checkpoint recovery.