f29ee96dd3
The macOS branch of the update's fleet-restart step only restarted the invoking profile's LaunchAgent. Sibling ai.hermes.gateway-<profile> services kept pre-update modules cached in sys.modules and died on their next agent turn (ImportError on new lazy imports, or TypeError/ AttributeError with garbled tracebacks on wider version gaps). The systemd branch already iterates every hermes-gateway* unit; this brings launchd to parity: - _restart_macos_launchd_gateways(): the invoking profile keeps the existing launchd_restart() path; every other gateway of this install is drained via SIGUSR1 (same as systemd siblings), then hard- kickstarted unless KeepAlive already respawned it, then verified on a fresh PID. TimeoutExpired is isolated per label (#68523 parity) and counts toward failed_or_stale_units — including timeouts during liveness discovery, which must not read as "unloaded". - Install-scoped fleet enumeration: launchd_gateway_labels_for_install() derives labels from THIS install's profiles (get_default_hermes_root), not by globbing the shared per-user ~/Library/LaunchAgents — a sandboxed HERMES_HOME (tests, capture sandboxes, side-by-side installs) must never enumerate, let alone restart, another install's fleet. This also keeps the hermetic test suite blind to a dev machine's real gateways. - Domain-explicit sibling handling via _locate_launchd_gateway_service(): liveness, kickstart, and fresh-PID verification all use the domain the service was actually located in (gui/<uid> vs user/<uid> probed per label via `launchctl print`). This addresses the #41403 review defect: the process-wide _launchd_domain() cache resolves the current profile's domain and must never be reused for a sibling. _launchd_domain() itself becomes a thin caching wrapper; behavior unchanged. - _get_service_pids(all_profiles=...): the update path's manual-process sweep excludes every gateway service PID (mirror of the systemd hermes-gateway* pattern) so it cannot mistake a freshly respawned sibling service for a stale manual gateway. Default-scope callers (gateway status, cron checks, stop_profile_gateway's orphan reaper — which kills what it is fed) keep the current-profile-only contract. - _warn_incomplete_gateway_fleet_restart() prints launchctl recovery hints for launchd labels alongside the systemctl ones. Supersedes and completes #41403, addressing its review feedback (per-label domain resolution + mocked regression tests). Co-authored-by: David Neyra <vyr.agent@vyrgs.com> Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>