Skip to content

fix(mac): verify launchd stop releases gateway port#81732

Merged
BunsDev merged 8 commits into
mainfrom
meow/macos-launchd-stop-postcondition
May 14, 2026
Merged

fix(mac): verify launchd stop releases gateway port#81732
BunsDev merged 8 commits into
mainfrom
meow/macos-launchd-stop-postcondition

Conversation

@BunsDev

@BunsDev BunsDev commented May 14, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Verify the effective macOS LaunchAgent gateway port after managed gateway stop cleanup before reporting success.
  • Resolve the port from LaunchAgent program arguments, the persisted LaunchAgent service environment, and then caller env so terminal gateway stop/gateway restart still check app-managed service ports.
  • Fail gateway restart before kickstart when the configured port is still busy after verified stale-listener cleanup.
  • Delay degraded fallback success output until after the port postcondition passes, so failed cleanup never prints Stopped LaunchAgent.
  • Add focused launchd regression coverage and a changelog entry for [Bug] openclaw gateway stop / launchctl bootout doesn't terminate underlying node process — wedged binary persists across stop #73132.

Fixes #73132.

Verification

  • PATH=/Users/buns/.cache/codex-runtimes/codex-primary-runtime/dependencies/node/bin:$PATH node scripts/run-vitest.mjs src/daemon/launchd.test.ts src/cli/daemon-cli/lifecycle.test.ts src/cli/daemon-cli/lifecycle-core.test.ts src/cli/daemon-cli/restart-health.test.ts
  • PATH=/Users/buns/.cache/codex-runtimes/codex-primary-runtime/dependencies/node/bin:$PATH pnpm exec oxfmt --check --threads=1 src/daemon/launchd.ts src/daemon/launchd.test.ts CHANGELOG.md
  • git diff --check
  • (cd apps/macos && swift test --filter GatewayLaunchAgentManagerTests)
  • (cd apps/macos && swift test --filter LaunchAgentManagerTests)
  • Testbox tbx_01krjwwv9z9z3f5d06fqph6eta: (git -c remote.origin.tagOpt=--no-tags fetch --unshallow origin '+refs/heads/main:refs/remotes/origin/main' || git -c remote.origin.tagOpt=--no-tags fetch --depth=10000 origin '+refs/heads/main:refs/remotes/origin/main') && git merge-base origin/main HEAD && pnpm check:changed

Behavior addressed: managed macOS LaunchAgent stop/restart no longer claims success when the resolved gateway port remains busy after cleanup, including the normal installed path where the port only exists in the persisted LaunchAgent service environment and fallback paths that report degraded stop success.

Real environment tested: local macOS SwiftPM package, focused TS/Vitest launchd/daemon CLI tests in the Codex worktree, and Testbox pnpm check:changed on the pushed PR branch.

Exact steps or command run after this patch: the six commands/listed proof items above were run after the patch and before this PR update.

Evidence after fix: TS focused tests passed with 4 files and 147 tests; SwiftPM GatewayLaunchAgentManagerTests passed 3 tests; SwiftPM LaunchAgentManagerTests filter passed the matching LaunchAgent/GatewayLaunchAgent suites with 4 tests total; formatting and whitespace checks were clean; Testbox tbx_01krjwwv9z9z3f5d06fqph6eta exited 0.

Observed result after fix: stop verifies the configured port before writing Stopped LaunchAgent, busy-port stop failures include listener diagnostics, restart aborts before launchctl kickstart when the port remains busy, stored LaunchAgent env-file-only ports are covered by stop/restart regression tests, and degraded fallback success is emitted only after the port is verified free.

What was not tested: signed app local-mode smoke was not run on this Mac because it would mutate the installed LaunchAgent/runtime state; that should be done on a dedicated macOS Testbox or smoke machine before landing.

@openclaw-barnacle openclaw-barnacle Bot added gateway Gateway runtime size: S maintainer Maintainer-authored PR labels May 14, 2026
@clawsweeper

clawsweeper Bot commented May 14, 2026

Copy link
Copy Markdown
Contributor

Codex review: found issues before merge.

Summary
The PR adds macOS LaunchAgent stop/restart gateway-port postcondition checks, resolves the port from LaunchAgent args/service env/caller env, extends launchd tests, and adds a changelog entry.

Reproducibility: yes. The linked issue gives concrete macOS stop steps, current main lacks listener/port verification, and this PR’s remaining issue is source-reproducible because fallback success text is emitted before the new postcondition can throw.

Real behavior proof
Not applicable: The external contributor proof gate does not apply to this MEMBER PR; the body lists focused TS, SwiftPM, and Testbox runs and explicitly notes signed app local-mode smoke was not run.

Next step before merge
This maintainer-labeled PR has a narrow P2 review finding, but the remaining action is author/maintainer revision and landing review rather than a standalone ClawSweeper repair job.

Security
Cleared: The diff reuses existing port inspection and stale gateway cleanup helpers, adds no dependencies or workflow changes, and parses the stored port through the existing strict positive-integer boundary.

Review findings

  • [P2] Delay degraded stopped output until port check passes — src/daemon/launchd.ts:684
Review details

Best possible solution:

Keep the postcondition and service-env resolution, but defer any stopped/degraded success output until the effective port is verified free and cover the busy fallback path in tests.

Do we have a high-confidence way to reproduce the issue?

Yes. The linked issue gives concrete macOS stop steps, current main lacks listener/port verification, and this PR’s remaining issue is source-reproducible because fallback success text is emitted before the new postcondition can throw.

Is this the best way to solve the issue?

No. The postcondition approach is the right fix shape, but the fallback output ordering should be changed so the user never sees stopped/degraded success when the resolved gateway port remains busy.

Full review comments:

  • [P2] Delay degraded stopped output until port check passes — src/daemon/launchd.ts:684
    When launchctl falls back to bootout, bootoutLaunchAgentOrThrow writes Stopped LaunchAgent (degraded) before this new assertion runs. If the port is still busy afterward, the command will fail but users still see the same stopped/degraded success line from the reported bug before the error; defer that stopped line until after the postcondition passes and add a busy fallback regression.
    Confidence: 0.88

Overall correctness: patch is incorrect
Overall confidence: 0.87

What I checked:

  • PR diff adds postcondition checks: The PR head adds assertGatewayPortReleasedAfterStop, calls it on stop paths, checks the port before restart kickstart, and adds launchd regressions for caller-env and stored service-env ports. (src/daemon/launchd.ts:608, 135f082b16b9)
  • Prior review gap is addressed: The PR head resolver now checks program arguments first, then command.environment.OPENCLAW_GATEWAY_PORT, then the caller environment, matching the intended service-env fallback shape. (src/daemon/launchd.ts:254, 135f082b16b9)
  • Remaining fallback output bug: At PR head, bootoutLaunchAgentOrThrow writes Stopped LaunchAgent (degraded) before returning, while the new assertions in the fallback callers run afterward; a busy port can therefore still show the degraded stopped line before failure. (src/daemon/launchd.ts:561, 135f082b16b9)
  • Current-main baseline: Current main stops LaunchAgent by returning after launchd operations and success output without inspecting the gateway listener/port, which is the bug this PR is trying to fix. (src/daemon/launchd.ts:604, 66b98b72946f)
  • Linked issue context: The linked report describes openclaw gateway stop printing Stopped LaunchAgent (degraded) while the gateway process remains alive and holds the port; the prior ClawSweeper issue review kept it open for a missing listener/port postcondition.
  • Area history: Recent macOS LaunchAgent stop behavior is tied to commit 1f88cb2, unmanaged lifecycle fallback to bf9c362 and 604a5e0, and earlier launchd stop persistence to 23d9a10. (src/daemon/launchd.ts:604, 1f88cb2ce5dd)

Likely related people:

  • steipete: Recent macOS LaunchAgent stop/disable and bootout behavior in the affected launchd and daemon lifecycle files is tied to commit 1f88cb2. (role: recent area contributor; confidence: high; commits: 1f88cb2ce5dd; files: src/daemon/launchd.ts, src/daemon/launchd.test.ts, src/cli/daemon-cli/lifecycle.ts)
  • vincentkoc: Introduced unmanaged gateway stop/restart fallback behavior and later lazy stop fallback port resolution used by the affected lifecycle path. (role: adjacent daemon lifecycle contributor; confidence: high; commits: bf9c362129e2, 604a5e07d0f7; files: src/cli/daemon-cli/lifecycle.ts, src/cli/daemon-cli/lifecycle-core.ts, src/cli/daemon-cli/restart-health.ts)
  • ngutman: Authored earlier launchd stop persistence work in the macOS LaunchAgent path that this PR now extends. (role: introduced related LaunchAgent stop behavior; confidence: medium; commits: 23d9a100c4aa; files: src/daemon/launchd.ts, src/daemon/launchd.test.ts, src/daemon/launchd-restart-handoff.ts)

Remaining risk / open question:

  • No live signed-app macOS LaunchAgent smoke was run in this read-only review; the PR body also notes that installed local-mode smoke was not run.

Codex review notes: model gpt-5.5, reasoning high; reviewed against 66b98b72946f.

@BunsDev

BunsDev commented May 14, 2026

Copy link
Copy Markdown
Contributor Author

Broad verification update:

  • Testbox pnpm check:changed passed for meow/macos-launchd-stop-postcondition.
  • Testbox: tbx_01krjpz0t39qwp29rd93cx2t90
  • Command: (git fetch/unshallow origin main for merge-base) && pnpm check:changed
  • Result: exit 0.

@BunsDev

BunsDev commented May 14, 2026

Copy link
Copy Markdown
Contributor Author

Addressed the LaunchAgent service-environment resolver gap from #81732 (comment).

