Skip to content

fix(desktop): scope agent sweep to the owning app instance#808

Merged
wesbillman merged 1 commit into
mainfrom
brain/instance-scoped-sweep
Jun 1, 2026
Merged

fix(desktop): scope agent sweep to the owning app instance#808
wesbillman merged 1 commit into
mainfrom
brain/instance-scoped-sweep

Conversation

@wesbillman

Copy link
Copy Markdown
Collaborator

Problem

When two Sprout desktop instances run on the same machine — e.g. a just dev build alongside the installed DMG (the standard dogfooding setup) — one instance's cleanup kills the other instance's agents. Symptom: agents stop unexpectedly, all at once, when the dev instance reloads or quits.

Root cause

sweep_system_agent_processes (the machine-wide orphan safety net) matches agent processes purely on binary name + same uid + env SPROUT_MANAGED_AGENT=1. There is no scoping by which desktop instance spawned them, so a dev instance happily SIGTERMs the DMG instance's agents (and vice versa) — they match all three criteria.

The PID-file-based sweep (sweep_orphaned_agent_processes) is already correctly instance-scoped (dev and prod have different bundle identifiers → separate app_data_dir → separate agent-pids/ receipt dirs). This machine-wide scan was the one hole.

Fix

Give each agent an ownership stamp and make the sweep refuse to reap agents that aren't ours:

  • Stamp SPROUT_MANAGED_AGENT=<app-identifier> at spawn instead of =1. The app identifier (xyz.block.sprout.app for release, xyz.block.sprout.app.dev for dev) is stable across restarts, so a relaunched instance still recognizes and can reclaim its own prior agents while never matching another instance's.
  • process_has_sprout_marker (both macOS KERN_PROCARGS2 and Linux /proc/environ paths) now takes the current instance id and only matches agents carrying that id.
  • Added current_instance_id(app) and a shared sprout_marker_entry() helper so the spawn stamp and the sweep matcher can never drift apart.
  • Both sweep call sites (lib.rs quit path, restore.rs startup path) pass the instance id.

Ownership becomes a property the agent carries, not a question we poll — so no racy "is another Sprout still alive?" probing.

Verification

  • just desktop-tauri-check clean
  • just desktop-tauri-clippy clean with -D warnings (--all-targets)
  • just desktop-tauri-test416 passed / 0 failed, including a new marker_entry_is_namespaced_by_instance_id test pinning the marker format

Notes / out of scope

  • The check-file-sizes.mjs override for runtime.rs is bumped 1300→1330 (the file was already at its limit; +40 lines tipped it over). Rationale comment extended.
  • Optional liveness-check hardening was intentionally left out — identity stamping makes it redundant.
  • There is a separate latent bug where closing the window (vs quitting the app) fires RunEvent::ExitRequested and kills all agents. Real, but not the trigger here and out of scope for this PR — flagging for a possible follow-up.

@wesbillman wesbillman requested a review from a team as a code owner June 1, 2026 15:35
@wesbillman wesbillman force-pushed the brain/instance-scoped-sweep branch from aa866b0 to 304982f Compare June 1, 2026 15:37
The system-wide orphan sweep (sweep_system_agent_processes) matched any
process by binary + uid + SPROUT_MANAGED_AGENT=1, with no instance
scoping. With two Sprouts on one machine (e.g. a just dev build and the
installed DMG), one instance's sweep would SIGTERM the other's agents.

Stamp each spawned agent's SPROUT_MANAGED_AGENT marker with the spawning
desktop instance's bundle identifier (xyz.block.sprout.app vs .dev), and
make the sweep only reap agents carrying this instance's id. The
identifier is stable across restarts, so an instance still recognizes its
own previously-spawned agents while never touching another live Sprout's.

Co-authored-by: Brain <21994759fc7a6fa6b965551d35cfd7897d262f2495467f2d78694ddcfa6a5c7e@sprout-oss.stage.blox.sqprod.co>
Signed-off-by: Wes <wesbillman@users.noreply.github.com>
@wesbillman wesbillman force-pushed the brain/instance-scoped-sweep branch from 304982f to 893feb6 Compare June 1, 2026 15:40
@wesbillman wesbillman enabled auto-merge (squash) June 1, 2026 15:42
@wesbillman wesbillman merged commit 39911e4 into main Jun 1, 2026
15 checks passed
@wesbillman wesbillman deleted the brain/instance-scoped-sweep branch June 1, 2026 15:49
tlongwell-block pushed a commit that referenced this pull request Jun 1, 2026
* origin/main:
  feat(desktop): keyboard shortcuts — ⌘⇧N new channel + ↑-to-edit last message (#809)
  fix(desktop): scope agent sweep to the owning app instance (#808)

Signed-off-by: tlongwell-block <109685178+tlongwell-block@users.noreply.github.com>

# Conflicts:
#	desktop/scripts/check-file-sizes.mjs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants