chore(process): mark the agent/plugin detached spawns that are not owned children, with the reason

The detached-spawn check (scripts/check_detached_spawns.py, from the owned-child API) flags every
start_new_session outside spawn_owned. Five sites in this family are deliberately not owned. Each
now carries a `detached-spawn: ok — <why>` marker, so the check passes without a baseline entry:

- iron-proxy daemon: meant to outlive the CLI that started it; `hermes egress stop` ends it
  through the pidfile + nonce.
- google_meet bot: reached through files across turns and stopped by meet_leave (pid in
  .active.json).
- photon sidecar: exits on stdin EOF (PHOTON_SIDECAR_WATCH_STDIN). kill -9 probe with that exact
  watch block: 0 of 1 survived; the same probe with the watch off: 1 of 1 survived.
- ddgs search worker: awaited under a 30 s cap that kills its group. Blocked reading its request
  on a stdin pipe, it exits when the owner dies (kill -9 probe: 0 of 1 survived).
- secret_sources command helper: awaited under a hard timeout (default 3 s) that kills its group.

Comments only; no behaviour change.
This commit is contained in:
kshitijk4poor authored and kshitij committed 2026-10-29 16:58:09 +05:30
1 parent 118712327d
commit 6ff702ec0d
5 files changed
+5

No files matched your search

+1
View File
@@ -734,6 +734,7 @@ def _spawn_daemon(bin_path: Path, cfg: Path, env: dict[str, str], log_path: Path
# start_new_session is POSIX-only (Windows isn't supported anyway — no upstream binary).
return subprocess.Popen(
[str(bin_path), "-config", str(cfg)], env=env, stdin=subprocess.DEVNULL, stdout=log_fd, stderr=subprocess.STDOUT,
# detached-spawn: ok — a daemon meant to outlive the CLI that started it; `hermes egress stop` ends it (pidfile + nonce)
**({} if platform.system() == "Windows" else {"start_new_session": True}),
)
except OSError as exc:
+1
View File
@@ -78,6 +78,7 @@ def _run_helper(command: str, secret_key: str, timeout_seconds: float, max_outpu
proc = subprocess.Popen(
["/bin/sh", "-c", command], env=env, stdin=subprocess.DEVNULL,
stdout=subprocess.PIPE, stderr=subprocess.PIPE, # stderr captured and DISCARDED — never inherited
# detached-spawn: ok — awaited; a hard timeout (default 3 s) kills the whole group
start_new_session=True, # so the hard timeout can kill the whole group
)
except OSError as exc:
+1
View File
@@ -102,6 +102,7 @@ def start(url: str, *, out_dir: Optional[Path] = None, headed: bool = False,
# Detach: stdout/stderr → log file, new session so parent signals don't propagate.
with open(log_path, "ab", buffering=0) as log_fh:
proc = subprocess.Popen([sys.executable, "-P", "-m", "plugins.google_meet.meet_bot"], stdin=subprocess.DEVNULL,
# detached-spawn: ok — reached via files across turns, stopped by meet_leave (pid in .active.json)
stdout=log_fh, stderr=subprocess.STDOUT, env=env, start_new_session=True,
close_fds=True)
record = {"pid": proc.pid, "meeting_id": meeting_id, "out_dir": str(out), "url": url,
+1
View File
@@ -1054,6 +1054,7 @@ class PhotonAdapter(BasePlatformAdapter):
self._sidecar_proc = subprocess.Popen( # noqa: ASYNC220 -- persistent sidecar; callers use the Popen pipes and poll()
[self._node_bin, str(_sidecar_dir() / "index.mjs")],
stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=env,
# detached-spawn: ok — exits on stdin EOF (PHOTON_SIDECAR_WATCH_STDIN), so it dies with this process
start_new_session=(sys.platform != "win32"),
# Windows: run the persistent sidecar headless so it does not open
# (or leave) a visible console window. CREATE_NO_WINDOW only (no
+1
View File
@@ -110,6 +110,7 @@ def _spawn_worker(env: dict[str, str]) -> subprocess.Popen:
env["PYTHONPATH"] = path_entry + os.pathsep + child_pythonpath if child_pythonpath else path_entry
worker_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "_search_worker.py")
# Own process group/session so terminate/kill also reach a hung primp grandchild.
# detached-spawn: ok — awaited under a 30 s cap that kills its group; blocked on its stdin pipe, it exits on owner death
extra_kwargs: dict[str, Any] = {"creationflags": subprocess.CREATE_NEW_PROCESS_GROUP} if sys.platform == "win32" else {"start_new_session": True}
# stdin/stdout/stderr stay explicit keyword args so scripts/check_subprocess_stdin.py sees them
# (TUI gateway inherits stdin). stderr=DEVNULL: a chatty child would deadlock a stdout-only drain.