Changes:

  • resolveLaunchAgentGatewayPort now checks port sources in the intended order: program arguments, persisted LaunchAgent command environment, then caller env.
  • Added stop and restart regressions where OPENCLAW_GATEWAY_PORT exists only in the generated LaunchAgent env wrapper.
  • No new dependencies, permissions, workflow/script changes, or secret-handling changes; the stored value is parsed through the existing strict positive-integer boundary before cleanup/inspection.

Verification on pushed head 135f082b16:

  • node scripts/run-vitest.mjs src/daemon/launchd.test.ts src/cli/daemon-cli/lifecycle.test.ts src/cli/daemon-cli/lifecycle-core.test.ts src/cli/daemon-cli/restart-health.test.ts — 4 files, 146 tests passed.
  • pnpm exec oxfmt --check --threads=1 CHANGELOG.md src/daemon/launchd.ts src/daemon/launchd.test.ts — passed.
  • git diff --check — passed.
  • Testbox tbx_01krjv3scxjsc0rf14mjepwtkw running pnpm check:changed — exit 0.

I checked review-thread state after the fix; there are no open GitHub review threads on this PR to resolve.

@BunsDev BunsDev self-assigned this May 14, 2026
@BunsDev

BunsDev commented May 14, 2026

Copy link
Copy Markdown
Contributor Author

@copilot resolve the merge conflicts in this pull request

Copilot AI requested a review from a team as a code owner May 14, 2026 09:14

Copilot AI commented May 14, 2026

Copy link
Copy Markdown
Contributor

@copilot resolve the merge conflicts in this pull request

Resolved. I rebased onto latest origin/main, fixed the CHANGELOG conflict, and pushed the updated branch; merge conflicts are now cleared in commit 58afacd.

@github-actions github-actions Bot added the dependencies-changed PR changes dependency-related files label May 14, 2026
@openclaw-barnacle openclaw-barnacle Bot added docs Improvements or additions to documentation channel: telegram Channel integration: telegram channel: voice-call Channel integration: voice-call extensions: memory-core Extension: memory-core cli CLI command changes scripts Repository scripts commands Command implementations agents Agent runtime and tooling extensions: anthropic extensions: codex extensions: anthropic-vertex and removed dependencies-changed PR changes dependency-related files labels May 14, 2026
@openclaw-barnacle openclaw-barnacle Bot added size: S and removed docs Improvements or additions to documentation channel: telegram Channel integration: telegram channel: voice-call Channel integration: voice-call extensions: memory-core Extension: memory-core cli CLI command changes scripts Repository scripts commands Command implementations agents Agent runtime and tooling extensions: anthropic extensions: codex extensions: anthropic-vertex size: XL labels May 14, 2026
@BunsDev

BunsDev commented May 14, 2026

Copy link
Copy Markdown
Contributor Author

Addressed the degraded fallback output blocker from the updated ClawSweeper review.

Changes:

  • bootoutLaunchAgentOrThrow now writes only the fallback warning.
  • Each degraded success line is emitted only after assertGatewayPortReleasedAfterStop(...) passes.
  • Added a busy-port fallback regression proving gateway stop --disable rejects without printing Stopped LaunchAgent when bootout fallback runs but the gateway port remains busy.

Verification on pushed head b6baf21de7:

  • node scripts/run-vitest.mjs src/daemon/launchd.test.ts src/cli/daemon-cli/lifecycle.test.ts src/cli/daemon-cli/lifecycle-core.test.ts src/cli/daemon-cli/restart-health.test.ts — 4 files, 147 tests passed.
  • pnpm exec oxfmt --check --threads=1 src/daemon/launchd.ts src/daemon/launchd.test.ts CHANGELOG.md — passed.
  • git diff --check — passed.
  • Testbox tbx_01krjwwv9z9z3f5d06fqph6eta running pnpm check:changed — exit 0.

@BunsDev

BunsDev commented May 14, 2026

Copy link
Copy Markdown
Contributor Author

Latest exact-head verification after merging current origin/main:

  • Head: c39c0c956f
  • node scripts/run-vitest.mjs src/daemon/launchd.test.ts src/cli/daemon-cli/lifecycle.test.ts src/cli/daemon-cli/lifecycle-core.test.ts src/cli/daemon-cli/restart-health.test.ts — 4 files, 147 tests passed.
  • pnpm exec oxfmt --check --threads=1 src/daemon/launchd.ts src/daemon/launchd.test.ts CHANGELOG.md — passed.
  • git diff --check — passed.
  • Testbox tbx_01krjxf8vrbjwxv3xfdx4770xr running pnpm check:changed — exit 0.

The earlier CI lint-suppression failure came from the rebased main baseline and is fixed by the newer origin/main commit now merged into this branch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gateway Gateway runtime maintainer Maintainer-authored PR size: M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] openclaw gateway stop / launchctl bootout doesn't terminate underlying node process — wedged binary persists across stop

2 participants