Skip to content

fix(gateway,tools): gate background-process completions on spawning-session boundary - #85939

Merged
teknium1 merged 1 commit into
mainfrom
fix/16455-completion-session-boundary
Aug 14, 2026
Merged

fix(gateway,tools): gate background-process completions on spawning-session boundary#85939
teknium1 merged 1 commit into
mainfrom
fix/16455-completion-session-boundary

Conversation

@teknium1

Copy link
Copy Markdown
Contributor

Summary

Background-process completions no longer land in the wrong conversation after /new — the spawning session id is stamped on the watcher at spawn and delivery is gated through the existing session-boundary policy.

Main already solved this class for async delegations (_classify_completion_target + _USER_BOUNDARY_END_REASONS); plain type=completion events carried only chat routing and bypassed the gate. This is the kernel salvage of PR #16455 by @Tosko4 (the original threaded boundary locks through 20 files; adapters/slash-commands/cron are deliberately untouched here).

Changes

  • tools/terminal_tool.py + tools/process_registry.py: stamp parent_session_id on watcher metadata at spawn; persists through checkpoint recovery.
  • gateway/run.py: _run_process_watcher includes the stamp in completion_evt; _deliver_completion_notification runs the EXISTING _classify_completion_target for stamped completion events (terminal → drop with log, retry → re-poll, deliver → proceed). One policy owner — no forked predicate. Unstamped legacy events behave exactly as today.

Validation

Case Result
Completion from /new-closed session dropped
Completion after idle-end delivered
Unstamped legacy event delivered (unchanged)
async_delegation path byte-untouched
New boundary tests + completion_delivery + bg-notifications + relay suites 71 passed, 0 failed
ruff + Windows-footgun checker clean

(The one red in the mirror test_process_registry.py run — test_checkpoint_redacts_command_with_inline_secret — is proven pre-existing on pristine origin/main and unrelated.)

Based on the session-boundary approach from #16455 by @Tosko4.

Infographic

Session boundary guard

… boundary

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.
@github-actions

github-actions Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

૮ >ﻌ< ა ci review

ran on 0a24aa1 — fix(gateway): gate background-process completions on spawnin

⚠️ Warnings

OSV vulnerability scan · View job

5 known vulnerabilities found in pinned dependencies.

How to fix:

Review the findings in the Security tab. Update the affected dependencies if a patched version is available.


debug info

CI timings

CI timings · View report · View job

Wall time 6m58s vs 6m50s (+2.0%). 14 job(s) slower, 8 faster, 2 unchanged.

  • Python tests / Run tests slice 8/12: -44.0s
  • Python tests / Run tests slice 6/12: +26.0s
  • Python tests / Run tests slice 11/12: +26.0s
  • Python tests / Run tests slice 10/12: +16.0s
  • Python tests / Run tests slice 2/12: +11.0s

@teknium1
teknium1 merged commit 7619564 into main Aug 14, 2026
83 of 84 checks passed
@teknium1
teknium1 deleted the fix/16455-completion-session-boundary branch August 14, 2026 08:09
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/gateway Gateway runner, session dispatch, delivery tool/terminal Terminal execution and process management sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state labels Aug 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/gateway Gateway runner, session dispatch, delivery P2 Medium — degraded but workaround exists sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state tool/terminal Terminal execution and process management type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants